42#include "../mxError.hpp"
44#include "../math/ft/fftT.hpp"
45#include "../math/vectorUtils.hpp"
65template <
typename realT>
77 for(
size_t i = 1; i < sz - 1; ++i )
80 var += half * PSD[sz - 1];
98template <
typename realT>
111 for( ; i < sz / 2; ++i )
116 var += half * PSD[i];
135template <
typename realT>
136realT
psdVar(
const std::vector<realT> &f,
137 const std::vector<realT> &PSD,
143 return psdVar2sided( f[1] - f[0], PSD.data(), PSD.size(), half );
145 return psdVar1sided( f[1] - f[0], PSD.data(), PSD.size(), half );
157template <
typename eigenArrT>
164 typename eigenArrT::Scalar half = 0.5;
168 typename eigenArrT::Scalar var = 0;
170 var = half * PSD( 0, 0 );
172 for(
int i = 1; i < freq.rows() - 1; ++i )
175 var += half * PSD( freq.rows() - 1, 0 );
177 var *= ( freq( 1, 0 ) - freq( 0, 0 ) );
195template <
class realT>
198 return ( f_max / ( 0.5 * dim ) );
210template<
typename eigenArr>
212 typename eigenArr::Scalar dt,
213 bool inverse =
false )
215 typename eigenArr::Index dim, dim_1, dim_2;
216 typename eigenArr::Scalar df;
221 dim = std::max(dim_1, dim_2);
227 for(
int ii=0; ii < ceil(0.5*(dim-1) + 1); ++ii)
232 for(
int ii=ceil(0.5*(dim-1)+1); ii < dim_1; ++ii)
234 vec(ii) = (ii-dim)*df;
239 for(
int ii=0; ii < dim; ++ii)
241 vec(ii) = df * ii / dim;
255template <
typename realT,
typename realParamT>
257 std::vector<realT> &vec,
266 if( vec.size() % 2 == 1 )
268 mxError(
"frequencyGrid", MXE_INVALIDARG,
"Frequency scale can't be odd-sized for FFT order" );
272 realT df = ( 1.0 / dtTT ) / ( (realT)vec.size() );
274 for( ssize_t ii = 0; ii < ceil( 0.5 * ( vec.size() - 1 ) + 1 ); ++ii )
279 for( ssize_t ii = ceil( 0.5 * ( vec.size() - 1 ) + 1 ); ii < vec.size(); ++ii )
281 vec[ii] = ( ii - (ssize_t)vec.size() ) * df;
288 if( vec.size() % 2 == 0 )
290 realT df = ( 0.5 / dtTT ) / ( (realT)vec.size() - 1 );
291 for(
int ii = 0; ii < vec.size(); ++ii )
300 realT df = ( 0.5 / dt ) / ( (realT)vec.size() );
301 for(
int ii = 0; ii < vec.size(); ++ii )
303 vec[ii] = df * ( ii + 1 );
312template <
typename eigenArr,
typename realParamT>
313void frequencyGrid( eigenArr &arr, realParamT drT, eigenArr *k_x, eigenArr *k_y )
315 typename eigenArr::Scalar dr = drT;
317 typename eigenArr::Index dim_1, dim_2;
318 typename eigenArr::Scalar k_1, k_2, df;
324 k_x->resize( dim_1, dim_2 );
326 k_y->resize( dim_1, dim_2 );
330 for(
int ii = 0; ii < 0.5 * ( dim_1 - 1 ) + 1; ++ii )
333 for(
int jj = 0; jj < 0.5 * ( dim_2 - 1 ) + 1; ++jj )
337 arr( ii, jj ) = sqrt( k_1 * k_1 + k_2 * k_2 );
340 ( *k_x )( ii, jj ) = k_1;
342 ( *k_y )( ii, jj ) = k_2;
345 for(
int jj = 0.5 * ( dim_2 - 1 ) + 1; jj < dim_2; ++jj )
347 k_2 = ( jj - dim_2 ) * df;
349 arr( ii, jj ) = sqrt( k_1 * k_1 + k_2 * k_2 );
352 ( *k_x )( ii, jj ) = k_1;
354 ( *k_y )( ii, jj ) = k_2;
358 for(
int ii = 0.5 * ( dim_1 - 1 ) + 1; ii < dim_1; ++ii )
360 k_1 = ( ii - dim_1 ) * df;
361 for(
int jj = 0; jj < 0.5 * ( dim_2 - 1 ) + 1; ++jj )
365 arr( ii, jj ) = sqrt( k_1 * k_1 + k_2 * k_2 );
368 ( *k_x )( ii, jj ) = k_1;
370 ( *k_y )( ii, jj ) = k_2;
373 for(
int jj = 0.5 * ( dim_2 - 1 ) + 1; jj < dim_2; ++jj )
375 k_2 = ( jj - dim_2 ) * df;
377 arr( ii, jj ) = sqrt( k_1 * k_1 + k_2 * k_2 );
380 ( *k_x )( ii, jj ) = k_1;
382 ( *k_y )( ii, jj ) = k_2;
388template <
typename eigenArr>
395template <
typename eigenArr>
396void frequencyGrid( eigenArr &arr,
typename eigenArr::Scalar dt, eigenArr &k_x, eigenArr &k_y )
411template <
typename realT>
414 realT integ = 2 * ( pow( fmax, -1.0 * alpha + 1.0 ) - pow( fmin, -1.0 * alpha + 1.0 ) ) / ( -1.0 * alpha + 1.0 );
429template <
typename realT>
432 realT integ = 2 * ( pow( kmax, -1 * alpha + 2.0 ) - pow( kmin, -1.0 * alpha + 2.0 ) ) / ( -1 * alpha + 2.0 );
446template <
typename floatT,
typename floatParamT>
448 std::vector<floatT> &f,
450 floatT fmin = std::numeric_limits<floatT>::min(),
452 floatT fmax = std::numeric_limits<floatT>::max()
461 if( fmin != std::numeric_limits<floatT>::min() || fmax != std::numeric_limits<floatT>::max() )
463 for(
size_t i = 0; i < psd.size(); ++i )
465 if( fabs( f[i] ) < fmin || fabs( f[i] ) > fmax )
472 for(
size_t i = 0; i < psd.size(); ++i )
478 s *= ( f[1] - f[0] );
480 for(
size_t i = 0; i < psd.size(); ++i )
495template <
typename floatT,
typename floatParamT>
497normPSD( Eigen::Array<floatT, Eigen::Dynamic, Eigen::Dynamic> &psd,
498 Eigen::Array<floatT, Eigen::Dynamic, Eigen::Dynamic> &k,
500 floatT kmin = std::numeric_limits<floatT>::min(),
502 floatT kmax = std::numeric_limits<floatT>::max()
511 dk1 = k( 1, 0 ) - k( 0, 0 );
516 dk2 = k( 0, 1 ) - k( 0, 0 );
523 if( kmin != std::numeric_limits<floatT>::min() || kmax != std::numeric_limits<floatT>::max() )
525 for(
int c = 0; c < psd.cols(); ++c )
527 for(
int r = 0; r < psd.rows(); ++r )
529 if( fabs( k( r, c ) ) < kmin || fabs( k( r, c ) ) > kmax )
537 for(
int c = 0; c < psd.cols(); ++c )
539 for(
int r = 0; r < psd.rows(); ++r )
548 for(
int c = 0; c < psd.cols(); ++c )
550 for(
int r = 0; r < psd.rows(); ++r )
552 psd( r, c ) *= norm / s;
579template <
typename eigenArrp,
typename eigenArrf>
582 typename eigenArrp::Scalar alpha,
583 typename eigenArrp::Scalar beta = -1 )
585 typedef typename eigenArrp::Scalar Scalar;
587 typename eigenArrp::Index dim_1, dim_2;
598 fmax = freq.abs().maxCoeff();
601 fmin = ( freq.abs() > 0 ).select( freq.abs(), freq.abs() + fmax ).minCoeff();
606 for(
int ii = 0; ii < dim_1; ++ii )
608 for(
int jj = 0; jj < dim_2; ++jj )
610 if( freq( ii, jj ) == 0 )
616 p = beta / std::pow( std::abs( freq( ii, jj ) ), alpha );
637template <
typename floatT,
640 typename T0T = double,
641 typename t0T = double,
642 typename betaT =
double>
644 std::vector<floatfT> &f,
652#ifndef MX_VKPSD_REFACT
653 static_assert( 0 * std::is_floating_point<floatT>::value,
654 "the 1D vonKarmanPSD has been refactored. After modifying your code to match, you must define "
655 "MX_VKPSD_REFACT before including psdUtils.hpp to avoid this error." );
660 T02 = 1.0 / ( T0 * T0 );
664 floatT sqrt_alpha = 0.5 * alpha;
672 psd.resize( f.size() );
674 for(
size_t i = 0; i < f.size(); ++i )
676 floatT p = _beta / pow( pow( f[i], 2 ) + T02, sqrt_alpha );
678 p *= exp( -1 * pow( f[i] *
static_cast<floatT
>( t0 ), 2 ) );
698template <
typename floatT>
700 std::vector<floatT> &f,
707 psd.resize( f.size() );
709 for(
int i = 0; i < f.size(); ++i )
711 floatT p = beta / ( 1 + pow( f[i] / fn, alpha ) );
740template <
typename eigenArrp,
typename eigenArrf,
typename alphaT,
typename L0T,
typename l0T,
typename betaT>
741void vonKarmanPSD( eigenArrp &psd, eigenArrf &freq, alphaT alpha, L0T L0 = 0, l0T l0 = 0, betaT beta = -1 )
743 typedef typename eigenArrp::Scalar Scalar;
745 typename eigenArrp::Index dim_1, dim_2;
758 fmax = freq.abs().maxCoeff();
761 fmin = ( freq.abs() > 0 ).select( freq.abs(), freq.abs() + fmax ).minCoeff();
763 _beta = beta =
oneoverf_norm( fmin, fmax,
static_cast<Scalar
>( alpha ) );
766 _beta =
static_cast<Scalar
>( beta );
770 L02 = 1.0 / ( L0 * L0 );
774 Scalar sqrt_alpha = 0.5 * alpha;
776 for(
int ii = 0; ii < dim_1; ++ii )
778 for(
int jj = 0; jj < dim_2; ++jj )
780 if( freq( ii, jj ) == 0 && L02 == 0 )
786 p = _beta / pow( pow( freq( ii, jj ), 2 ) + L02, sqrt_alpha );
788 p *= exp( -1 * pow( freq( ii, jj ) *
static_cast<Scalar
>( l0 ), 2 ) );
816template <
typename vectorTout,
typename vectorTin>
818 vectorTout &psdTwoSided,
819 vectorTin &psdOneSided,
822 typename vectorTin::value_type scale = 0.5
826 typedef typename vectorTout::value_type outT;
832 if( addZeroFreq == 0 )
835 N = 2 * psdOneSided.size() - 2;
839 N = 2 * psdOneSided.size();
842 psdTwoSided.resize( N );
847 psdTwoSided[0] = outT( 0.0 );
851 psdTwoSided[0] = outT( psdOneSided[0] );
856 for( i = 0; i < psdOneSided.size() - 1 - ( 1 - needZero ); ++i )
858 psdTwoSided[i + 1] = outT( psdOneSided[i + ( 1 - needZero )] * scale );
859 psdTwoSided[i + psdOneSided.size() + needZero] = outT( psdOneSided[psdOneSided.size() - 2 - i] * scale );
861 psdTwoSided[i + 1] = outT( psdOneSided[i + ( 1 - needZero )] );
877 std::vector<T> &freqTwoSided,
878 std::vector<T> &freqOneSided
885 if( freqOneSided[0] != 0 )
887 N = 2 * freqOneSided.size();
892 N = 2 * freqOneSided.size() - 2;
895 freqTwoSided.resize( N );
899 freqTwoSided[0] = 0.0;
903 freqTwoSided[0] = freqOneSided[0];
907 for( i = 0; i < freqOneSided.size() - 1 - ( 1 - needZero ); ++i )
909 freqTwoSided[i + 1] = freqOneSided[i + ( 1 - needZero )];
910 freqTwoSided[i + freqOneSided.size() + needZero] = -freqOneSided[freqOneSided.size() - 2 - i];
912 freqTwoSided[i + 1] = freqOneSided[i + ( 1 - needZero )];
932template <
typename realT>
934 std::vector<realT> &binPSD,
935 std::vector<realT> &freq,
936 std::vector<realT> &PSD,
938 bool binAtZero =
true
951 realT df = freq[1] - freq[0];
954 while( freq[i] <= 0.5 * binSize + 0.5 * df )
959 if( i >= freq.size() )
965 binFreq.push_back( 0 );
966 binPSD.push_back( PSD[0] );
970 binFreq.push_back( 0 );
971 binPSD.push_back( sumPSD / nSum );
980 while( i < freq.size() )
983 while( freq[i] - startFreq + 0.5 * df < binSize )
986 sumPSD += sc * PSD[i];
991 if( i >= freq.size() - 1 )
995 if( i < freq.size() )
998 sumPSD += 0.5 * PSD[i];
1004 if( i < freq.size() )
1006 binFreq.push_back( sumFreq / nSum );
1011 binFreq.push_back( freq[freq.size() - 1] );
1014 binPSD.push_back( sumPSD / ( nSum - 1 ) );
1019 if( i >= freq.size() )
1024 startFreq = freq[i];
1028 realT var =
psdVar( freq, PSD );
1029 realT binv =
psdVar( binFreq, binPSD );
1031 for(
int i = 0; i < binFreq.size(); ++i )
1032 binPSD[i] *= var / binv;
void oneoverf_psd(eigenArrp &psd, eigenArrf &freq, typename eigenArrp::Scalar alpha, typename eigenArrp::Scalar beta=-1)
Generates a power spectrum.
realT oneoverf_norm(realT fmin, realT fmax, realT alpha)
Calculate the normalization for a 1-D PSD.
void augment1SidedPSD(vectorTout &psdTwoSided, vectorTin &psdOneSided, bool addZeroFreq=false, typename vectorTin::value_type scale=0.5)
Augment a 1-sided PSD to standard 2-sided FFT form.
eigenArrT::Scalar psdVarDisabled(eigenArrT &freq, eigenArrT &PSD, bool trap=true)
Calculate the variance of a PSD.
realT oneoverk_norm(realT kmin, realT kmax, realT alpha)
Calculate the normalization for a 2-D PSD.
realT psdVar1sided(realT df, const realT *PSD, size_t sz, realT half=0.5)
Calculate the variance of a 1-D, 1-sided PSD.
int vonKarmanPSD(std::vector< floatT > &psd, std::vector< floatfT > &f, alphaT alpha, T0T T0=0, t0T t0=0, betaT beta=1)
Generate a 1-D von Karman power spectrum.
void augment1SidedPSDFreq(std::vector< T > &freqTwoSided, std::vector< T > &freqOneSided)
Augment a 1-sided frequency scale to standard FFT form.
realT psdVar(const std::vector< realT > &f, const std::vector< realT > &PSD, realT half=0.5)
Calculate the variance of a 1-D PSD.
realT psdVar2sided(realT df, const realT *PSD, size_t sz, realT half=0.5)
Calculate the variance of a 1-D, 2-sided PSD.
void frequency_grid1D(eigenArr &vec, typename eigenArr::Scalar dt, bool inverse=false)
Create a 1-D frequency grid.
realT freq_sampling(size_t dim, realT f_max)
Calculates the frequency sampling for a grid given maximum dimension and maximum frequency.
int kneePSD(std::vector< floatT > &psd, std::vector< floatT > &f, floatT beta, floatT fn, floatT alpha)
Generate a 1-D "knee" PSD.
int normPSD(std::vector< floatT > &psd, std::vector< floatT > &f, floatParamT normT, floatT fmin=std::numeric_limits< floatT >::min(), floatT fmax=std::numeric_limits< floatT >::max())
Normalize a 1-D PSD to have a given variance.
int frequencyGrid(std::vector< realT > &vec, realParamT dt, bool fftOrder=true)
Create a 1-D frequency grid.
int rebin1SidedPSD(std::vector< realT > &binFreq, std::vector< realT > &binPSD, std::vector< realT > &freq, std::vector< realT > &PSD, realT binSize, bool binAtZero=true)
Rebin a PSD, including its frequency scale, to a larger frequency bin size (fewer bins)