通过拟合计算提高FFT幅度谱求频率的分辨率

1. 问题描述

当信号为单一频率成分,但其频率不在FFT分辨率点上时,无法直接通过FFT幅度谱峰值点获得精确频率。

在单一信号频率无噪声的情况下,幅度谱的‘形状’只和频率有关,和信号的幅度与相位无关(这里的形状可以指归一化幅度谱)。因此可以尝试通过幅度谱的形状推导出频率。

本文通过数学推导得出幅度谱比值和频率的关系,从而得到频率插值的公式。

python
def fit_func1(x0, x1, x2, y0, y1, y2):
    assert y1 >= y0 and y1 >= y2
    a = x1
    b = -1 if (y0 > y2) else 1
    r = y1 / (y0 if (y0 > y2) else y2)
    x_peak = a + b / (r + 1)
    return x_peak

具体的Python实验:非整数倍周期信号FFT影响.py

该方法的实际应用:idx_estimation()函数:通过中心点的幅度谱值与相邻点的幅度谱值,估计出更精确的坐标

2. 数学模型

2.1 信号定义

考虑归一化频率为 ff 的复指数信号:

x[n]=ej2πfn,n=0,1,,N1x[n] = e^{j2\pi f n}, \quad n=0,1,\cdots,N-1

其DFT定义为:

X[k]=n=0N1x[n]ej2πkn/NX[k] = \sum_{n=0}^{N-1} x[n] e^{-j2\pi kn/N}

2.2 等比数列求和

将信号表达式代入DFT:

X[k]=n=0N1ej2πfnej2πkn/N=n=0N1ej2πn(fk/N)X[k] = \sum_{n=0}^{N-1} e^{j2\pi f n} \cdot e^{-j2\pi kn/N} = \sum_{n=0}^{N-1} e^{j2\pi n (f - k/N)}

这是一个首项为 a1=1a_1 = 1,公比为 r=ej2π(fk/N)r = e^{j2\pi (f - k/N)} 的等比数列。等比数列求和公式为:

SN=a11rN1rS_N = a_1 \frac{1 - r^N}{1 - r}

代入参数:

X[k]=1[ej2π(fk/N)]N1ej2π(fk/N)X[k] = \frac{1 - [e^{j2\pi (f - k/N)}]^N}{1 - e^{j2\pi (f - k/N)}}

2.3 简化表达式

化简分子:

[ej2π(fk/N)]N=ej2πN(fk/N)=ej2π(Nfk)[e^{j2\pi (f - k/N)}]^N = e^{j2\pi N(f - k/N)} = e^{j2\pi (Nf - k)}

由于 kk 是整数,ej2πk=1e^{-j2\pi k} = 1,所以:

ej2π(Nfk)=ej2πNfe^{j2\pi (Nf - k)} = e^{j2\pi Nf}

因此分子简化为:

1ej2πNf1 - e^{j2\pi Nf}

最终DFT表达式为:

X[k]=1ej2πNf1ej2π(fk/N)X[k] = \frac{1 - e^{j2\pi Nf}}{1 - e^{j2\pi (f - k/N)}}

2.4 幅度谱表达式

幅度谱为:

X[k]=1ej2πNf1ej2π(fk/N)|X[k]| = \left| \frac{1 - e^{j2\pi Nf}}{1 - e^{j2\pi (f - k/N)}} \right|

利用复指数性质 1ejθ=2sin(θ/2)|1 - e^{j\theta}| = 2|\sin(\theta/2)|

X[k]=sin(πNf)sin[π(fk/N)]|X[k]| = \frac{|\sin(\pi Nf)|}{|\sin[\pi (f - k/N)]|}

3. 任意两点幅度比值计算

3.1 分类讨论

X[k]|X[k]|表达式的分子是一个不随序号kk改变的值,那么通过相除可以去掉该项

考虑频点 aabb,其幅度比为:

