AR模型在信號處理中的應用

本文目標:分析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語言實現

  1. /* 
  2.  * ar_model.h 
  3.  * 
  4.  *  Created on: 2013-8-11 
  5.  *      Author: monkeyzx 
  6.  */  
  7.   
  8. #ifndef AR_MODEL_H_  
  9. #define AR_MODEL_H_  
  10.   
  11. typedef struct {  
  12.     float real;  
  13.     float imag;  
  14. } complex;  
  15.   
  16. extern void maryuwa(complex x[],complex a[],complex r[],int n,int ip,  
  17.         float *ep,int *ierror);  
  18. extern void mpsplot(float psdr[],float psdi[],int mfre,float ts);  
  19.   
  20. extern void zx_ar_model(void);  
  21.   
  22. #endif /* AR_MODEL_H_ */  
save_snippets.png
/*
 * 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_ */

  1. /* 
  2.  * ar_model.c 
  3.  * 
  4.  *  Created on: 2013-8-11 
  5.  *      Author: monkeyzx 
  6.  */  
  7.   
  8. #include <stdio.h>  
  9. #include <stdlib.h>  
  10. #include <math.h>  
  11. #include <stdlib.h>  
  12. //#include "msp.h"  
  13. #include "ar_model.h"  
  14. #include "time.h"  
  15.   
  16. float mabs(complex a)  
  17. {  
  18.      float m;  
  19.   
  20.      m=a.real*a.real+a.imag*a.imag;  
  21.      m=sqrt(m);  
  22.   
  23.      return(m);  
  24. }  
  25.   
  26. /*--------------------------------------------------------------------- 
  27.   Routine MCORRE1:To estimate the biased cross-correlation function 
  28.   of complex arrays x and y. If y=x,then it is auto-correlation. 
  29.   input parameters: 
  30.      x  :n dimensioned complex array. 
  31.      y  :n dimensioned complex array. 
  32.      n  :the dimension of x and y. 
  33.      lag:point numbers of correlation. 
  34.   output parameters: 
  35.      r  :lag dimensioned complex array, the correlation function is 
  36.          stored in r(0) to r(lag-1). 
  37.                                       in Chapter 1 and 11 
  38. ---------------------------------------------------------------------*/  
  39. void mcorre1(complex x[],complex y[],complex r[],int n,int lag)  
  40. {  
  41.     int m,j,k;  
  42.   
  43.     for(k=0;k<lag;k++) {  
  44.         m=n-1-k;  
  45.         r[k].real=0.0f;  
  46.         r[k].imag=0.0f;  
  47.         for(j=0;j<=m;j++) {  
  48.             r[k].real+=y[j+k].real*x[j].real+y[j+k].imag*x[j].imag;  
  49.             r[k].imag+=y[j+k].imag*x[j].real-y[j+k].real*x[j].imag;  
  50.         }  
  51.         r[k].real=r[k].real/n;  
  52.         r[k].imag=r[k].imag/n;  
  53.     }  
  54.     return;  
  55. }  
  56.   
  57. /*--------------------------------------------------------------------- 
  58.   Routine maryuwa: To determine the autoregressive coefficients by 
  59.           solving Yule-Walker equation with Levinson algorithm. 
  60.   Input Parameters: 
  61.      n     : Number of data samples (integer) 
  62.      ip    : Order of autoregressive model 
  63.      x     : Array of complex data values, x(0) to x(n-1) 
  64.   Output Parameters: 
  65.      ep    : Driving noise variance (real) 
  66.      a     : Array of complex autoregressive coefficients, a(0) to 
  67.              a(ip) 
  68.   ierror=0 : No error 
  69.         =1 : ep<=0 . 
  70.  
  71.         r  : complex work array, auto-correlation 
  72.                                        in chapter 12 
  73. --------------------------------------------------------------------*/  
  74. void maryuwa(complex x[],complex a[],complex r[],int n,int ip,  
  75. float *ep,int *ierror)  
  76. {  
  77.     complex sum;  
  78.     int i,k;  
  79.     float r0;  
  80.   
  81.     *ierror=1;  
  82.     mcorre1(x,x,r,n,ip+1);  
  83.     a[0].real=1.0;  
  84.     a[0].imag=0.0;  
  85.     r0=r[0].real;  
  86.     a[1].real=-r[1].real/r0;  
  87.     a[1].imag=-r[1].imag/r0;  
  88.     *ep=r0*(1.0f-pow(mabs(a[1]),2));  
  89.     for(k=2;k<=ip;k++) {  
  90.         sum.real=0.;  
  91.         sum.imag=0.;  
  92.         for(i=1;i<k;i++) {  
  93.             sum.real+=r[k-i].real*a[i].real-r[k-i].imag*a[i].imag;  
  94.             sum.imag+=r[k-i].real*a[i].imag+r[k-i].imag*a[i].real;  
  95.         }  
  96.         sum.real+=r[k].real;  
  97.         sum.imag+=r[k].imag;  
  98.         a[k].real=-sum.real/(*ep);  
  99.         a[k].imag=-sum.imag/(*ep);  
  100.         (*ep)*=1.-pow(mabs(a[k]),2);  
  101.         if(*ep<=0.0)  
  102.             return;  
  103.         for(i=1;i<k;i++) {  
  104.             x[i].real=a[i].real+a[k-i].real*a[k].real+  
  105.                     a[k-i].imag*a[k].imag;  
  106.             x[i].imag=a[i].imag+a[k-i].real*a[k].imag-  
  107.                     a[k-i].imag*a[k].real;  
  108.         }  
  109.         for(i=1;i<k;i++) {  
  110.             a[i].real=x[i].real;  
  111.             a[i].imag=x[i].imag;  
  112.         }  
  113.     }  
  114.     *ierror=0;  
  115. }  
  116.   
  117. /*---------------------------------------------------------------------- 
  118.   routinue mrelfft:To perform  split-radix DIF fft algorithm. 
  119.  
  120.   input parameters: 
  121.    xr,xi:real and image part of complex data for DFT/IDFT,n=0,...,N-1 
  122.    N    :Data point number of DFT compute . 
  123.    isign:Transform direction disignator , 
  124.                isign=-1: For Forward Transform. 
  125.                isign=+1: For Inverse Transform. 
  126.  
  127.   output parameters: 
  128.    xr,xi:real and image part of complex result of DFT/IDFT,n=0,...,N-1 
  129.  
  130.   Note: N  must be a power of 2 . 
  131.                                        in chapter 5 
  132. ---------------------------------------------------------------------*/  
  133. void mrelfft(float xr[],float xi[],int n,int isign)  
  134. {  
  135.     float e,es,cc1,ss1,cc3,ss3,r1,s1,r2,s2,s3,xtr,xti,a,a3;  
  136.     int m,n2,n4,j,k,is,id,i0,i1,i2,i3,n1,i,nn;  
  137.   
  138.     for(m=1;m<=16;m++) {  
  139.         nn=pow(2,m);  
  140.         if(n==nn)break;  
  141.     }  
  142.     if(m>16) {  
  143. #ifdef _DEBUG  
  144.         printf(" N is not a power of 2 ! \n");  
  145. #endif  
  146.         return;  
  147.     }  
  148.     n2=n*2;  
  149.     es=-isign*atan(1.0)*8.0;  
  150.     for(k=1;k<m;k++) {  
  151.         n2=n2/2;  
  152.         n4=n2/4;  
  153.         e=es/n2;  
  154.         a=0.0;  
  155.         for(j=0;j<n4;j++) {  
  156.             a3=3*a;  
  157.             cc1=cos(a);  
  158.             ss1=sin(a);  
  159.             cc3=cos(a3);  
  160.             ss3=sin(a3);  
  161.             a=(j+1)*e;  
  162.             is=j;  
  163.             id=2*n2;  
  164.             do {  
  165.                 for(i0=is;i0<n;i0+=id) {  
  166.                     i1=i0+n4;  
  167.                     i2=i1+n4;  
  168.                     i3=i2+n4;  
  169.                     r1=xr[i0]-xr[i2];  
  170.                     s1=xi[i0]-xi[i2];  
  171.                     r2=xr[i1]-xr[i3];  
  172.                     s2=xi[i1]-xi[i3];  
  173.                     xr[i0]+=xr[i2];  
  174.                     xi[i0]+=xi[i2];  
  175.                     xr[i1]+=xr[i3];  
  176.                     xi[i1]+=xi[i3];  
  177.                     if(isign!=1) {  
  178.                         s3=r1-s2;  
  179.                         r1=r1+s2;  
  180.                         s2=r2-s1;  
  181.                         r2=r2+s1;  
  182.                     } else {  
  183.                             s3=r1+s2;  
  184.                             r1=r1-s2;  
  185.                             s2=-r2-s1;  
  186.                             r2=-r2+s1;  
  187.                     }  
  188.                     xr[i2]=r1*cc1-s2*ss1;  
  189.                     xi[i2]=-s2*cc1-r1*ss1;  
  190.                     xr[i3]=s3*cc3+r2*ss3;  
  191.                     xi[i3]=r2*cc3-s3*ss3;  
  192.                 }  
  193.                 is=2*id-n2+j;  
  194.                 id=4*id;  
  195.             }while(is<n-1);  
  196.         }  
  197.     }  
  198. /*   ------------ special last stage -------------------------*/  
  199.     is=0;  
  200.     id=4;  
  201.     do {  
  202.         for(i0=is;i0<n;i0+=id) {  
  203.             i1=i0+1;  
  204.             xtr=xr[i0];  
  205.             xti=xi[i0];  
  206.             xr[i0]=xtr+xr[i1];  
  207.             xi[i0]=xti+xi[i1];  
  208.             xr[i1]=xtr-xr[i1];  
  209.             xi[i1]=xti-xi[i1];  
  210.         }  
  211.         is=2*id-2;  
  212.         id=4*id;  
  213.     } while(is<n-1);  
  214.     j=1;  
  215.     n1=n-1;  
  216.     for(i=1;i<=n1;i++) {  
  217.         if(i<j) {  
  218.             xtr=xr[j-1];  
  219.             xti=xi[j-1];  
  220.             xr[j-1]=xr[i-1];  
  221.             xi[j-1]=xi[i-1];  
  222.             xr[i-1]=xtr;  
  223.             xi[i-1]=xti;  
  224.         }  
  225.         k=n/2;  
  226.         while(1) {  
  227.             if(k>=j)break;  
  228.             j=j-k;  
  229.             k=k/2;  
  230.         }  
  231.         j=j+k;  
  232.     }  
  233.     if(isign==-1) return;  
  234.     for(i=0;i<n;i++) {  
  235.         xr[i]/=n;  
  236.         xi[i]/=n;  
  237.     }  
  238. }  
  239.   
  240. /*--------------------------------------------------------------------- 
  241.    Routine mpsplot: To plot the normalized power spectum curve on the 
  242.    normalized frequency axis from -.5 to  +.5 . 
  243.         mfre : Points in frequency axis and must be the power of 2. 
  244.         ts   : Sample interval in seconds (real). 
  245.         psdr : Real array of power spectral density values. 
  246.         psdi : Real work array. 
  247.                                        in chapter 11,12 
  248. --------------------------------------------------------------------*/  
  249. void mpsplot(float psdr[],float psdi[],int mfre,float ts)  
  250. {  
  251.     FILE *fp;  
  252.     char filename[30];  
  253.     int k,m2;  
  254.     float pmax,fs,faxis;  
  255.   
  256.     m2=mfre/2;  
  257.     for(k=0;k<m2;k++){  
  258.         psdi[k]=psdr[k];  
  259.         psdr[k]=psdr[k+m2];  
  260.         psdr[k+m2]=psdi[k];  
  261.     }  
  262.     pmax=psdr[0];  
  263.     for(k=1;k<mfre;k++)  
  264.         if(psdr[k]>pmax)  
  265.             pmax=psdr[k];  
  266.         for(k=0;k<mfre;k++) {  
  267.             psdr[k]=psdr[k]/pmax;  
  268.         if(psdr[k]<=0.0)  
  269.             psdr[k]=.000001;  
  270.     }  
  271.     fs=1./ts;  
  272.     fs=fs/(float)(mfre);  
  273.     printf("Please input filename:\n");  
  274.     scanf("%s",filename);  
  275.     if((fp=fopen(filename,"w"))==NULL) {  
  276.         printf("cannot open file\n");  
  277.         exit(0);  
  278.     }  
  279.     for(k=0;k<mfre;k++) {  
  280.         faxis=fs*(k-m2);  
  281.         fprintf(fp,"%f,%f\n",faxis,10.*log10(psdr[k]));  
  282.     }  
  283.     fclose(fp);  
  284.     return;  
  285. }  
  286.   
  287. /*---------------------------------------------------------------------- 
  288.    Routine mar1psd: To compute the power spectum by AR-model parameters. 
  289.    Input parameters: 
  290.           ip : AR model order (integer) 
  291.           ep   : White noise variance of model input (real) 
  292.           ts   : Sample interval in seconds (real) 
  293.           a    : Complex array of AR  parameters a(0) to a(ip) 
  294.    Output parameters: 
  295.           psdr : Real array of power spectral density values 
  296.           psdi : Real work array 
  297.                                         in chapter 12 
  298. ---------------------------------------------------------------------*/  
  299. void mar1psd(complex a[],int ip,int mfre,float *ep,float ts)  
  300. {  
  301.     static float psdr[4096];  
  302.     static float psdi[4096];  
  303.     int k;  
  304.     float p;  
  305.   
  306.     for(k=0;k<=ip;k++) {  
  307.         psdr[k]=a[k].real;  
  308.         psdi[k]=a[k].imag;  
  309.     }  
  310.     for(k=ip+1;k<mfre;k++) {  
  311.         psdr[k]=0.;  
  312.         psdi[k]=0.;  
  313.     }  
  314.     mrelfft(psdr,psdi,mfre,-1);  
  315.     for(k=0;k<mfre;k++) {  
  316.         p=pow(psdr[k],2)+pow(psdi[k],2);  
  317.         psdr[k]=(*ep)*ts/p;  
  318.     }  
  319.   
  320.     mpsplot(psdr,psdi,mfre,ts);  
  321.   
  322.     return;  
  323. }  
  324.   
  325.   
  326. /* 
  327.  * Below are examples for using @maryuwa and @mar1psd 
  328.  */  
  329. #define PI            (3.1415926)  
  330. #define N             (1024)  
  331. #define AN            (10)  
  332. complex x[N];  
  333. complex r[N];  
  334. complex a[AN];  
  335.   
  336. /* 
  337.  * generate random number which satify guass distribution 
  338.  */  
  339. double guass_rand(void)  
  340. {  
  341.     static double V1, V2, S;  
  342.     static int phase = 0;  
  343.     double X;  
  344.   
  345.     if ( phase == 0 ) {  
  346.         do {  
  347.             double U1 = (double)rand() / RAND_MAX;  
  348.             double U2 = (double)rand() / RAND_MAX;  
  349.   
  350.             V1 = 2 * U1 - 1;  
  351.             V2 = 2 * U2 - 1;  
  352.             S = V1 * V1 + V2 * V2;  
  353.         } while(S >= 1 || S == 0);  
  354.   
  355.         X = V1 * sqrt(-2 * log(S) / S);  
  356.     } else {  
  357.         X = V2 * sqrt(-2 * log(S) / S);  
  358.     }  
  359.   
  360.     phase = 1 - phase;  
  361.   
  362.     return X;  
  363. }  
  364.   
  365. void zx_ar_model(void)  
  366. {  
  367.     int i=0;  
  368.     float ep = 0;  
  369.     int ierror = 0;  
  370.   
  371.     /* 
  372.      * generate x[N] 
  373.      */  
  374.     srand(time(NULL));  
  375.     for (i=0; i<N; i++) {  
  376.         x[i].real = sin(2*PI*i/N) + guass_rand();  
  377.         x[i].imag = 0;  
  378.     }  
  379.   
  380.     /* Find parameters for AR model */  
  381.     maryuwa(x, a, r, N, AN, &ep, &ierror);  
  382.   
  383.     /* Calculate power spectum using parameters of AR model */  
  384.     mar1psd(a, AN, N, &ep, 1);  
  385. }  
save_snippets.png
/*
 * 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);
}

  1. /* 
  2.  * main.c 
  3.  * 
  4.  *  Created on: 2013-8-11 
  5.  *      Author: monkeyzx 
  6.  */  
  7. #include "ar_model.h"  
  8.   
  9. int main(void)  
  10. {  
  11.     zx_ar_model();  
  12.   
  13.     return 0;  
  14. }  
save_snippets.png
/*
 * 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讀取該文件,繪製出功率譜的圖形

  1. data = load('output.txt');  
  2. plot(data(:,1),data(:,2));  
save_snippets.png
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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章