news 2026/3/11 13:03:45

汉宁窗与汉明窗:原理、公式与代码实现剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
汉宁窗与汉明窗:原理、公式与代码实现剖析

汉宁窗与汉明窗:原理、公式与代码实现剖析

一、为什么需要窗函数?——频谱泄漏的深度解析

1. 频谱泄漏的原理

想象你在听一首歌,但只截取了其中的一小段,然后想用FFT分析它的频率。问题来了:你截断的这段音乐在时域上是突然开始和结束的,这相当于在时域上乘以一个矩形窗。

频谱泄漏的数学原理

  • 假设原始信号为x(t)=Acos⁡(2πf0t)x(t) = A\cos(2\pi f_0 t)x(t)=Acos(2πf0t)
  • 时域截断后:x′(t)=x(t)⋅rect(t/T)x'(t) = x(t) \cdot \text{rect}(t/T)x(t)=x(t)rect(t/T)
  • 在频域:X′(f)=X(f)∗rect(f)=X(f)∗sinc(fT)X'(f) = X(f) * \text{rect}(f) = X(f) * \text{sinc}(fT)X(f)=X(f)rect(f)=X(f)sinc(fT)
  • 矩形窗的频谱是sinc函数,有主瓣和旁瓣,导致原信号的频谱被"扩散"

频谱泄漏示意图

原信号频谱: |-----| (理想正弦波) | | 矩形窗频谱: |-----|-----|-----|... (sinc函数) | | | | 卷积后频谱: |-----|-----|-----|... (频谱泄漏) | | | |

2. 窗函数的解决方案

窗函数通过在信号两端逐渐减小振幅,使信号"平滑地消失",从而减少频谱泄漏。

  • 理想窗函数:主瓣窄(频率分辨率高),旁瓣低(泄漏小)
  • 实际权衡:没有完美窗函数,需要在主瓣宽度和旁瓣高度之间权衡

二、汉宁窗(Hanning Window)的详细剖析

1. 数学原理与公式

汉宁窗的定义
w(n)=0.5⋅[1−cos⁡(2πnN−1)],0≤n≤N−1w(n) = 0.5 \cdot \left[1 - \cos\left(\frac{2\pi n}{N-1}\right)\right], \quad 0 \leq n \leq N-1w(n)=0.5[1cos(N12πn)],0nN1

推导过程
汉宁窗是升余弦窗的一个特例,可以看作是3个矩形时间窗的频谱之和:
w(n)=13rect(nN)∗rect(nN)∗rect(nN)w(n) = \frac{1}{3} \text{rect}\left(\frac{n}{N}\right) * \text{rect}\left(\frac{n}{N}\right) * \text{rect}\left(\frac{n}{N}\right)w(n)=31rect(Nn)rect(Nn)rect(Nn)
或者说是3个sinc(t)型函数之和,而括号中的两项相对于第一个谱窗向左、右各移动了π/T,从而使旁瓣互相抵消。

2. 时域特性

  • 时域形状:两端触零的平滑钟形曲线
  • 端点值w(0)=w(N−1)=0w(0) = w(N-1) = 0w(0)=w(N1)=0
  • 中心点w((N−1)/2)=1w((N-1)/2) = 1w((N1)/2)=1
  • 对称性:关于中心对称

3. 频域特性

特性数值说明
主瓣宽度1.2π/N比矩形窗宽约2.5倍
第一旁瓣-31dB旁瓣最高点的幅度
旁瓣衰减速度-60dB/10oct每十倍频程衰减60dB
旁瓣最大值-31dB与主瓣的相对幅度

4. 代码实现