X[a]X[b]=sin[π(fa/N)]1sin[π(fb/N)]1=sin[π(fb/N)]sin[π(fa/N)]\frac{|X[a]|}{|X[b]|} = \frac{|\sin[\pi (f - a/N)]|^{-1}}{|\sin[\pi (f - b/N)]|^{-1}} = \frac{|\sin[\pi (f - b/N)]|}{|\sin[\pi (f - a/N)]|}

fb/Nf-b/N 的值非常小时,可以应用近似:

sin(x)=xsin(x) = x

因此我们取点峰值点k1k_1与相邻点k1±1k_1 \pm 1计算比值

在峰值邻域(k1k_1及其相邻点),设f=k1+δNf = \frac{k_1 + \delta}{N},则:

  1. 峰值点k1k_1

X[k1]1sin(πδ/N)|X[k_1]| \propto \frac{1}{|\sin(\pi \delta/N)|}

  1. 相邻点k1±1k_1 \pm 1

X[k1±1]1sin[π(δ1)/N]|X[k_1 \pm 1]| \propto \frac{1}{|\sin[\pi (\delta \mp 1)/N]|}


情况1:δ0\delta \geq 0(取右侧点k1+1k_1+1)

r=X[k1]X[k1+1]=sin[π(δ1)/N]sin(πδ/N)r = \frac{|X[k_1]|}{|X[k_1+1]|} = \frac{|\sin[\pi (\delta - 1)/N]|}{|\sin(\pi \delta/N)|}

NN较大时,小角度近似sinθθ\sin\theta \approx \theta

rπ(δ1)/Nπδ/N=1δδ=1δδr \approx \frac{|\pi (\delta - 1)/N|}{|\pi \delta/N|} = \frac{|1 - \delta|}{\delta} = \frac{1 - \delta}{\delta}

解得:

δ1r+1\delta \approx \frac{1}{r + 1}


情况2:δ<0\delta < 0(取左侧点k11k_1-1)

r=X[k1]X[k11]=sin[π(δ+1)/N]sin(πδ/N)1+δδ=1+δδr = \frac{|X[k_1]|}{|X[k_1-1]|} = \frac{|\sin[\pi (\delta + 1)/N]|}{|\sin(\pi \delta/N)|} \approx \frac{|1 + \delta|}{|\delta|} = -\frac{1 + \delta}{\delta}

解得:

δ1r+1\delta \approx \frac{-1}{r + 1}


3.2 统一表达式

两种情况的解可统一表示为:

δbr+1\delta \approx \frac{b}{r + 1}

其中:

b={1δ01δ<0b = \begin{cases} 1 & \delta \geq 0 \\ -1 & \delta < 0 \end{cases}

综上

我们计算拟合频点的方法为

  1. 找到幅度谱X|X| 的峰值点 k1k_1 以及相邻点中较大的点 k1±1k_1 \pm 1
  2. 计算 r=X[k1]X[k1±1]r = \frac{|X[k_1]|}{|X[k_1 \pm 1]|}, b = 11 or 1-1
  3. 根据 rr DFT频点 fNfN

    fN=k1+δ=k1+br+1,b={1δ01δ<0fN = k_1 + \delta = k_1 + \frac{b}{r + 1} , b = \begin{cases} 1 & \delta \geq 0 \\ -1 & \delta < 0 \end{cases}

4. 其他

假如选择峰值点和较小的相邻点推导,公式为

fN=k1+b1r,b={1δ01δ<0fN = k_1 + \frac{b}{1-r} , b = \begin{cases} 1 & \delta \geq 0 \\ -1 & \delta < 0 \end{cases}

5. 实验

此处展示非整数倍周期信号FFT影响.py的运行结果

  1. 测试不同频率的正弦信号下通过幅度谱峰值计算频率的误差
alt text
  1. 生成一个包含两种频率成分的信号,搜索幅度谱峰值后进行插值求频率
alt text
nuttx启动流程
记录一些shell指令