离散傅里叶变换DFT基本原理图解:矩形窗和汉宁窗

文章探讨了DFT的基本原理,通过对比不同时间窗和采样率,分析了矩形窗和汉宁窗对频谱泄露的影响。整周期采样可减少频谱泄露,而非整周期采样则会导致泄露。汉宁窗虽能有效降低旁瓣,减少泄露,但会牺牲一些频率分辨率。文章还提供了MATLAB代码示例来可视化这些概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前两天看书,看到解释DFT基本原理的,认为讲的挺好的,虽然在信号与系统里也学过类似的图,但没有对比,有些东西领会的不深,这个通过对比不同时间窗、不同采样率对频谱泄露的影响等,讲的很好,然后我进一步发挥,对比了矩形窗和汉宁窗,以加深理解。

先来看加矩形窗的整周期采样过程(整周期采样体现在窗宽为周期的整数倍),参数如下:

T0 = 1;

% 余弦波的周期

f0 = 1/T0;

% 余弦波的频率

A = 1;

% 余弦波的振幅

Ts = 0.1;

% 时域采样周期

Fs = 1/Ts;

wT = 1;

% 窗的宽度

windowflag = 1;

% 1为矩形窗,其他为汉宁窗

结果如下:

可以看到整周期采样没有频谱泄露。其实在加窗时就会造成频谱的泄露,如sinc函数形状有明显的旁瓣,但如果窗函数的宽度是信号周期的整数倍,则频域采样(时域周期延拓)将正好采在sinc函数的峰值处,表现出来就是没有频谱泄露(上图中最后一幅图)。

如果不是整周期采样,如设窗宽为:

wT = 1.4;

% 窗的宽度

结果为:

可以看到非整周期采样时,频域的采样点采在sinc函数的非峰值处,造成明显的频谱泄露(上图中最后一幅图)。

而如果这时使用其他窗函数,则可以改善频谱泄露的状况,如使用汉宁窗:

windowflag = 2;

% 1为矩形窗,其他为汉宁窗

结果如下:

可以看到汉宁窗的旁瓣非常低,能量相对矩形窗非常集中,最后的结果是虽然仍有频谱泄露,但相对于矩形窗已经好得多了,主要还在于其压低的旁瓣很小。可见加窗的效果。

汉宁窗也有它的缺点,就是它的峰值处的带宽比矩形窗要宽,可以说分辨率没有矩形窗好。

注意到汉宁窗频谱的高度只有不到1,而矩形窗的频谱则达1.5,这个没有关系,因为汉宁窗在时域压低了边缘的幅度,相当于减小了信号的能量,所以频域的峰值会降低,这是可以也需要在频域处理完反变换回来时除以汉宁窗来解除其压低能量的效果的。

 

记得学数字信号处理时,说造成频谱泄露的两个原因是窗函数有能量泄露(上面如实展示了)、周期延拓造成不连续点。对于后者,个人认为值得商榷,造成不连续点只是表象,如果说这是本质原因,那采样值总是离散值,离散值就是不连续点,总会造成频谱泄露的呀,但对整周期采样的余弦波,虽然是离散点,但没有频谱泄露(可能有,但很小),所以其真正原因是没有整周期采样,但问题又来了,实际中的信号可不是简单的余弦波、正弦波,有固定频率的,所以无法整周期采样,整谁的周期啊?所以频谱泄露只能抑制,不能消除。

以上结果的代码如下:

main.m文件

clc

clear all

close all

ts = 0.001;

% 连续函数的显示采样周期

fs = 0.01;

% 频域内的显示采样周期

T0 = 1;

% 余弦波的周期

f0 = 1/T0;

% 余弦波的频率

A = 1;

% 余弦波的振幅

Ts = 0.1;

% 时域采样周期

Fs = 1/Ts;

wT = 1.4;

% 窗的宽度

windowflag = 2;

% 1为矩形窗,其他为汉宁窗

handle.txrange = [-T0 T0]*2;

% 时域的显示范围

handle.tyrange = [-A*1.5 A*1.5];

handle.fxrange = [-f0 f0]*13;

% 频域的显示范围

handle.fyrange = [-A*0.5 A*2];

% 余弦信号

t = handle.txrange(1):ts:handle.txrange(2);

xt = A*cos(2*pi*f0*t);

index = 1;

handle.data(index).x = t;

handle.data(index).y = xt;