Python实现
importnumpyasnpimportmatplotlib.pyplotaspltdefhanning_window(N):"""生成汉宁窗"""n=np.arange(N)window=0.5*(1-np.cos(2*np.pi*n/(N-1)))returnwindow# 生成长度为64的汉宁窗N=64hanning=hanning_window(N)# 绘制时域波形plt.figure(figsize=(10,6))plt.plot(hanning,'b-',linewidth=2)plt.title('Hanning Window (N=64)')plt.xlabel('Sample Index')plt.ylabel('Amplitude')plt.grid(True)plt.show()# 计算频谱hanning_fft=np.fft.fft(hanning,1024)hanning_fft=np.fft.fftshift(hanning_fft)freq=np.fft.fftfreq(1024,1.0/N)freq=np.fft.fftshift(freq)# 绘制频谱plt.figure(figsize=(10,6))plt.plot(freq,20*np.log10(np.abs(hanning_fft)),'r-')plt.title('Frequency Response of Hanning Window')plt.xlabel('Frequency (Normalized)')plt.ylabel('Magnitude (dB)')plt.grid(True)plt.show()
Matlab实现
% 生成汉宁窗N=64;n=0:N-1;hanning=0.5*(1-cos(2*pi*n/(N-1)));% 绘制时域波形figure;plot(hanning,'b-','LineWidth',2);title(['Hanning Window (N=',num2str(N),')']);xlabel('Sample Index');ylabel('Amplitude');grid on;% 计算频谱hanning_fft=fft(hanning,1024);hanning_fft=fftshift(hanning_fft);freq=(0:1023)/1024-0.5;freq=freq*(2*pi);% Normalize frequency% 绘制频谱figure;plot(freq,20*log10(abs(hanning_fft)),'r-','LineWidth',2);title('Frequency Response of Hanning Window');xlabel('Frequency (Normalized)');ylabel('Magnitude (dB)');grid on;
C++实现
#include<iostream>#include<vector>#include<cmath>#include<fstream>std::vector<double>hanningWindow(intN){std::vector<double>window(N);for(intn=0;n<N;++n){window[n]=0.5*(1-cos(2*M_PI*n/(N-1)));}returnwindow;}voidsaveWindowToFile(conststd::vector<double>&window,conststd::string&filename){std::ofstreamfile(filename);for(doubleval:window){file<<val<<"\n";}file.close();}intmain(){intN=64;std::vector<double>window=hanningWindow(N);saveWindowToFile(window,"hanning_window.txt");std::cout<<"Hanning window of length "<<N<<" generated and saved to hanning_window.txt"<<std::endl;return0;}

三、汉明窗(Hamming Window)的详细剖析

1. 数学原理与公式

汉明窗的定义
w(n)=0.54−0.46⋅cos⁡(2πnN−1),0≤n≤N−1w(n) = 0.54 - 0.46 \cdot \cos\left(\frac{2\pi n}{N-1}\right), \quad 0 \leq n \leq N-1w(n)=0.540.46cos(N12πn),0nN1

为什么是0.54和0.46?

  • 这些系数是通过优化得到的,使得窗函数的频谱中第一个旁瓣的幅度达到最小。
  • 通过微调系数,可以使得第一旁瓣的幅度从-31dB降低到-42dB。

2. 时域特性

  • 时域形状:两端不触零的平顶钟形曲线
  • 端点值w(0)=w(N−1)=0.54w(0) = w(N-1) = 0.54w(0)=w(N1)=0.54
  • 中心点w((N−1)/2)=1w((N-1)/2) = 1w((N1)/2)=1
  • 对称性:关于中心对称

3. 频域特性

特性数值说明
主瓣宽度1.3π/N比汉宁窗略宽
第一旁瓣-42dB旁瓣最高点的幅度
旁瓣衰减速度-20dB/10oct比汉宁窗慢
旁瓣最大值-42dB与主瓣的相对幅度

4. 代码实现

