头文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * classicalpse.h * * Classical Power Spectrum Estimation Mothods. * * The goal of spectral density estimation is to estimate the spectral density * of a random signal from a sequence of time samples of the signal. The * purpose of estimating the spectral density is to detect any periodicities * in the data, by observing peaks at the frequencies corresponding to these * periodicities. * * This file provides 5 usually used Classical-Specturm-Estimation methods: * correlogram method, periodogram method, * smoothed periodogram method (Barteltt method and Welch method), * and Blackman-Tukey method * * Zhang Ming, 2010-11, Xi'an Jiaotong University. *****************************************************************************/ #ifndef CLASSICALPSE_H #define CLASSICALPSE_H #include <window.h> #include <utilities.h> #include <fft.h> #include <correlation.h> namespace splab { template<typename Type> Vector<Type> correlogramPSE( const Vector<Type>&, int ); template<typename Type> Vector<Type> periodogramPSE( const Vector<Type>&, const Vector<Type>&, int ); template<typename Type> Vector<Type> bartlettPSE( const Vector<Type>&, int, int ); template<typename Type> Vector<Type> welchPSE( const Vector<Type>&, const Vector<Type>&, int, int ); template<typename Type> Vector<Type> btPSE( const Vector<Type>&, const Vector<Type>&, int ); #include <classicalpse-impl.h> } // namespace splab #endif // CLASSICALSE_H
实现文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * classicalpse-impl.h * * Implementation for classical power spectrum estimatoin methods. * * Zhang Ming, 2010-11, Xi'an Jiaotong University. *****************************************************************************/ /** * The correlogram power spectral estimator. * xn : input signal * L : the number of power spectrum density samples * return : spectral estimates at L frequencies: * w = 0, 2*pi/L, ..., 2*pi(L-1)/L */ template <typename Type> inline Vector<Type> correlogramPSE( const Vector<Type> &xn, int L ) { return periodogramPSE( xn, rectangle(xn.size(),Type(1)), L ); } /** * The windowed periodogram power spectral estimator. * xn : input signal * wn : window function * L : the number of power spectrum density samples * return : spectral estimates at L frequencies: * w = 0, 2*pi/L, ..., 2*pi(L-1)/L */ template <typename Type> Vector<Type> periodogramPSE( const Vector<Type> &xn, const Vector<Type> &wn, int L ) { int N = xn.size(), M = wn.size(); assert( M <= N ); if( M < N ) { cerr << "The length of window is smaller than the length of data, "; cerr << "the data will be trucated to the window length!" << endl; } Vector<Type> wxn(L); if( L >= M ) { for( int i=0; i<M; ++i ) wxn[i] = xn[i] * wn[i]; } else { cerr << "The FFT points is smaller than the data points, "; cerr << "the data will be trucated to the FFT points!" << endl; for( int i=0; i<L; ++i ) wxn[i] = xn[i] * wn[i]; } Vector<Type> absXk = abs( fft( wxn ) ); return absXk*absXk / Type(M); } /** * The Bartlett method of power spectral estimation. * xn : input signal * M : the length of subsequences * L : the number of power spectrum density samples * return : spectral estimates at L frequencies: * w = 0, 2*pi/L, ..., 2*pi(L-1)/L */ template <typename Type> inline Vector<Type> bartlettPSE( const Vector<Type> &xn, int M, int L ) { return welchPSE( xn, rectangle(M,Type(1)), M, L ); } /** * The Welch method of power spectral estimation. * xn : input signal * wn : window function * K : the number of subsequence * L : the number of power spectrum density samples * return : spectral estimates at L frequencies: * w = 0, 2*pi/L, ..., 2*pi(L-1)/L */ template <typename Type> Vector<Type> welchPSE( const Vector<Type> &xn, const Vector<Type> &wn, int K, int L ) { int N = xn.size(), M = wn.size(); assert( M < N ); assert( K < N ); int S = ( N-M+K )/K; Type P = sum( wn*wn ) / Type(M); Vector<Type> phi(L); for( int i=0; i<S; ++i ) phi += periodogramPSE( wkeep(xn,M,i*K), wn, L ); return phi/(S*P); } /** * The Blackman-Tukey method of power spectral estimation. * The correlation function is obtained from the standard biased estimate. * xn : input signal * wn : window function * L : the number of power spectrum density samples * return : spectral estimates at L frequencies: * w = 0, 2*pi/L, ..., 2*pi(L-1)/L */ template <typename Type> Vector<Type> btPSE( const Vector<Type> &xn, const Vector<Type> &wn, int L ) { int N = xn.size(), M = wn.size(); assert( M <= N ); Vector<Type> Rxx = fastCorr( xn, "biased" ); Vector<Type> wrn(L); if( L >= M ) { for( int i=0; i<M; ++i ) wrn[i] = Rxx[N-1+i] * wn[i]; } else { cerr << "The FFT points is smaller than the data points, "; cerr << "the data will be trucated to the FFT points!" << endl; for( int i=0; i<L; ++i ) wrn[i] = Rxx[N-1+i] * wn[i]; } return Type(2)*real(fft(wrn)) - wrn[0]; }
测试代码:
/***************************************************************************** * classicalpse_test.cpp * * Classical power spectrum estimation testing. * * Zhang Ming, 2010-11, Xi'an Jiaotong University. *****************************************************************************/ #define BOUNDS_CHECK #include <iostream> #include <cstring> #include <vectormath.h> #include <classicalpse.h> #include "engine.h" using namespace std; using namespace splab; typedef double Type; const int N = 100; const int K = 25; const int M = 50; const int L = 200; int main() { /******************************* [ signal ] ******************************/ int mfn = L/2+1; Type amp1 = Type(1.0), amp2 = Type(0.5); Type f1 = Type(0.3), f2 = Type(0.4); Vector<Type> tn = linspace(Type(0), Type(N-1), N ); Vector<Type> sn = amp1*sin(TWOPI*f1*tn) + amp2*sin(TWOPI*f2*tn); /******************************** [ widow ] ******************************/ Vector<Type> wn = window( "Hamming", M, Type(1.0) ); /********************************* [ PSD ] *******************************/ // Vector<Type> Ps = correlogramPSE( sn, L ); // Vector<Type> Ps = periodogramPSE( sn, wn, L ); // Vector<Type> Ps = bartlettPSE( sn, M, L ); Vector<Type> Ps = welchPSE( sn, wn, K, L ); // Vector<Type> Ps = btPSE( sn, wn, L ); /******************************** [ PLOT ] *******************************/ Engine *ep = engOpen( NULL ); if( !ep ) { cerr << "Cannot open Matlab Engine!" << endl; exit(1); } mxArray *msn = mxCreateDoubleMatrix( N, 1, mxREAL ); mxArray *mPs = mxCreateDoubleMatrix( mfn, 1, mxREAL ); memcpy( mxGetPr(msn), sn, N*sizeof(Type) ); memcpy( mxGetPr(mPs), Ps, mfn*sizeof(Type) ); engPutVariable( ep, "sn", msn ); engPutVariable( ep, "Ps", mPs ); const char *mCmd = " figure('name','Welch Method of Spectrum Estimation'); \ N = length(sn); mfn = length(Ps); \ subplot(2,1,1); \ plot((0:N-1), sn); \ axis([0,N,min(sn),max(sn)]); \ title('(a) Signal', 'FontSize',12); \ xlabel('Samples', 'FontSize',12); \ ylabel('Amplitude', 'FontSize',12); \ subplot(2,1,2); \ h = stem((0:mfn-1)/(mfn-1)/2, Ps); \ axis([0,0.5,min(Ps),max(Ps)]); \ set(h,'MarkerFaceColor','blue'); \ set(gca, 'XTick', 0:0.1:0.5); \ grid on; \ title('(b) Spectrum', 'FontSize',12); \ xlabel('Normalized Frequency ( f / fs )', 'FontSize',12); \ ylabel('Amplitude', 'FontSize',12); "; engEvalString( ep, mCmd ); mxDestroyArray( msn ); mxDestroyArray( mPs ); system( "pause" ); engClose(ep); return 0; }
运行结果: