Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Seitosh
Seitosh
Commits
5ac27a61
Commit
5ac27a61
authored
Jan 03, 2019
by
thomas.forbriger
Browse files
libpsdxx [WP]: implement PSD computation
Code is copied from foutra.cc
parent
98202b7a
Changes
1
Hide whitespace changes
Inline
Side-by-side
src/libs/libpsdxx/dpsdcomputer_psd.cc
View file @
5ac27a61
...
...
@@ -33,13 +33,232 @@
#define PSDXX_DPSDCOMPUTER_PSD_CC_VERSION \
"PSDXX_DPSDCOMPUTER_PSD_CC V1.0"
#include
<psd.h>
#include
<iostream>
#include
<psdxx/psd.h>
#include
<psdxx/error.h>
#include
<aff/iterator.h>
#include
<aff/dump.h>
#include
<aff/seriesoperators.h>
#include
<aff/functions/avg.h>
#include
<aff/functions/rms.h>
#include
<aff/functions/sqrsum.h>
#include
<aff/subarray.h>
#include
<tsxx/tsxx.h>
#include
<tsxx/tapers.h>
#include
<tsxx/filter.h>
#include
<tsxx/wid2timeseries.h>
#include
<fourier/fftwaff.h>
using
std
::
cout
;
using
std
::
endl
;
// time series
typedef
aff
::
Series
<
double
>
Tseries
;
typedef
fourier
::
fft
::
DRFFTWAFF
Tfft
;
namespace
psd
{
Tdouble_series
DPSDComputer
::
psd
(
const
Tdouble_series
&
s
)
const
{
Tdouble_series
retval
;
/*======================================================================*/
// start processing
// create taper
ts
::
tapers
::
Hanning
hanning_taper
;
// create FFTW processor
Tfft
fft
;
const
Tseries
&
inputseries
=
s
.
data
;
const
double
&
dt
=
s
.
interval
;
// process data
//
// inputseries: full series passed to function
// series: series for one segment to be analysed
// the spectral representation of a single segment is also stored
// in this container
// spectrum: resulting spectral representation
//
// in the previous (pre segmentation) version of foutra only "series" was
// used; we will make use of the aff::Series reference semantics to use the
// old code with no more modifications than necessary; such "series" will
// be used for different things
//
// wid2.dt remains valid throughout the processing
// wid2.nsamples is only correct for the inputseries
// use series.size() for other request for number of samples
// prepare segmentation
// --------------------
int
nsegsamples
=
inputseries
.
size
();
if
(
this
->
Mnsegments
>
1
)
{
nsegsamples
=
2
*
inputseries
.
size
()
/
(
this
->
Mnsegments
+
1
);
}
// adjust length of time series
if
(
this
->
Mdivisor
>
1
)
{
if
(
this
->
Mverbose
)
{
std
::
cout
<<
" adjust divisor to "
<<
this
->
Mdivisor
<<
std
::
endl
;
std
::
cout
<<
" number of input samples: "
<<
inputseries
.
size
()
<<
std
::
endl
;
std
::
cout
<<
" number of segment samples: "
<<
nsegsamples
<<
std
::
endl
;
}
int
rest
=
nsegsamples
%
this
->
Mdivisor
;
nsegsamples
=
nsegsamples
-
rest
;
if
(
this
->
Mverbose
)
{
std
::
cout
<<
" number of processing samples: "
<<
nsegsamples
<<
std
::
endl
;
}
}
// segment stride
int
segstride
=
inputseries
.
size
()
/
(
this
->
Mnsegments
+
1
);
if
(
this
->
Mverbose
&&
(
this
->
Mnsegments
>
1
))
{
cout
<<
" number of input samples: "
<<
inputseries
.
size
()
<<
endl
;
cout
<<
" number of segments: "
<<
this
->
Mnsegments
<<
endl
;
cout
<<
" number of samples in each segment: "
<<
nsegsamples
<<
endl
;
cout
<<
" stride between segments: "
<<
segstride
<<
endl
;
cout
<<
" overlap of proximate segments: "
<<
100.
*
(
nsegsamples
-
segstride
)
/
nsegsamples
<<
"%"
<<
endl
;
}
// length of time series segment
double
T
=
dt
*
nsegsamples
;
// length of taper window
double
Tw
=
T
;
// frequency sampling interval
double
df
=
1.
/
T
;
if
(
this
->
Mpadfactor
>
1
)
{
T
*=
this
->
Mpadfactor
;
df
/=
this
->
Mpadfactor
;
}
if
(
this
->
Mverbose
)
{
cout
<<
" duration T of each segment: "
<<
T
<<
"s"
<<
endl
;
cout
<<
" duration Tw of signal window: "
<<
Tw
<<
"s"
<<
endl
;
cout
<<
" frequency sampling interval df: "
<<
df
<<
"Hz"
<<
endl
;
}
// the result will be collected in
Tseries
spectrum
;
// segment counter
unsigned
int
isegment
=
0
;
// start actual processing
// -----------------------
while
(
isegment
<
this
->
Mnsegments
)
{
int
firstindex
=
inputseries
.
first
()
+
isegment
*
segstride
;
int
lastindex
=
firstindex
+
nsegsamples
-
1
;
PSDXX_assert
((
firstindex
>=
inputseries
.
first
())
&&
(
firstindex
<=
inputseries
.
last
())
&&
(
lastindex
>=
inputseries
.
first
())
&&
(
lastindex
<=
inputseries
.
last
()),
"ERROR: index out of range; program design error"
);
Tseries
segseries
=
aff
::
subarray
(
inputseries
)(
firstindex
,
lastindex
);
Tseries
series
=
segseries
;
if
(
this
->
Mnsegments
>
1
)
{
series
=
segseries
.
copyout
();
}
series
.
shift
(
-
series
.
first
());
// demean
if
(
this
->
Mdemean
)
{
ts
::
filter
::
RemoveAverage
demean
(
0
);
demean
(
ts
::
filter
::
Ttimeseries
(
series
,
dt
));
}
// detrend
if
(
this
->
Mdetrend
)
{
ts
::
filter
::
RemoveTrend
detrend
(
0
);
detrend
(
ts
::
filter
::
Ttimeseries
(
series
,
dt
));
}
// apply taper
hanning_taper
.
apply
(
series
);
// pad time series
// Notice: padding the signals requires correct scaling of amplitudes
// this is only implemented for harmonic signals up to now
if
(
this
->
Mpadfactor
>
0
)
{
Tseries
newseries
(
series
.
size
()
*
this
->
Mpadfactor
);
newseries
=
0.
;
Tseries
subseries
(
aff
::
subarray
(
newseries
)(
series
.
f
(),
series
.
l
()));
subseries
.
copyin
(
series
);
series
=
newseries
;
}
Tfft
::
Tspectrum
coeff
=
fft
(
series
,
dt
);
series
=
Tseries
(
coeff
.
size
());
aff
::
Iterator
<
Tseries
>
S
(
series
);
aff
::
Browser
<
Tfft
::
Tspectrum
>
C
(
coeff
);
while
(
S
.
valid
()
&&
C
.
valid
())
{
*
S
=
C
->
real
()
*
C
->
real
()
+
C
->
imag
()
*
C
->
imag
();
++
S
;
++
C
;
}
// scaling factor to adjust for taper effect
double
tapscaling
=
1.
;
// scaling factor for Hanning
// see below for derivation of this factor
tapscaling
=
8.
/
3.
;
// we have an energy spectrum so far
// adjust scaling factor to obtain signal power
double
scalingfactor
=
2.
*
tapscaling
/
Tw
;
series
*=
scalingfactor
;
// collect result
if
(
isegment
==
0
)
{
spectrum
=
series
.
copyout
();
}
else
{
// spectrum += series;
for
(
int
i
=
spectrum
.
f
(),
j
=
series
.
f
();
i
<=
spectrum
.
l
();
++
i
,
++
j
)
{
PSDXX_assert
(
j
<=
series
.
l
(),
"ERROR: program design error"
);
spectrum
(
i
)
+=
series
(
j
);
}
}
++
isegment
;
}
// while (isegment<this->Mnsegments)
if
(
this
->
Mnsegments
>
1
)
{
spectrum
/=
this
->
Mnsegments
;
}
// use reference semantics to make results available under previous
// name
retval
.
data
=
spectrum
;
retval
.
interval
=
df
;
return
(
retval
);
}
// Tdouble_series DPSDComputer::psd(const Tdouble_series& s) const
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment