FFT和解析解的自回归序列的光谱密度差异

信息处理 fft 功率谱密度 时频 时间序列 自回归模型
2022-02-24 11:13:21

我想获得自回归序列 AR(1) 的功率谱密度 (PSD)。根据参考资料(第 12 页)的分析解决方案是

对于Xt=ϕ1Xt1+Wt,WtN(0,σw2)

f(w)=σw212ϕ1cos(2πw)+ϕ12

,,则 [0, 2pi] 中使用 fft 和解析解对应的 PSD 曲线为σw=1ϕ1=0.4

在此处输入图像描述

从下图可以看出,fft得到的PSD远不是解析解得到的U型曲线。

在此处输入图像描述

谁能告诉我为什么结果不同?


我用来生成情节的代码是:

import matplotlib.pyplot as plt
import numpy as np
from scipy.fft import fft, fftfreq  

def analy(x):
    PSD = 1/(1.16-0.8*np.cos(2*np.pi*x))
    return PSD

def my_fft(N):   
    T = 1  # sample spacing
    t = np.linspace(0.0, N*T, N, endpoint=True)
    y = np.zeros([N,1])

    rho = 0.4
    for i in range(len(t)-1):
        y[i+1] = rho*y[i] + (1-0)*np.random.normal(0,1) 

    yf = fft(y)   
    xf = fftfreq(N, T)[:N//2]  # sample frequency points
    PSD = 2.0/N * np.abs(yf[0:N//2])

    return xf*np.pi*2, PSD

def compare_PSD():
    N = 100     # Number of sample points
    UB = np.pi  # sample upper bound
    x_analy = np.linspace(0, UB, num=N)
    PSD_analy = analy(x_analy)
    x_fft, PSD_fft = my_fft(N)
    plt.plot(x_analy, PSD_analy, label='Analytical')
    plt.plot(x_fft, PSD_fft, label='scipy.fft')
    plt.xlabel('Frequency')
    plt.ylabel('PSD')
    plt.legend()
    plt.show()

compare_PSD() 

1个回答

我得到了正确的结果。我之前的比较有两个错误。

  1. 概念错误:PSD是通过对协方差进行傅里叶变换得到的,而不是原始时间序列数据。

f(v)=h=σw21ϕ12ρ(h)e2πivh=σw21ϕ12[2h(0,)ϕ1he2πivhϕ10e0]

  1. 编码:“scipy.fft”将向量作为输入。但是,前面代码中的“y”是一个矩阵。

下面是正确的结果。 在此处输入图像描述


import matplotlib.pyplot as plt
import numpy as np
from scipy.fft import fft, fftfreq  

def cal_PSD_anal(x, phi):
    PSD = 1/(1 + phi**2-2*phi*np.cos(2*np.pi*x))
    return PSD

def cal_PSD_fft(N, phi):     
    # covaraince 
    gamma = phi**np.arange(N)
    yf = fft(gamma).real
    PSD = 1 / (1 - phi**2) * (2*np.abs(yf[0:N//2]) - 1)    
    return PSD

def compare_PSD():
    N = 100     # Number of sample points
    UB = 0.5 #np.pi  # sample upper bound
    T = 1  # sample spacing
    phi = 0.4
        
    x = fftfreq(N, T)[:N//2]  # sample frequency points
    PSD_fft = cal_PSD_fft(N, phi)    

    PSD_anal = cal_PSD_anal(x, phi)
    
    plt.figure(figsize=(4, 3), dpi=300) 
    plt.plot(x, PSD_anal, 'bo', label='Analytical', markersize=4)
    plt.plot(x, PSD_fft, 'r', label='FFT') 

    plt.title('PSD of AR(1, {})'.format(phi))
    plt.xlabel('Frequency')
    plt.ylabel('PSD')
    plt.legend()
    plt.grid(axis='y')
    plt.tight_layout()
    plt.savefig('./PSD_AR_1_{}.png'.format(phi), dpi=300)
    plt.show()
    
compare_PSD()