Python实现
importnumpyasnpimportmatplotlib.pyplotaspltdefhamming_window(N):"""生成汉明窗"""n=np.arange(N)window=0.54-0.46*np.cos(2*np.pi*n/(N-1))returnwindow# 生成长度为64的汉明窗N=64hamming=hamming_window(N)# 绘制时域波形plt.figure(figsize=(10,6))plt.plot(hamming,'b-',linewidth=2)plt.title('Hamming Window (N=64)')plt.xlabel('Sample Index')plt.ylabel('Amplitude')plt.grid(True)plt.show()# 计算频谱hamming_fft=np.fft.fft(hamming,1024)hamming_fft=np.fft.fftshift(hamming_fft)freq=np.fft.fftfreq(1024,1.0/N)freq=np.fft.fftshift(freq)# 绘制频谱plt.figure(figsize=(10,6))plt.plot(freq,20*np.log10(np.abs(hamming_fft)),'r-')plt.title('Frequency Response of Hamming Window')plt.xlabel('Frequency (Normalized)')plt.ylabel('Magnitude (dB)')plt.grid(True)plt.show()
Matlab实现
% 生成汉明窗N=64;n=0:N-1;hamming=0.54-0.46*cos(2*pi*n/(N-1));% 绘制时域波形figure;plot(hamming,'b-','LineWidth',2);title(['Hamming Window (N=',num2str(N),')']);xlabel('Sample Index');ylabel('Amplitude');grid on;% 计算频谱hamming_fft=fft(hamming,1024);hamming_fft=fftshift(hamming_fft);freq=(0:1023)/1024-0.5;freq=freq*(2*pi);% Normalize frequency% 绘制频谱figure;plot(freq,20*log10(abs(hamming_fft)),'r-','LineWidth',2);title('Frequency Response of Hamming Window');xlabel('Frequency (Normalized)');ylabel('Magnitude (dB)');grid on;
C++实现
#include<iostream>#include<vector>#include<cmath>#include<fstream>std::vector<double>hammingWindow(intN){std::vector<double>window(N);for(intn=0;n<N;++n){window[n]=0.54-0.46*cos(2*M_PI*n/(N-1));}returnwindow;}voidsaveWindowToFile(conststd::vector<double>&window,conststd::string&filename){std::ofstreamfile(filename);for(doubleval:window){file<<val<<"\n";}file.close();}intmain(){intN=64;std::vector<double>window=hammingWindow(N);saveWindowToFile(window,"hamming_window.txt");std::cout<<"Hamming window of length "<<N<<" generated and saved to hamming_window.txt"<<std::endl;return0;}

四、汉宁窗 vs 汉明窗:深度对比

1. 数学公式对比

窗函数公式系数
汉宁窗w(n)=0.5⋅[1−cos⁡(2πn/(N−1))]w(n) = 0.5 \cdot [1 - \cos(2\pi n/(N-1))]w(n)=0.5[1cos(2πn/(N1))]0.5, 0.5
汉明窗w(n)=0.54−0.46⋅cos⁡(2πn/(N−1))w(n) = 0.54 - 0.46 \cdot \cos(2\pi n/(N-1))w(n)=0.540.46cos(2πn/(N1))0.54, 0.46

2. 时域特性对比

特性汉宁窗汉明窗
端点值00.54
中心值11
两端形状触零不触零
时域形状钟形曲线平顶钟形

3. 频域特性对比

特性汉宁窗汉明窗
第一旁瓣-31dB-42dB
旁瓣衰减速度-60dB/10oct-20dB/10oct
主瓣宽度1.2π/N1.3π/N
适用场景通用场景语音信号处理

4. 代码实现对比

# 汉宁窗实现defhanning_window(N):return0.5*(1-np.cos(2*np.pi*np.arange(N)/(N-1)))# 汉明窗实现defhamming_window(N):return0.54-0.46*np.cos(2*np.pi*np.arange(N)/(N-1))

五、窗函数在信号处理中的实际应用

1. 信号处理流程

  1. 选择窗函数:根据需求选择汉宁窗、汉明窗等
  2. 生成窗函数:使用公式生成窗函数序列
  3. 应用窗函数:将窗函数与信号进行逐点乘法
  4. 执行FFT:对加窗后的信号进行快速傅里叶变换
  5. 分析频谱:根据频谱结果进行信号分析

2. 实际应用示例(Python)

