You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:27:24