如何验证Core Audio中音频幅值的正确性?附代码相关疑问
解答你的音频幅值验证与绘图问题
1. 为什么magnitudeAtBand数值极小?这正常吗?
这完全是正常的,核心原因有两点:
- 首先,你录制的原始音频信号本身音量极低:从输出的
data数组来看,数值都在±0.0001量级,说明当前环境安静或麦克风增益设置较低。而Float格式的PCM音频范围是**[-1.0, 1.0]**,1.0对应最大音量,弱输入信号自然会导致FFT后的幅值偏小。 - 其次,
TempiFFT返回的是线性幅值,这种刻度对弱信号的差异展示不直观。如果想更清晰地观察频段间的强弱对比,建议启用你注释掉的dB转换:
dB是对数刻度,会放大小信号的差异,结果通常为负数(因为小于1的数值取对数为负),但更符合人耳对声音的感知,也更适合绘图展示。let magnitudeDB = TempiFFT.toDB(fft.magnitudeAtBand(i))
2. 如何绘制振幅图?
你可以绘制两种常见的振幅图,分别对应时域和频域:
时域波形图(原始音频振幅)
- 数据来源:直接使用
data数组的Float值,每个元素对应一个采样点的瞬时振幅。 - 绘图逻辑:
- X轴:可以是采样点序号,或转换为时间(采样点序号 ÷ 采样率,比如44100Hz下,2048个采样点对应约0.046秒)。
- Y轴:振幅值,范围固定为[-1.0, 1.0]。
- 实现方式:用SwiftUI的
Path手动绘制折线,或者用第三方库如Charts的LineChartView,将data转为ChartDataEntry后传入即可。
频域振幅图(FFT频段幅值)
- 数据来源:使用
magnitudeArr(线性幅值)或magnitudeDBArr(dB幅值)。 - 绘图逻辑:
- X轴:每个频段对应的频率范围。你的代码分了20个频段,采样率44100Hz,奈奎斯特频率为22050Hz,因此每个频段宽度为
22050 / 20 = 1102.5Hz,第i个频段的覆盖范围是i*1102.5Hz到(i+1)*1102.5Hz。 - Y轴:线性幅值(0到当前最大幅值)或dB幅值(通常-60dB到0dB,0dB对应最大输入信号)。
- 实现方式:用
Charts的BarChartView(柱状图)或LineChartView(折线图),把每个频段的幅值和对应频率转为ChartDataEntry即可。
- X轴:每个频段对应的频率范围。你的代码分了20个频段,采样率44100Hz,奈奎斯特频率为22050Hz,因此每个频段宽度为
3. 为什么data中存在负数?
这是线性PCM音频的标准特性,完全正常:
Float格式的PCM数据用正负值表示声波的振动状态:正数对应空气被压缩的状态,负数对应空气被稀疏的状态,0代表静止。比如标准的正弦波音频信号,就是在[-1.0, 1.0]之间周期性正负波动的,所以你的data里出现负数是正确的信号表现。
额外验证建议
如果想确认数据是否准确,可以做个简单测试:
- 播放一个已知的测试信号(比如1kHz的正弦波,音量适中),同时用你的代码录制。
- 查看
data数组,应该能看到明显的周期性正负波动,数值范围大概在±0.5左右(取决于音量)。 - 查看FFT结果,第一个频段(0-1102.5Hz)的幅值会明显高于其他频段,以此验证你的FFT逻辑是正确的。
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

