FFT与窗函数执行顺序咨询——压电传感器吉他电压采集项目
问题解答
核心结论
必须先对采集到的时域电压信号应用窗函数,再执行FFT,绝对不能反过来操作。
原因解释
FFT的数学前提是输入信号是严格周期性的,但你采集的吉他发声信号是瞬态的(拨弦后声音逐渐衰减),而且采集的信号片段不可能刚好是完整周期的整数倍。直接对这类信号做FFT会产生频谱泄漏——原本集中在单一频率的能量会扩散到相邻频率上,导致噪声干扰、频谱精度下降。
窗函数的作用就是通过平滑信号的首尾边缘,让截断后的信号更接近周期性,从而大幅减少频谱泄漏。如果先做FFT再加窗,相当于对频域信号做滤波,完全起不到抑制泄漏的作用,反而会破坏真实的频谱信息。
Python实现示例
针对你的吉他信号采集场景,推荐使用汉宁窗(Hanning Window)或布莱克曼窗(Blackman Window),这两种窗在抑制频谱泄漏和保留频率精度之间的平衡较好。以下是基础实现步骤:
- 导入必要库
import numpy as np
- 读取采集到的电压数据(替换成你从压电传感器获取的实际数据)
# 假设采样率为44100Hz(音频常用采样率),采集固定长度的信号 sample_rate = 44100 num_samples = 1024 # 取2的整数次方,FFT计算更快 # 实际项目中替换为从传感器读取数据的代码,比如: # raw_signal = pi_adc.read_samples(num_samples) raw_signal = np.random.normal(0, 0.5, num_samples) # 模拟传感器数据+噪声
- 应用窗函数并执行FFT
# 生成汉宁窗 window = np.hanning(num_samples) # 对原始信号加窗 windowed_signal = raw_signal * window # 执行FFT并处理结果 fft_result = np.fft.fft(windowed_signal) # 计算频率轴 freq_axis = np.fft.fftfreq(num_samples, 1/sample_rate) # 提取正频率部分的幅度值(转换为相对幅度) positive_mask = freq_axis >= 0 fft_magnitude = np.abs(fft_result[positive_mask]) / num_samples positive_freqs = freq_axis[positive_mask]
- 适配LCD显示的简化处理
# 截取吉他核心频段(比如0-1000Hz) target_mask = positive_freqs <= 1000 display_freqs = positive_freqs[target_mask] display_mag = fft_magnitude[target_mask] # 将幅度值映射到LCD的像素高度范围(比如0-60) max_mag = np.max(display_mag) if np.max(display_mag) != 0 else 1 display_mapped = (display_mag / max_mag) * 60 # 后续即可将display_mapped的数据输出到LCD显示频谱柱状图
额外建议
- 采样率建议设置为44100Hz或48000Hz,这是音频领域的标准采样率,能完整捕捉吉他的所有频率成分。
- 如果LCD屏幕尺寸有限,可以对FFT结果做降采样,只保留关键频率点的幅度值,避免显示拥挤。
内容的提问来源于stack exchange,提问作者Roger Fed
相关产品推荐
相关产品推荐