importnumpyasnpimportmatplotlib.pyplotaspltfromscipyimportsignal# 生成一个正弦信号fs=1000# 采样频率t=np.linspace(0,1,fs,endpoint=False)# 1秒信号f=50# 信号频率signal=np.sin(2*np.pi*f*t)# 生成汉宁窗N=1024hanning=signal.windows.hann(N)# 应用汉宁窗windowed_signal=signal*hanning# 执行FFTfft_result=np.fft.fft(windowed_signal,N)freq=np.fft.fftfreq(N,1/fs)# 绘制原始信号和加窗后的信号plt.figure(figsize=(12,8))plt.subplot(2,1,1)plt.plot(t[:100],signal[:100],'b-',linewidth=1.5)plt.title('Original Signal (50Hz Sinusoid)')plt.xlabel('Time (s)')plt.ylabel('Amplitude')plt.grid(True)plt.subplot(2,1,2)plt.plot(t[:100],windowed_signal[:100],'r-',linewidth=1.5)plt.title('Windowed Signal (Hanning Window)')plt.xlabel('Time (s)')plt.ylabel('Amplitude')plt.grid(True)plt.tight_layout()plt.show()# 绘制频谱plt.figure(figsize=(10,6))plt.plot(freq[:N//2],20*np.log10(np.abs(fft_result[:N//2])),'g-')plt.title('Spectrum of Windowed Signal (Hanning Window)')plt.xlabel('Frequency (Hz)')plt.ylabel('Magnitude (dB)')plt.grid(True)plt.show()

3. 窗函数在OpenCV中的实现(2D汉宁窗)

根据知识库[1],OpenCV实现的2D汉宁窗:

