本文目標:分析AR模型並求解AR模型的輸出x(n)的功率譜。
1. AR模型概念觀
數字信號處理功率譜估計方法分經典功率譜估計和現代功率譜估計,現代功率譜估計以參數模型功率譜估計爲代表,參數功率譜模型如下:
u(n) ——> H(z) ——> x(n)
參數模型的基本思路是:
—— 參數模型假設研究過程是由一個輸入序列u(n)激勵一個線性系統H(z)的輸出。
—— 由假設參數模型的輸出x(n)或其自相關函數來估計H(z)的參數
—— 由H(z)的參數估計x(n)的功率譜
因此,參數模型功率譜的求解有兩步:
(1)H(z)模型參數估計
(2)依據模型參數求功率譜
AR模型(自迴歸模型,Auto Regression Model)是典型的現代參數功模型。其定義爲
其中,輸入設定爲方差爲的白噪聲序列,ak是模型的參數,p是模型的階數,Px爲x(n)功率譜,也即本文要求解的目標。
AR模型是一個全極點模型,“自迴歸”的含義是:現在的輸出是現在的輸入和過去p個輸出的加權和。
現在我們希望建立AR參數模型和x(n)的自相關函數的關係,也即AR模型的正則方程:
上面的正則方程也稱Yule-Walker方程,其中的rx爲自相關函數。由方程可以看出,一個p階的AR模型有p+1個參數()。
通過推導可以發現,AR模型與線性預測器是等價的,AR模型是在最小平方意義上對數據的擬合。
2. AR模型參數求解——Levinson-Durbin Algorithm
定義爲p階AR模型在m階次時的第k個係數,k=1,2,...,m。定義爲m階系統時的,這也是線性預測器中前向預測的最小誤差功率。此時,一階AR模型時有我們定義初始時,則
由PART1中矩陣的對稱性質,將上面的公式推廣到高階AR模型,可以推導出Levinson-Durbin遞推算法:
Levinson-Durbin遞推算法從低階開始遞推,,給出了每一階次時所有參數,。這一特點有利於我們選擇合適的AR模型階次。
因爲必須大於0,由式知,如果,遞推應該停止。
到此,選擇最佳階次的參數代入到中,求得功率譜。
3. matlab實現
matlab工具箱中提供了現成的函數實現AR模型功率譜計算。參考[2],我們將內容摘錄如下:
AR模型的譜估計是現代譜估計的主要內容。
1.AR模型的Yule—Walker方程和Levinson-Durbin遞推算法:在MATLAB中,函數levinson和aryule都採用Levinson-Durbin遞推算法來求解AR模型的參數a1,a2,……,ap及白噪聲序列的方差,只是兩者的輸入參數不同,它們的格式爲:
A=LEVINSON(R,ORDER) A=ARYULE(x,ORDER)
兩函數均爲定階ORDER的求解,但是函數levinson的輸入參數要求是序列的自相關函數,而函數aryule的輸入參數爲採樣序列。
下面語句說明函數levinson和函數aryule的功能是相同的:
例子:
randn('seed',0)
a=[1 0.1 0.2 0.3 0.4 0.5];
x=impz(1,a,20)+randn(20,1)/20;
r=xcorr(x,'biased');
r(1:length(x)-1)=[];
A=levinson(r,5)
B=aryule(x,5)
2.Burg算法:
格式爲:A=ARBURG(x,ORDER); 其中x爲有限長序列,參數ORDER用於指定AR模型的階數。以上面的例子爲例:
randn('seed',0)
a=[1 0.1 0.2 0.3 0.4 0.5];
x=impz(1,a,20)+randn(20,1)/20;
A=arburg(x,5)
3.改進的協方差法:
格式爲:A=ARMCOV(x,ORDER); 該函數用來計算有限長序列x(n)的ORDER階AR模型的參數。例如:輸入下面語句:
randn('seed',0)
a=[1 0.1 0.2 0.3 0.4 0.5];
x=impz(1,a,20)+randn(20,1)/20;
A=armcov(x,5)
AR模型階數P的選擇:
AR模型階數P一般事先是不知道的,需要事先選定一個較大的值,在遞推的過程中確定。在使用Levinson—Durbin遞推方法時,可以給出由低階到高階的每一組參數,且模型的最小預測誤差功率Pmin(相當於白噪聲序列的方差)是遞減的。直觀上講,當預測誤差功率P達到指定的希望值時,或是不再發生變化時,這時的階數即是應選的正確階數。
因爲預測誤差功率P是單調下降的,因此,該值降到多少才合適,往往不好選擇。比較常見的準則是:
最終預測誤差準則:FPE(r)=Pr{[N+(r+1)]/ [N-(r+1)]}
信息論準則:AIC(r)=N*log(Pr)+2*r
上面的N爲有限長序列x(n)的長度,當階數r由1增加時,FPE(r) 和AIC(r)都將在某一r處取得極小值。將此時的r定爲最合適的階數p。
MATLAB中AR模型的譜估計的函數說明:
1. Pyulear函數:
功能:利用Yule--Walker方法進行功率譜估計.
格式: Pxx=Pyulear(x,ORDER,NFFT)
[Pxx,W]=Pyulear(x,ORDER,NFFT)
[Pxx,W]=Pyulear(x,ORDER,NFFT,Fs)
Pyulear(x,ORDER,NFFT,Fs,RANGE,MAGUNITS)
說明:Pxx =Pyulear(x,ORDER,NFFT)中,採用Yule--Walker方法估計序列x的功率譜,參數ORDER用來指定AR模型的階數,NFFT爲FFT算法的長度,默認值爲256,若NFFT爲偶數,則Pxx爲(NFFT/2 + 1)維的列矢量,若NFFT爲奇數,則Pxx爲(NFFT + 1)/2維的列矢量;當x爲複數時,Pxx長度爲NFFT。
[Pxx,W]=Pyulear(x,ORDER,NFFT)中,返回一個頻率向量W.
[Pxx,W]=Pyulear(x,ORDER,NFFT,Fs)中,可以在F向量得到功率譜估計的頻率點,Fs指定採樣頻率。
Pyulear(x,ORDER,NFFT,Fs,RANGE,MAGUNITS)中,直接畫出功率譜估計的曲線圖。
2. Pburg函數:
功能:利用Burg方法進行功率譜估計。
格式:Pxx=Pburg(x,ORDER,NFFT)
[Pxx,W]=Pburg(x,ORDER,NFFT)
[Pxx,W]=Pburg(x,ORDER,NFFT,Fs)
Pburg(x,ORDER,NFFT,Fs,RANGE,MAGUNITS)
說明:Pburg函數與Pyulear函數格式相同,只是計算AR模型時所採用的方法不同,因此格式可以參照Pyulear函數。
3. Pcov函數:
功能:利用協方差方法進行功率譜估計。
格式:Pxx=Pcov(x,ORDER,NFFT)
[Pxx,W]=Pcov(x,ORDER,NFFT)
[Pxx,W]=Pcov(x,ORDER,NFFT,Fs)
Pcov(x,ORDER,NFFT,Fs,RANGE,MAGUNITS)
說明:Pcov函數採用協方差法估計AR模型的參數,然後計算序列x的功率譜。協方差法與改進的協方差法相比,前者僅令前向預測誤差爲最小,其他步驟是一樣的。:Pcov函數與Pyulear函數格式相同,只是計算AR模型時所採用的方法不同,因此格式可以參照Pyulear函數.
4.Pmcov:
功能:利用改進的協方差方法進行功率譜估計。
格式:Pxx=Pmcov(x,ORDER,NFFT)
[Pxx,W]=Pmcov(x,ORDER,NFFT)
[Pxx,W]=Pmcov(x,ORDER,NFFT,Fs)
Pmcov(x,ORDER,NFFT,Fs,RANGE,MAGUNITS)
例如:輸入下面語句:
figure 8.10--8.11
Fs=1000; %採樣頻率
n=0:1/Fs:3;
xn=cos(2*pi*n*200)+randn(size(n));
%設置參數
order=20;
nfft=1024;
%Yule-Walker方法
figure(1)
pyulear(xn,order,nfft,Fs);
%Burg方法
figure(2)
pburg(xn,order,nfft,Fs);
%協方差法
figure(3)
pcov(xn,order,nfft,Fs);
%改進協方差方法
figure(4)
pmcov(xn,order,nfft,Fs);
AR譜的分辨率:
經典譜估計的分辨率反比與信號的有效長度,但是現代譜估計的分辨率可以不受此限制. 這是因爲對於給定的N點有限長序列x(n),雖然其估計出的相關函數也是有限長的,但是現代譜估計的一些方法隱含着數據和自相關函數的外推,使其可能的長度超過給定的長度,因而AR譜的分辨率較高。
例如:序列x(n)由兩個正鉉信號組成,其頻率分別爲f1=20Hz和f2=21Hz,並含有一定的噪聲量。試分別用週期圖法,Burg方法與改進的協方差法估計信號的功率譜,且AR模型的階數取30和50兩種情況討論。
上面的例子可以通過下面程序實現:
Fs=200;
n=0:1/Fs:1;
xn=sin(2*pi*20*n)+sin(2*pi*21*n)+0.1*randn(size(n));
window=boxcar(length(xn));
nfft=512;
[Pxx,f]=periodogram(xn,window,nfft,Fs);
figure(1)
plot(f,10*log10(Pxx)),grid
xlabel('Frequency(Hz)')
ylabel('Power Spectral Density(dB/Hz)')
title('Periodogram PSD Estimate')
order1=30;
order2=50;
figure(2)
pburg(xn,order1,nfft,Fs)
figure(3)
pburg(xn,order2,nfft,Fs)
figure(4)
pmcov(xn,order1,nfft,Fs)
figure(5)
pmcov(xn,order1,nfft)
4. C語言實現
- /*
- * ar_model.h
- *
- * Created on: 2013-8-11
- * Author: monkeyzx
- */
- #ifndef AR_MODEL_H_
- #define AR_MODEL_H_
- typedef struct {
- float real;
- float imag;
- } complex;
- extern void maryuwa(complex x[],complex a[],complex r[],int n,int ip,
- float *ep,int *ierror);
- extern void mpsplot(float psdr[],float psdi[],int mfre,float ts);
- extern void zx_ar_model(void);
- #endif /* AR_MODEL_H_ */
/*
* ar_model.h
*
* Created on: 2013-8-11
* Author: monkeyzx
*/
#ifndef AR_MODEL_H_
#define AR_MODEL_H_
typedef struct {
float real;
float imag;
} complex;
extern void maryuwa(complex x[],complex a[],complex r[],int n,int ip,
float *ep,int *ierror);
extern void mpsplot(float psdr[],float psdi[],int mfre,float ts);
extern void zx_ar_model(void);
#endif /* AR_MODEL_H_ */
- /*
- * ar_model.c
- *
- * Created on: 2013-8-11
- * Author: monkeyzx
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <stdlib.h>
- //#include "msp.h"
- #include "ar_model.h"
- #include "time.h"
- float mabs(complex a)
- {
- float m;
- m=a.real*a.real+a.imag*a.imag;
- m=sqrt(m);
- return(m);
- }
- /*---------------------------------------------------------------------
- Routine MCORRE1:To estimate the biased cross-correlation function
- of complex arrays x and y. If y=x,then it is auto-correlation.
- input parameters:
- x :n dimensioned complex array.
- y :n dimensioned complex array.
- n :the dimension of x and y.
- lag:point numbers of correlation.
- output parameters:
- r :lag dimensioned complex array, the correlation function is
- stored in r(0) to r(lag-1).
- in Chapter 1 and 11
- ---------------------------------------------------------------------*/
- void mcorre1(complex x[],complex y[],complex r[],int n,int lag)
- {
- int m,j,k;
- for(k=0;k<lag;k++) {
- m=n-1-k;
- r[k].real=0.0f;
- r[k].imag=0.0f;
- for(j=0;j<=m;j++) {
- r[k].real+=y[j+k].real*x[j].real+y[j+k].imag*x[j].imag;
- r[k].imag+=y[j+k].imag*x[j].real-y[j+k].real*x[j].imag;
- }
- r[k].real=r[k].real/n;
- r[k].imag=r[k].imag/n;
- }
- return;
- }
- /*---------------------------------------------------------------------
- Routine maryuwa: To determine the autoregressive coefficients by
- solving Yule-Walker equation with Levinson algorithm.
- Input Parameters:
- n : Number of data samples (integer)
- ip : Order of autoregressive model
- x : Array of complex data values, x(0) to x(n-1)
- Output Parameters:
- ep : Driving noise variance (real)
- a : Array of complex autoregressive coefficients, a(0) to
- a(ip)
- ierror=0 : No error
- =1 : ep<=0 .
- r : complex work array, auto-correlation
- in chapter 12
- --------------------------------------------------------------------*/
- void maryuwa(complex x[],complex a[],complex r[],int n,int ip,
- float *ep,int *ierror)
- {
- complex sum;
- int i,k;
- float r0;
- *ierror=1;
- mcorre1(x,x,r,n,ip+1);
- a[0].real=1.0;
- a[0].imag=0.0;
- r0=r[0].real;
- a[1].real=-r[1].real/r0;
- a[1].imag=-r[1].imag/r0;
- *ep=r0*(1.0f-pow(mabs(a[1]),2));
- for(k=2;k<=ip;k++) {
- sum.real=0.;
- sum.imag=0.;
- for(i=1;i<k;i++) {
- sum.real+=r[k-i].real*a[i].real-r[k-i].imag*a[i].imag;
- sum.imag+=r[k-i].real*a[i].imag+r[k-i].imag*a[i].real;
- }
- sum.real+=r[k].real;
- sum.imag+=r[k].imag;
- a[k].real=-sum.real/(*ep);
- a[k].imag=-sum.imag/(*ep);
- (*ep)*=1.-pow(mabs(a[k]),2);
- if(*ep<=0.0)
- return;
- for(i=1;i<k;i++) {
- x[i].real=a[i].real+a[k-i].real*a[k].real+
- a[k-i].imag*a[k].imag;
- x[i].imag=a[i].imag+a[k-i].real*a[k].imag-
- a[k-i].imag*a[k].real;
- }
- for(i=1;i<k;i++) {
- a[i].real=x[i].real;
- a[i].imag=x[i].imag;
- }
- }
- *ierror=0;
- }
- /*----------------------------------------------------------------------
- routinue mrelfft:To perform split-radix DIF fft algorithm.
- input parameters:
- xr,xi:real and image part of complex data for DFT/IDFT,n=0,...,N-1
- N :Data point number of DFT compute .
- isign:Transform direction disignator ,
- isign=-1: For Forward Transform.
- isign=+1: For Inverse Transform.
- output parameters:
- xr,xi:real and image part of complex result of DFT/IDFT,n=0,...,N-1
- Note: N must be a power of 2 .
- in chapter 5
- ---------------------------------------------------------------------*/
- void mrelfft(float xr[],float xi[],int n,int isign)
- {
- float e,es,cc1,ss1,cc3,ss3,r1,s1,r2,s2,s3,xtr,xti,a,a3;
- int m,n2,n4,j,k,is,id,i0,i1,i2,i3,n1,i,nn;
- for(m=1;m<=16;m++) {
- nn=pow(2,m);
- if(n==nn)break;
- }
- if(m>16) {
- #ifdef _DEBUG
- printf(" N is not a power of 2 ! \n");
- #endif
- return;
- }
- n2=n*2;
- es=-isign*atan(1.0)*8.0;
- for(k=1;k<m;k++) {
- n2=n2/2;
- n4=n2/4;
- e=es/n2;
- a=0.0;
- for(j=0;j<n4;j++) {
- a3=3*a;
- cc1=cos(a);
- ss1=sin(a);
- cc3=cos(a3);
- ss3=sin(a3);
- a=(j+1)*e;
- is=j;
- id=2*n2;
- do {
- for(i0=is;i0<n;i0+=id) {
- i1=i0+n4;
- i2=i1+n4;
- i3=i2+n4;
- r1=xr[i0]-xr[i2];
- s1=xi[i0]-xi[i2];
- r2=xr[i1]-xr[i3];
- s2=xi[i1]-xi[i3];
- xr[i0]+=xr[i2];
- xi[i0]+=xi[i2];
- xr[i1]+=xr[i3];
- xi[i1]+=xi[i3];
- if(isign!=1) {
- s3=r1-s2;
- r1=r1+s2;
- s2=r2-s1;
- r2=r2+s1;
- } else {
- s3=r1+s2;
- r1=r1-s2;
- s2=-r2-s1;
- r2=-r2+s1;
- }
- xr[i2]=r1*cc1-s2*ss1;
- xi[i2]=-s2*cc1-r1*ss1;
- xr[i3]=s3*cc3+r2*ss3;
- xi[i3]=r2*cc3-s3*ss3;
- }
- is=2*id-n2+j;
- id=4*id;
- }while(is<n-1);
- }
- }
- /* ------------ special last stage -------------------------*/
- is=0;
- id=4;
- do {
- for(i0=is;i0<n;i0+=id) {
- i1=i0+1;
- xtr=xr[i0];
- xti=xi[i0];
- xr[i0]=xtr+xr[i1];
- xi[i0]=xti+xi[i1];
- xr[i1]=xtr-xr[i1];
- xi[i1]=xti-xi[i1];
- }
- is=2*id-2;
- id=4*id;
- } while(is<n-1);
- j=1;
- n1=n-1;
- for(i=1;i<=n1;i++) {
- if(i<j) {
- xtr=xr[j-1];
- xti=xi[j-1];
- xr[j-1]=xr[i-1];
- xi[j-1]=xi[i-1];
- xr[i-1]=xtr;
- xi[i-1]=xti;
- }
- k=n/2;
- while(1) {
- if(k>=j)break;
- j=j-k;
- k=k/2;
- }
- j=j+k;
- }
- if(isign==-1) return;
- for(i=0;i<n;i++) {
- xr[i]/=n;
- xi[i]/=n;
- }
- }
- /*---------------------------------------------------------------------
- Routine mpsplot: To plot the normalized power spectum curve on the
- normalized frequency axis from -.5 to +.5 .
- mfre : Points in frequency axis and must be the power of 2.
- ts : Sample interval in seconds (real).
- psdr : Real array of power spectral density values.
- psdi : Real work array.
- in chapter 11,12
- --------------------------------------------------------------------*/
- void mpsplot(float psdr[],float psdi[],int mfre,float ts)
- {
- FILE *fp;
- char filename[30];
- int k,m2;
- float pmax,fs,faxis;
- m2=mfre/2;
- for(k=0;k<m2;k++){
- psdi[k]=psdr[k];
- psdr[k]=psdr[k+m2];
- psdr[k+m2]=psdi[k];
- }
- pmax=psdr[0];
- for(k=1;k<mfre;k++)
- if(psdr[k]>pmax)
- pmax=psdr[k];
- for(k=0;k<mfre;k++) {
- psdr[k]=psdr[k]/pmax;
- if(psdr[k]<=0.0)
- psdr[k]=.000001;
- }
- fs=1./ts;
- fs=fs/(float)(mfre);
- printf("Please input filename:\n");
- scanf("%s",filename);
- if((fp=fopen(filename,"w"))==NULL) {
- printf("cannot open file\n");
- exit(0);
- }
- for(k=0;k<mfre;k++) {
- faxis=fs*(k-m2);
- fprintf(fp,"%f,%f\n",faxis,10.*log10(psdr[k]));
- }
- fclose(fp);
- return;
- }
- /*----------------------------------------------------------------------
- Routine mar1psd: To compute the power spectum by AR-model parameters.
- Input parameters:
- ip : AR model order (integer)
- ep : White noise variance of model input (real)
- ts : Sample interval in seconds (real)
- a : Complex array of AR parameters a(0) to a(ip)
- Output parameters:
- psdr : Real array of power spectral density values
- psdi : Real work array
- in chapter 12
- ---------------------------------------------------------------------*/
- void mar1psd(complex a[],int ip,int mfre,float *ep,float ts)
- {
- static float psdr[4096];
- static float psdi[4096];
- int k;
- float p;
- for(k=0;k<=ip;k++) {
- psdr[k]=a[k].real;
- psdi[k]=a[k].imag;
- }
- for(k=ip+1;k<mfre;k++) {
- psdr[k]=0.;
- psdi[k]=0.;
- }
- mrelfft(psdr,psdi,mfre,-1);
- for(k=0;k<mfre;k++) {
- p=pow(psdr[k],2)+pow(psdi[k],2);
- psdr[k]=(*ep)*ts/p;
- }
- mpsplot(psdr,psdi,mfre,ts);
- return;
- }
- /*
- * Below are examples for using @maryuwa and @mar1psd
- */
- #define PI (3.1415926)
- #define N (1024)
- #define AN (10)
- complex x[N];
- complex r[N];
- complex a[AN];
- /*
- * generate random number which satify guass distribution
- */
- double guass_rand(void)
- {
- static double V1, V2, S;
- static int phase = 0;
- double X;
- if ( phase == 0 ) {
- do {
- double U1 = (double)rand() / RAND_MAX;
- double U2 = (double)rand() / RAND_MAX;
- V1 = 2 * U1 - 1;
- V2 = 2 * U2 - 1;
- S = V1 * V1 + V2 * V2;
- } while(S >= 1 || S == 0);
- X = V1 * sqrt(-2 * log(S) / S);
- } else {
- X = V2 * sqrt(-2 * log(S) / S);
- }
- phase = 1 - phase;
- return X;
- }
- void zx_ar_model(void)
- {
- int i=0;
- float ep = 0;
- int ierror = 0;
- /*
- * generate x[N]
- */
- srand(time(NULL));
- for (i=0; i<N; i++) {
- x[i].real = sin(2*PI*i/N) + guass_rand();
- x[i].imag = 0;
- }
- /* Find parameters for AR model */
- maryuwa(x, a, r, N, AN, &ep, &ierror);
- /* Calculate power spectum using parameters of AR model */
- mar1psd(a, AN, N, &ep, 1);
- }
/*
* ar_model.c
*
* Created on: 2013-8-11
* Author: monkeyzx
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdlib.h>
//#include "msp.h"
#include "ar_model.h"
#include "time.h"
float mabs(complex a)
{
float m;
m=a.real*a.real+a.imag*a.imag;
m=sqrt(m);
return(m);
}
/*---------------------------------------------------------------------
Routine MCORRE1:To estimate the biased cross-correlation function
of complex arrays x and y. If y=x,then it is auto-correlation.
input parameters:
x :n dimensioned complex array.
y :n dimensioned complex array.
n :the dimension of x and y.
lag:point numbers of correlation.
output parameters:
r :lag dimensioned complex array, the correlation function is
stored in r(0) to r(lag-1).
in Chapter 1 and 11
---------------------------------------------------------------------*/
void mcorre1(complex x[],complex y[],complex r[],int n,int lag)
{
int m,j,k;
for(k=0;k<lag;k++) {
m=n-1-k;
r[k].real=0.0f;
r[k].imag=0.0f;
for(j=0;j<=m;j++) {
r[k].real+=y[j+k].real*x[j].real+y[j+k].imag*x[j].imag;
r[k].imag+=y[j+k].imag*x[j].real-y[j+k].real*x[j].imag;
}
r[k].real=r[k].real/n;
r[k].imag=r[k].imag/n;
}
return;
}
/*---------------------------------------------------------------------
Routine maryuwa: To determine the autoregressive coefficients by
solving Yule-Walker equation with Levinson algorithm.
Input Parameters:
n : Number of data samples (integer)
ip : Order of autoregressive model
x : Array of complex data values, x(0) to x(n-1)
Output Parameters:
ep : Driving noise variance (real)
a : Array of complex autoregressive coefficients, a(0) to
a(ip)
ierror=0 : No error
=1 : ep<=0 .
r : complex work array, auto-correlation
in chapter 12
--------------------------------------------------------------------*/
void maryuwa(complex x[],complex a[],complex r[],int n,int ip,
float *ep,int *ierror)
{
complex sum;
int i,k;
float r0;
*ierror=1;
mcorre1(x,x,r,n,ip+1);
a[0].real=1.0;
a[0].imag=0.0;
r0=r[0].real;
a[1].real=-r[1].real/r0;
a[1].imag=-r[1].imag/r0;
*ep=r0*(1.0f-pow(mabs(a[1]),2));
for(k=2;k<=ip;k++) {
sum.real=0.;
sum.imag=0.;
for(i=1;i<k;i++) {
sum.real+=r[k-i].real*a[i].real-r[k-i].imag*a[i].imag;
sum.imag+=r[k-i].real*a[i].imag+r[k-i].imag*a[i].real;
}
sum.real+=r[k].real;
sum.imag+=r[k].imag;
a[k].real=-sum.real/(*ep);
a[k].imag=-sum.imag/(*ep);
(*ep)*=1.-pow(mabs(a[k]),2);
if(*ep<=0.0)
return;
for(i=1;i<k;i++) {
x[i].real=a[i].real+a[k-i].real*a[k].real+
a[k-i].imag*a[k].imag;
x[i].imag=a[i].imag+a[k-i].real*a[k].imag-
a[k-i].imag*a[k].real;
}
for(i=1;i<k;i++) {
a[i].real=x[i].real;
a[i].imag=x[i].imag;
}
}
*ierror=0;
}
/*----------------------------------------------------------------------
routinue mrelfft:To perform split-radix DIF fft algorithm.
input parameters:
xr,xi:real and image part of complex data for DFT/IDFT,n=0,...,N-1
N :Data point number of DFT compute .
isign:Transform direction disignator ,
isign=-1: For Forward Transform.
isign=+1: For Inverse Transform.
output parameters:
xr,xi:real and image part of complex result of DFT/IDFT,n=0,...,N-1
Note: N must be a power of 2 .
in chapter 5
---------------------------------------------------------------------*/
void mrelfft(float xr[],float xi[],int n,int isign)
{
float e,es,cc1,ss1,cc3,ss3,r1,s1,r2,s2,s3,xtr,xti,a,a3;
int m,n2,n4,j,k,is,id,i0,i1,i2,i3,n1,i,nn;
for(m=1;m<=16;m++) {
nn=pow(2,m);
if(n==nn)break;
}
if(m>16) {
#ifdef _DEBUG
printf(" N is not a power of 2 ! \n");
#endif
return;
}
n2=n*2;
es=-isign*atan(1.0)*8.0;
for(k=1;k<m;k++) {
n2=n2/2;
n4=n2/4;
e=es/n2;
a=0.0;
for(j=0;j<n4;j++) {
a3=3*a;
cc1=cos(a);
ss1=sin(a);
cc3=cos(a3);
ss3=sin(a3);
a=(j+1)*e;
is=j;
id=2*n2;
do {
for(i0=is;i0<n;i0+=id) {
i1=i0+n4;
i2=i1+n4;
i3=i2+n4;
r1=xr[i0]-xr[i2];
s1=xi[i0]-xi[i2];
r2=xr[i1]-xr[i3];
s2=xi[i1]-xi[i3];
xr[i0]+=xr[i2];
xi[i0]+=xi[i2];
xr[i1]+=xr[i3];
xi[i1]+=xi[i3];
if(isign!=1) {
s3=r1-s2;
r1=r1+s2;
s2=r2-s1;
r2=r2+s1;
} else {
s3=r1+s2;
r1=r1-s2;
s2=-r2-s1;
r2=-r2+s1;
}
xr[i2]=r1*cc1-s2*ss1;
xi[i2]=-s2*cc1-r1*ss1;
xr[i3]=s3*cc3+r2*ss3;
xi[i3]=r2*cc3-s3*ss3;
}
is=2*id-n2+j;
id=4*id;
}while(is<n-1);
}
}
/* ------------ special last stage -------------------------*/
is=0;
id=4;
do {
for(i0=is;i0<n;i0+=id) {
i1=i0+1;
xtr=xr[i0];
xti=xi[i0];
xr[i0]=xtr+xr[i1];
xi[i0]=xti+xi[i1];
xr[i1]=xtr-xr[i1];
xi[i1]=xti-xi[i1];
}
is=2*id-2;
id=4*id;
} while(is<n-1);
j=1;
n1=n-1;
for(i=1;i<=n1;i++) {
if(i<j) {
xtr=xr[j-1];
xti=xi[j-1];
xr[j-1]=xr[i-1];
xi[j-1]=xi[i-1];
xr[i-1]=xtr;
xi[i-1]=xti;
}
k=n/2;
while(1) {
if(k>=j)break;
j=j-k;
k=k/2;
}
j=j+k;
}
if(isign==-1) return;
for(i=0;i<n;i++) {
xr[i]/=n;
xi[i]/=n;
}
}
/*---------------------------------------------------------------------
Routine mpsplot: To plot the normalized power spectum curve on the
normalized frequency axis from -.5 to +.5 .
mfre : Points in frequency axis and must be the power of 2.
ts : Sample interval in seconds (real).
psdr : Real array of power spectral density values.
psdi : Real work array.
in chapter 11,12
--------------------------------------------------------------------*/
void mpsplot(float psdr[],float psdi[],int mfre,float ts)
{
FILE *fp;
char filename[30];
int k,m2;
float pmax,fs,faxis;
m2=mfre/2;
for(k=0;k<m2;k++){
psdi[k]=psdr[k];
psdr[k]=psdr[k+m2];
psdr[k+m2]=psdi[k];
}
pmax=psdr[0];
for(k=1;k<mfre;k++)
if(psdr[k]>pmax)
pmax=psdr[k];
for(k=0;k<mfre;k++) {
psdr[k]=psdr[k]/pmax;
if(psdr[k]<=0.0)
psdr[k]=.000001;
}
fs=1./ts;
fs=fs/(float)(mfre);
printf("Please input filename:\n");
scanf("%s",filename);
if((fp=fopen(filename,"w"))==NULL) {
printf("cannot open file\n");
exit(0);
}
for(k=0;k<mfre;k++) {
faxis=fs*(k-m2);
fprintf(fp,"%f,%f\n",faxis,10.*log10(psdr[k]));
}
fclose(fp);
return;
}
/*----------------------------------------------------------------------
Routine mar1psd: To compute the power spectum by AR-model parameters.
Input parameters:
ip : AR model order (integer)
ep : White noise variance of model input (real)
ts : Sample interval in seconds (real)
a : Complex array of AR parameters a(0) to a(ip)
Output parameters:
psdr : Real array of power spectral density values
psdi : Real work array
in chapter 12
---------------------------------------------------------------------*/
void mar1psd(complex a[],int ip,int mfre,float *ep,float ts)
{
static float psdr[4096];
static float psdi[4096];
int k;
float p;
for(k=0;k<=ip;k++) {
psdr[k]=a[k].real;
psdi[k]=a[k].imag;
}
for(k=ip+1;k<mfre;k++) {
psdr[k]=0.;
psdi[k]=0.;
}
mrelfft(psdr,psdi,mfre,-1);
for(k=0;k<mfre;k++) {
p=pow(psdr[k],2)+pow(psdi[k],2);
psdr[k]=(*ep)*ts/p;
}
mpsplot(psdr,psdi,mfre,ts);
return;
}
/*
* Below are examples for using @maryuwa and @mar1psd
*/
#define PI (3.1415926)
#define N (1024)
#define AN (10)
complex x[N];
complex r[N];
complex a[AN];
/*
* generate random number which satify guass distribution
*/
double guass_rand(void)
{
static double V1, V2, S;
static int phase = 0;
double X;
if ( phase == 0 ) {
do {
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while(S >= 1 || S == 0);
X = V1 * sqrt(-2 * log(S) / S);
} else {
X = V2 * sqrt(-2 * log(S) / S);
}
phase = 1 - phase;
return X;
}
void zx_ar_model(void)
{
int i=0;
float ep = 0;
int ierror = 0;
/*
* generate x[N]
*/
srand(time(NULL));
for (i=0; i<N; i++) {
x[i].real = sin(2*PI*i/N) + guass_rand();
x[i].imag = 0;
}
/* Find parameters for AR model */
maryuwa(x, a, r, N, AN, &ep, &ierror);
/* Calculate power spectum using parameters of AR model */
mar1psd(a, AN, N, &ep, 1);
}
- /*
- * main.c
- *
- * Created on: 2013-8-11
- * Author: monkeyzx
- */
- #include "ar_model.h"
- int main(void)
- {
- zx_ar_model();
- return 0;
- }
/*
* main.c
*
* Created on: 2013-8-11
* Author: monkeyzx
*/
#include "ar_model.h"
int main(void)
{
zx_ar_model();
return 0;
}
上面的實例中給定輸入信號爲餘弦信號,採樣點數爲1024個點,通過計算後的功率譜通過mpsplot函數保存到文本文件output.txt中,保存格式如下:
-0.500000,-15.334630
-0.499023,-15.334833
-0.498047,-15.335444
-0.497070,-15.336456
-0.496094,-15.337864
-0.495117,-15.339655
-0.494141,-15.341816
-0.493164,-15.344331
-0.492188,-15.347179
-0.491211,-15.350342
-0.490234,-15.353794
-0.489258,-15.357505
-0.488281,-15.361453
-0.487305,-15.365603
-0.486328,-15.369924
-0.485352,-15.374381
......
最後藉助matlab讀取該文件,繪製出功率譜的圖形
data = load('output.txt');
plot(data(:,1),data(:,2));
關於上面的C程序,這裏只提與主題無關的,double guass_rand(void)是C語言中典型的生成高斯分佈隨機數的發生器,這裏用於在餘弦函數上加上一個高斯的噪聲。關於更多的隨機數生成器可參考關於怎樣產生隨機數的徹底研究 [自行理解],我將該博文轉載過來,感謝作者。
Refrences:
[1] 胡廣書《數字信號處理——理論、算法與實現 第二版》
[2] AR模型matlab相關函數描述http://blog.sina.com.cn/s/blog_62f573ad0100sfh1.html
2015-06-01補充:
更詳細,更正確,經過驗證整理的代碼參考https://github.com/xiahouzuoxin/ar_model