Android频谱分析仪手动绘图时频率值偏差问题求助
嘿,我看你在做Android频谱分析仪的时候遇到了频率刻度不准的问题——低频数值还行,高频误差随频率升高越来越大,1000Hz显示1250Hz、3000Hz显示3750Hz,这固定的1.25倍误差,大概率是频率计算逻辑和坐标缩放顺序出了问题,咱们一步步来修正:
1. 先揪出核心错误:频率值计算公式错了
FFT的每个点对应的实际频率,核心公式是:
double actualFreq = i * (sampleRate / (double) FFT点数);
其中FFT点数就是你代码里的pow2,而且有效频率点只到FFT点数/2(对应Nyquist频率,也就是采样率的一半)。
你现在的代码里用了sampleRate/(pow2>>1),也就是把分母换成了FFT点数/2,这直接让计算出的频率放大了2倍!再结合可能的缩放逻辑叠加,就出现了1.25倍的误差。
2. 修正坐标计算的顺序
你现在是先缩放频率步长再乘以i,这很容易出错。正确的做法是先算出实际频率,再把频率转换成屏幕坐标,调整后的代码如下:
int length = currentWaveDataDouble.length; int pow2 = Integer.highestOneBit(length) << 1; int sampleRate = 44100; // 提前计算频率步长,减少循环内计算量 double freqStep = sampleRate / (double) pow2; // 实际绘制部分 for(int i = 0; i < p2.length; i++) { // 第一步:计算当前点的实际频率 double actualFreq = i * freqStep; // 超过最大显示频率直接跳出,不用继续绘制 if (actualFreq >= maxFreqPlus1) { break; } // 第二步:把频率转换成屏幕x坐标,再加上轴偏移 float xVal = (float) scaleX.ScaleValue(actualFreq); xVal += axisWidth + yAxisMargin; // y轴计算和绘制逻辑不变 float yVal = (float) scaleY.ScaleValue(p2[i]); yVal += axisWidth + xAxisMargin; canvas.drawPoint(xVal, yVal, marker); if(yVal > yMax) { yMax = yVal; xMax = xVal; } }
3. 检查FFT点数pow2的计算逻辑
你代码里pow2 = Integer.highestOneBit(length) << 1;是取大于length的最小2的幂,但要确认:
- 你实际执行FFT时,是不是用了
pow2长度的数据?如果只是用了原length长度的数据做FFT,那pow2就不是真正的FFT点数,分母就错了。 - 如果需要补零到2的幂长度,那
pow2必须是补零后的实际长度,否则频率计算的步长肯定不对。
4. 额外优化提升绘图速度
- 循环到
i < pow2/2就可以停止,超过Nyquist频率的点是镜像数据,完全没必要绘制,能减少一半的绘制量。 - 提前计算
freqStep,避免在循环里重复做除法运算,进一步提升效率。
内容的提问来源于stack exchange,提问作者Ross F
相关产品推荐
相关产品推荐