voidcv::createHanningWindow(OutputArray _dst,cv::Size winSize,inttype){CV_INSTRUMENT_REGION();CV_Assert(type==CV_32FC1||type==CV_64FC1);CV_Assert(winSize.width>1&&winSize.height>1);_dst.create(winSize,type);Mat dst=_dst.getMat();introws=dst.rows,cols=dst.cols;AutoBuffer<double>_wc(cols);double*constwc=_wc.data();doublecoeff0=2.0*CV_PI/(double)(cols-1),coeff1=2.0*CV_PI/(double)(rows-1);for(intj=0;j<cols;j++)wc[j]=0.5*(1.0-cos(coeff0*j));if(dst.depth()==CV_32F){for(inti=0;i<rows;i++){float*dstData=dst.ptr<float>(i);doublewr=0.5*(1.0-cos(coeff1*i));for(intj=0;j<cols;j++)dstData[j]=(float)(wr*wc[j]);}}else{for(inti=0;i<rows;i++){double*dstData=dst.ptr<double>(i);doublewr=0.5*(1.0-cos(coeff1*i));for(intj=0;j<cols;j++)dstData[j]=wr*wc[j];}}// perform batch sqrt for SSE performance gainscv::sqrt(dst,dst);}

六、如何选择汉宁窗还是汉明窗?

1. 选择指南

场景推荐窗函数原因
通用信号处理汉宁窗平衡点,适用于大多数情况
语音信号处理汉明窗第一旁瓣更低(-42dB vs -31dB),更适合关注主瓣附近信号
需要极低旁瓣汉明窗第一旁瓣抑制更好
需要快速旁瓣衰减汉宁窗旁瓣衰减更快(-60dB/10oct vs -20dB/10oct)
计算资源有限汉明窗在FPGA实现中可节省20%-51%的资源

2. 选择技巧

  1. 不知道选哪种:汉宁窗是"万金油",适用于大多数情况。
  2. 语音信号处理:汉明窗更常用。
  3. 需要精确测量幅度:考虑使用平顶窗。
  4. 需要极高旁瓣抑制:考虑使用布莱克曼窗。

七、窗函数家族的其他成员

窗函数公式特点
矩形窗w(n)=1w(n) = 1w(n)=1主瓣最窄,旁瓣最高(-13dB)
汉宁窗0.5[1−cos⁡(2πn/(N−1))]0.5[1-\cos(2\pi n/(N-1))]0.5[1cos(2πn/(N1))]通用,平衡点
汉明窗0.54−0.46cos⁡(2πn/(N−1))0.54-0.46\cos(2\pi n/(N-1))0.540.46cos(2πn/(N1))第一旁瓣更低
布莱克曼窗0.42−0.5cos⁡(2πn/(N−1))+0.08cos⁡(4πn/(N−1))0.42-0.5\cos(2\pi n/(N-1))+0.08\cos(4\pi n/(N-1))0.420.5cos(2πn/(N1))+0.08cos(4πn/(N1))旁瓣更低,主瓣更宽
平顶窗多项式形式幅度测量精度高

八、总结

汉宁窗是"通用选手",适合大多数情况;汉明窗是"优化选手",特别适合关注主瓣附近信号的场景。

选择汉宁窗还是汉明窗,取决于你更看重"旁瓣衰减速度"还是"第一旁瓣的抑制效果"。

汉宁窗:通用性强,旁瓣衰减快,是信号处理中的"万金油"。
汉明窗:第一旁瓣更低(-42dB vs 汉宁窗的-31dB),特别适合语音信号处理等需要关注主瓣附近信号的场景。

在实际应用中,你可以通过比较频谱泄漏情况来确定哪种窗函数更适合你的具体需求。记住,没有完美的窗函数,只有最适合你应用场景的窗函数。

希望这个超详细的剖析能帮助你深入理解汉宁窗和汉明窗!如果你在实际应用中遇到具体问题,欢迎继续讨论~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/10 12:33:55

研发费用加计扣除、高新技术企业中的归集范围有哪些?

在实际应用中&#xff0c;大家对研发费用的理解多存在于科研经费或者政府创新激励政策中&#xff0c;本期就来谈一谈研发费用的定义与归集范围。01-研发活动的定义研发费用就是研究与开发某项目所支付的费用。根据定义&#xff0c;研发费用是个集合概念&#xff0c;并不是单指某…

作者头像 李华
网站建设 2026/3/10 12:33:42

Nintendo Switch 文件解析终极指南:NSTool 完整使用教程

Nintendo Switch 文件解析终极指南&#xff1a;NSTool 完整使用教程 【免费下载链接】nstool General purpose read/extract tool for Nintendo Switch file formats. 项目地址: https://gitcode.com/gh_mirrors/ns/nstool Nintendo Switch 文件解析工具 NSTool 是一款专…

作者头像 李华
网站建设 2026/3/10 21:57:26

新榜智汇 GEO 搜索优化软件:全域品牌追踪,GEO 策略精准提效

现在做企业推广&#xff0c;没人能忽略AI生成引擎的影响力了吧&#xff1f;用户越来越习惯用各类AI工具找答案、做决策。这时候&#xff0c;你的品牌能不能在AI生成结果里被精准找到&#xff0c;口碑好不好&#xff0c;直接影响客户转化。但想做好这块的优化&#xff0c;真没那…

作者头像 李华
网站建设 2026/3/7 6:36:24

29、深入理解内存管理与动态内存分配

深入理解内存管理与动态内存分配 1. 内存页与地址空间 在计算机系统中,内存以页为单位进行管理。对于32位系统,页大小通常为4KB;对于64位系统,页大小通常为8KB。页分为有效页和无效页,有效页与物理内存中的页或二级存储(如交换分区或磁盘文件)相关联,而无效页则未与任…

作者头像 李华
网站建设 2026/3/9 5:54:18

AI语音也能传情达意?EmotiVoice带你进入情感合成世界

AI语音也能传情达意&#xff1f;EmotiVoice带你进入情感合成世界 在虚拟偶像直播中&#xff0c;一句“你真的好棒&#xff01;”如果用平淡的语调念出&#xff0c;观众可能毫无波澜&#xff1b;但若语气上扬、节奏轻快&#xff0c;瞬间就能点燃弹幕的热情。这种细微的情绪差异&…

作者头像 李华
网站建设 2026/3/11 10:26:13

为什么这款本地语音转文字工具是隐私敏感用户的终极选择?

在数字化时代&#xff0c;你的每一段语音都可能成为数据泄露的牺牲品。想象一下&#xff1a;商业会议录音被第三方存储&#xff0c;客户通话内容被用于AI模型训练&#xff0c;个人对话在网络传输中被截获...这些不是危言耸听&#xff0c;而是使用在线语音转文字工具的真实风险。…

作者头像 李华