handle.data(index).type = 'plot';

handle.data(index).ylim = [-A A]*1.2;

handle.data(index).title = '余弦信号x(t)';

% 余弦信号的频谱

f = handle.fxrange(1):fs:handle.fxrange(2);

xf = A*(f == f0 | f == -f0);

index = 2;

handle.data(index).x = f;

handle.data(index).y = xf;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A*0.2 A*1.2];

handle.data(index).title = '余弦信号频谱x(f)';

% 采样序列(周期脉冲序列)

t = handle.txrange(1):Ts:handle.txrange(2);

pt = ones(size(t));

index = 3;

handle.data(index).x = t;

handle.data(index).y = pt;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A*0.2 A*1.2];

handle.data(index).title = '采样脉冲p(t)';

% 采样序列的频谱

sampletemp = round(handle.fxrange(1)/fs):round(handle.fxrange(2)/fs);

f = sampletemp*fs;

pf = mod(sampletemp, round(Fs/fs)) == 0;

index = 4;

handle.data(index).x = f;

handle.data(index).y = pf;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A*0.2 A*1.2];

handle.data(index).title = '采样脉冲频谱p(f)';

% 采样余弦波

t = handle.txrange(1):Ts:handle.txrange(2);

xpt = A*cos(2*pi*f0*t);

index = 5;

handle.data(index).x = t;

handle.data(index).y = xpt;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A A]*1.2;

handle.data(index).title = '采样信号x(t)×p(t)';

% 采样余弦波的频谱

f = handle.fxrange(1):fs:handle.fxrange(2);

xpf = conv(xf, double(pf), 'same');

index = 6;

handle.data(index).x = f;

handle.data(index).y = xpf;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A*0.2 A*1.2];

handle.data(index).title = '采样信号频谱x(f)*p(f)';

% 窗函数

t = handle.txrange(1):ts:handle.txrange(2);

if windowflag == 1

    wt = t>=0 & t<=wT;

else

    wt = sin(t*pi/wT).^2;

    wt(t<0 | t>wT) = 0;

end

index = 7;

handle.data(index).x = t;

handle.data(index).y = wt;

handle.data(index).type = 'plot';

handle.data(index).ylim = [-A*0.2 A*1.2];

handle.data(index).title = '窗函数w(t)';

% 窗函数的频谱

f = handle.fxrange(1):fs:handle.fxrange(2);

if windowflag == 1

    wf = sinc(wT*f)*wT;

    % 矩形窗

else

    wf = wT/2*sinc(wT*f) + wT/4*sinc(wT*f-1) + wT/4*sinc(wT*f-1);

    % 汉宁窗

end

index = 8;

handle.data(index).x = f;

handle.data(index).y = abs(wf);

handle.data(index).type = 'plot';

handle.data(index).ylim = [-A*0.2 A*wT*1.2];

handle.data(index).title = '窗函数频谱|w(f)|';

% 采样余弦信号加窗

t = 0:Ts:wT-Ts/100;

if windowflag == 1

    xpwt = A.*cos(2*pi*f0*t);

else

    xpwt = sin(t*pi/wT).^2*A.*cos(2*pi*f0*t);

end

index = 9;

handle.data(index).x = t;

handle.data(index).y = xpwt;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A A]*1.2;

handle.data(index).title = '信号加窗x(t)×p(t)×w(t)';

% 加窗后的频谱

f = handle.fxrange(1):fs:handle.fxrange(2);

xpwf = conv(xpf, wf, 'same');

index = 10;

handle.data(index).x = f;

handle.data(index).y = abs(xpwf);

handle.data(index).type = 'plot';

handle.data(index).ylim = [-A*0.2 A*wT*1.2];

handle.data(index).title = '加窗后频谱|x(f)*p(f)*w(f)|';

% 频域采样的时域信号

t = handle.txrange(1):ts:handle.txrange(2);

pft = mod(t, wT) == 0;

index = 11;

handle.data(index).x = t;

handle.data(index).y = pft;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A*0.2 A*1.2];

handle.data(index).title = '周期延拓pf(t)';

% 频域采样信号

sampletemp = round(handle.fxrange(1)/fs):round(handle.fxrange(2)/fs);

f = sampletemp*fs;

pff = mod(sampletemp, round(1/wT/fs)) == 0;

index = 12;

handle.data(index).x = f;

handle.data(index).y = pff;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A*0.2 A*1.2];

