如何修复Arduino FFT库返回错误频率 用于吉他调音器开发
问题根因
你现在恒定输出60Hz的核心原因是市电工频干扰盖过了实际采集的音频信号,同时你的代码参数和采集逻辑也存在明显问题,按以下步骤修改即可解决:
1. 硬件干扰修复
- 先确认麦克风模块偏置电压正常:无声音时A0引脚的ADC读数应当为满量程的1/2左右,5V供电的Arduino读数稳定在512上下、3.3V供电的稳定在2048上下,偏差过大直接更换模块
- 60Hz是欧美标准市电工频干扰,当前模块20dB增益太低,导致有用声音信号幅值远低于干扰信号:更换增益可调的麦克风模块,把增益调到40~60dB区间(不要开太高避免信号削波);或者直接用电池给Arduino和麦克风模块供电,不要插USB连接电脑/用市电适配器,切断工频干扰的耦合路径
- 给A0引脚对地接一个100nF陶瓷电容滤除杂波,麦克风信号线尽量短,优先用带屏蔽层的线材
2. 代码参数和逻辑修正
你当前的参数完全不匹配吉他调音场景:
- 吉他空弦音范围是82Hz(6弦E)~329Hz(1弦E),你现在用128点FFT+2048Hz采样率的频率分辨率只有16Hz,误差大到完全没法调音,至少要把采样点提升到1024、采样频率提升到4096Hz,分辨率达到4Hz才能满足基本需求,要更精准可以用2048点采样,分辨率可达2Hz
- arduinoFFT的
MajorPeak函数默认不会跳过直流分量,需要手动把低频干扰区间的幅值置0,避免工频/直流干扰被识别为主峰值 - 采样时需要关闭Arduino内置定时器中断,避免中断打断采样流程导致采样间隔不准,FFT计算结果失真
3. 修改后的参考代码
#define SAMPLES 1024 #define SAMPLING_FREQUENCY 4096 arduinoFFT FFT = arduinoFFT(); unsigned int samplingPeriod; unsigned long microSeconds; double vReal[SAMPLES]; double vImag[SAMPLES]; void setup() { Serial.begin(115200); samplingPeriod = round(1000000.0 / SAMPLING_FREQUENCY); } void loop() { noInterrupts(); for(int i=0; i<SAMPLES; i++) { microSeconds = micros(); vReal[i] = analogRead(A0); vImag[i] = 0; while(micros() < (microSeconds + samplingPeriod)) { // 等待采样间隔 } } interrupts(); FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); // 滤除72Hz以下所有信号,直接干掉60Hz工频干扰,不影响82Hz以上的吉他有效信号 for(int i=0; i<18; i++) { vReal[i] = 0; } double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY); Serial.println(peak); delay(100); }
内容的提问来源于stack exchange,提问作者Micnasr
相关产品推荐
相关产品推荐