handle.data(index).title = '频域采样pf(f)';

% 加窗采样余弦信号周期延拓

t = handle.txrange(1):Ts:handle.txrange(2);

xpwpft = xpwt(round(mod(t/Ts,wT/Ts))+1);

index = 13;

handle.data(index).x = t;

handle.data(index).y = xpwpft;

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A A]*1.2;

handle.data(index).title = '周期延拓后信号[x(t)×p(t)×w(t)]*pf(t)';

% 加窗采样余弦信号频谱(频域采样)

f = handle.fxrange(1):fs:handle.fxrange(2);

xpwpff = xpwf.*pff;

index = 14;

handle.data(index).x = f;

handle.data(index).y = abs(xpwpff);

handle.data(index).type = 'stem';

handle.data(index).ylim = [-A*0.2 A*wT*1.2];

handle.data(index).title = '频域采样后频谱|[x(f)*p(f)*w(f)]×pf(f)|';

% 显示

Show(handle)

hold on

plot(handle.data(10).x, handle.data(10).y, ':r')

Show函数文件Show.m

function Show(handle)

fig1 = figure;

fig2 = figure;

for i = 1:length(handle.data)

    if i <= 6

        figure(fig1);

        subplot(3, 2, i)

    else

        figure(fig2);

        subplot(4, 2, i-6)

    end  

   

    switch handle.data(i).type

        case 'plot'

            plot(handle.data(i).x, handle.data(i).y)

        case 'stem'

            stem(handle.data(i).x, handle.data(i).y, 'Marker', 'none')

    end

   

    if mod(i, 2) == 1

        xlim(handle.txrange)

    else

        xlim(handle.fxrange)       

    end

    ylim(handle.data(i).ylim)

    title(handle.data(i).title)

end

end

### 关于汉宁窗及其在信号处理中的应用 #### 什么是汉宁窗汉宁窗(Hanning Window),也被称为升余弦窗,是一种常见的窗口函数,在信号处理领域被广泛应用于频谱分析滤波设计。它通过平滑信号的边缘来减少频谱泄漏效应,从而提高频率估计的准确性[^2]。 #### 汉宁窗的数学表达式 汉宁窗可以通过以下公式定义: \[ w(n) = 0.5 \left( 1 - \cos\left(\frac{2\pi n}{N-1}\right)\right), \quad 0 \leq n \leq N-1 \] 其中 \( N \) 是窗口长度,\( n \) 表示采样点索引。 --- ### 使用 MATLAB 实现汉宁窗 以下是利用 MATLAB 创建并绘制汉宁窗的一个简单例子: ```matlab % 定义参数 windowLength = 64; % 窗口长度 % 计算汉宁窗 hannWindow = hann(windowLength, 'periodic'); % 绘制结果 figure; plot(hannWindow); title('Hanning Window'); xlabel('Sample Index'); ylabel('Amplitude'); grid on; ``` 上述代码展示了如何创建一个周期性的汉宁窗,并将其可视化。`hann()` 函数是 MATLAB 中内置的功能之一,专门用于生成汉宁窗[^1]。 --- ### 使用 Python 实现汉宁窗 如果希望在 Python 中实现类似的汉宁窗功能,则可以借助 `numpy` 库完成此操作: ```python import numpy as np import matplotlib.pyplot as plt # 定义参数 window_length = 64 # 窗口长度 # 计算汉宁窗 hann_window = np.hanning(window_length) # 绘制结果 plt.figure() plt.plot(hann_window) plt.title("Hanning Window") plt.xlabel("Sample Index") plt.ylabel("Amplitude") plt.grid(True) plt.show() ``` 这段代码同样实现了汉宁窗的计算与绘图过程。`np.hanning()` 方法提供了便捷的方式生成指定长度的汉宁窗序列[^3]。 --- ### 汉宁窗的应用场景 1. **频谱分析** 在对时间域信号进行傅里叶变换之前施加汉宁窗,能够有效降低因截断引起的频谱泄露现象,提升频谱分辨率。 2. **滤波器设计** 结合 FIR 或 IIR 滤波器的设计流程,汉宁窗可用于调整滤波器系数分布特性,优化通带纹波平坦度性能。 3. **雷达信号处理** 如 LFMCW 雷达系统中,采用汉宁窗作为匹配滤波的一部分,有助于改善目标检测精度以及距离分辨能力[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值