首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ADC 位数在频谱分析中对高频的影响是巨大的(Σ-Δ 上大分)

ADC 位数在频谱分析中对高频的影响是巨大的(Σ-Δ 上大分)

作者头像
云深无际
发布2026-01-07 14:44:30
发布2026-01-07 14:44:30
1040
举报
文章被收录于专栏:云深之无迹云深之无迹

昨天的文章,有个读者问了一个有趣的问题:

如何设计一个基于软件的频谱分析仪(以ADALM2000为例建模)

其实这个问题极好,我是有一篇这样的稿子的,还没有发
其实这个问题极好,我是有一篇这样的稿子的,还没有发

其实这个问题极好,我是有一篇这样的稿子的,还没有发

在具体的看问题前,可以先看几个 ADC 数据手册里面的图。

看一个 AD7768-1 的 FFT 图
看一个 AD7768-1 的 FFT 图

看一个 AD7768-1 的 FFT 图

其实也是有尖峰的,但是不太明显:

我的仿真图里面其实是类似的样子
我的仿真图里面其实是类似的样子

我的仿真图里面其实是类似的样子

开始研究

其实这个图是来自于我的写的仿真代码,那这个问题一定在代码里面,我们来慢慢分析。

模拟信号包含了一个 白噪声 成分,噪声密度设定为 50 nV/√Hz,这在高频部分可能导致较强的噪声波动。频谱中的尖峰很可能是由噪声引起的,特别是在高频区域,噪声的能量可能不容易消除;在频谱分析中,噪声密度(以 dBV/√Hz 表示)和噪声底线的平滑程度紧密相关。如果噪声的分布比较宽广,或者没有做足够的平滑,可能会导致频谱中出现尖峰。

代码语言:javascript
复制
# 设定输入噪声密度 50 nV/√Hz(随便举例)
e_n = 50e-9

在代码中使用了 Hann窗,这是常用的窗函数之一,主要用于减少频谱泄漏。虽然Hann窗能够有效减少大部分的泄漏,但如果信号中包含强烈的高频成分,或者噪声较大,窗函数的效果仍然可能不足以完全平滑频谱,尤其是在高频部分。

代码语言:javascript
复制
# 4. 窗函数:Hann
window = np.hanning(N)

相干增益(CG)等效噪声带宽(ENBW) 是影响频谱表现的重要因素;窗函数可能会在高频区域引入一些额外的峰值,尤其是噪声对频谱的影响很大时。

FFT 分辨率与采样率

代码语言:javascript
复制
fs = 100_000.0      # 采样率 100 kS/s
N = 16384           # FFT 点数

代码设定的采样率 fs = 100 kS/s 和 FFT 点数 N = 16384 决定了频谱的分辨率;较高的FFT点数通常能提供更好的频率分辨率,但如果噪声不均匀地分布在频谱上,仍然可能出现尖峰。

量化误差

代码语言:javascript
复制
B = 12              # 12 bit ADC

使用了 12-bit ADC 来量化信号,虽然量化误差通常不容易在低频区域看出,但如果信号中有较强的噪声或频率成分,量化误差也可能在高频部分表现为尖峰。

一条条的研究

噪声的影响

噪声会导致高频部分的尖峰,尤其是白噪声密度较高时;那我们可以通过减少噪声的强度,或者去除噪声,来观察高频尖峰的变化。

修改代码:
代码语言:javascript
复制
# 将噪声强度降低或者直接去除噪声
e_n = 10e-9  # 降低噪声密度
# 或者直接去掉噪声
# noise = np.zeros(N)
# x_analog += noise

观察频谱图的高频部分是否变得更加平滑。

窗函数的选择

选择窗函数(如Hann窗)可能会影响高频部分,特别是窗函数的相干增益和等效噪声带宽(ENBW)设置;那就尝试使用不同的窗函数(如Hamming窗、Blackman窗等),并观察它们对频谱图高频部分的影响。

修改代码:
代码语言:javascript
复制
# 尝试其他窗函数,比如 Hamming 或 Blackman
window = np.hamming(N)  # Hamming窗
# 或者使用Blackman窗
# window = np.blackman(N)

观察高频部分的尖峰是否消失或者变小。(明显是尖峰更明显了)

FFT分辨率与采样率

频谱分辨率不足可能会导致高频部分无法清晰显示,或者出现误差;那就通过增大 N(FFT点数)或调整 fs(采样率)来提升频率分辨率,并观察高频部分的变化。

修改代码:
代码语言:javascript
复制
# 增加 FFT 点数 N 或者提高采样率 fs
fs = 200_000.0  # 提高采样率
N = 32768  # 增加 FFT 点数

验证效果:观察高频部分是否变得更加清晰,并且尖峰是否减少。

细腻了不少
细腻了不少

细腻了不少

但是尖峰还在
但是尖峰还在

但是尖峰还在

量化误差

量化误差可能会导致高频部分的噪声或尖峰; 可以通过减少量化误差,或者使用更高位数的ADC模拟,观察高频部分的变化。

修改代码:
代码语言:javascript
复制
# 通过增加 ADC 位数,减少量化误差
B = 16  # 使用 16 位 ADC

验证效果:观察频谱图是否变得更加平滑,特别是在高频区域。

是不是很神奇,已经看不见了
是不是很神奇,已经看不见了

是不是很神奇,已经看不见了

24bit ADC

更加的细腻了
更加的细腻了

更加的细腻了

非常漂亮
非常漂亮

非常漂亮

减少噪声 强度或者 去除噪声,观察高频部分是否发生变化;然后尝试使用不同的 窗函数,如 Hamming 或 Blackman,看看对高频尖峰的影响;最后增加FFT点数(N)提高采样率(fs),验证是否能够改善高频分辨率和减少尖峰;以及减少量化误差,通过增加 ADC 位数(如从12位增加到16位),观察高频部分的变化。

数学建模详细的证明

怎么说呢,这次不是给出推导才有的结论,而是替代code有了结果再倒推。

信号采样与量化过程

首先,我们来回顾一下 采样量化 的过程。根据代码,信号经过 12位ADC16位ADC 以及更高的ADC采样后的变化可以通过以下数学模型来建模。

采样与量化公式

信号的连续时间部分 会被离散化并量化为数字信号。设定的量化步长 由ADC的位数 和满量程 决定:

对于12位ADC,,对于16位ADC,。量化误差与步长直接相关,步长越小,量化误差越小。

量化误差

量化误差 是由于将模拟信号 映射到离散的数字值时产生的误差。假设量化误差为随机变量,符合均匀分布的模型:

量化误差的标准差(即均匀分布的标准差)为:

对于12位ADC()和16位ADC(),量化误差的标准差分别为:

因为16位ADC的步长更小,量化误差的标准差更小,意味着量化噪声对信号的影响较小。

噪声密度与频谱的关系

量化误差引入的噪声表现为信号的频谱中,尤其在高频部分,量化噪声的功率谱密度(Noise Power Spectral Density, NPSD)由量化误差的标准差决定。

噪声功率谱密度

量化噪声的功率谱密度 是噪声的一个重要参数,表示单位频率带宽上的噪声功率。在这里,假设噪声为白噪声,均匀分布在频谱上。

对于ADC量化噪声,其功率谱密度 为常数,且由量化误差的标准差 决定:

其中 是频谱分辨率,即每个频率bin的宽度。在实际应用中,噪声功率谱密度与ADC位数和量化步长相关,16位ADC能够有效减少量化噪声的功率谱密度,因此高频部分的噪声水平会降低。

通过FFT计算噪声谱密度

在代码中,通过FFT对信号进行分析,FFT结果的幅度谱反映了信号和噪声的频谱分布。由于量化误差引入的噪声在高频段表现尤为明显,FFT处理后得到的噪声谱密度应表现为频谱图中的“噪声底”。16位ADC的低量化误差导致噪声底显著降低,因此频谱图中的高频部分得以平滑,避免了12位ADC时的尖峰噪声。

窗函数对频谱的影响

为了减少频谱泄漏,你在代码中使用了 Hann窗。窗函数通过对信号进行加窗处理,减少FFT频谱中的旁瓣和泄漏。对于纯正弦波,Hann窗能够有效地减少旁瓣泄漏,但对于噪声成分,窗函数的作用较小。

等效噪声带宽(ENBW)

在FFT分析中,等效噪声带宽(ENBW)描述了窗函数对频谱泄漏的影响。对于Hann窗,ENBW与窗函数的频率分辨率有关,可以通过以下公式计算:

其中, 是与窗函数相关的常数。Hann窗的 值约为1.5,因此窗函数的影响使得噪声密度被平滑,尤其是在高频区域。

通过 16位ADC 的更小步长,减少了 量化误差噪声的标准差,因此频谱图中的高频噪声水平明显降低,尤其在高频部分的尖峰消失或大幅减小;窗函数(如Hann窗)减少了频谱泄漏,尤其是在高频部分,避免了由频谱泄漏引起的噪声波动;其实也验证了16位ADC在低噪声底和高频噪声平滑方面的优势。(高位的 ADC 更加的明显)也从测量看到Σ-Δ ADC 的内核,就是对量化噪音的压制。

仔细看也还是有点毛边
仔细看也还是有点毛边

仔细看也还是有点毛边

不是完全没有
不是完全没有

不是完全没有

这个是我改成了 48bit 的 ADC 的结果
这个是我改成了 48bit 的 ADC 的结果

这个是我改成了 48bit 的 ADC 的结果

然后再加上双倍的 FFT 点数
然后再加上双倍的 FFT 点数

然后再加上双倍的 FFT 点数

采样率翻 10 倍,这个就更加的明显了
采样率翻 10 倍,这个就更加的明显了

采样率翻 10 倍,这个就更加的明显了

后记

代码和上次的一样,大家可以随意调整,玩的愉快。

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt

# 1. ADC / FFT 参数
fs = 1000_000.0      # 采样率 100 kS/s
N = 32768*2           # FFT 点数
B = 48              # 12 bit ADC
V_FS = 1.0          # 满量程 ±1 V,示例

# 2. 构造模拟输入信号:1 kHz 正弦 + 白噪声
f_sig = 1000.0
A_sig = 0.2         # 峰值 0.2 V → 约 0.141 Vrms

t = np.arange(N) / fs
x_analog = A_sig * np.sin(2 * np.pi * f_sig * t)

# 设定输入噪声密度 50 nV/√Hz(随便举例)
e_n = 10e-9
# 对应到每个采样点的时域噪声标准差:sigma = e_n * sqrt(fs/2)
# (粗略关系,准确推导更复杂,这里当示范)
sigma_noise = e_n * np.sqrt(fs/2)
noise = np.random.normal(scale=sigma_noise, size=N)

x_analog += noise

# 3. ADC 量化建模:12 bit,范围 ±V_FS
# 3.1 限幅
x_clip = np.clip(x_analog, -V_FS, V_FS)

# 3.2 量化步长
Delta = 2 * V_FS / (2**B)
codes = np.round(x_clip / Delta)   # 量化到整数码
codes = np.clip(codes, -(2**(B-1)), 2**(B-1)-1)

# 3.3 再转换回电压(这一步和 M2K 驱动做的类似)
x_digital = codes * Delta

# 4. 窗函数:Hann
window = np.hamming(N)
CG = np.sum(window) / N           # 相干增益
ENBW_factor = np.sum(window**2) * N / (np.sum(window)**2)
df = fs / N
ENBW = df * ENBW_factor

xw = x_digital * window

# 5. FFT(只看正频)
X = np.fft.rfft(xw)
freqs = np.fft.rfftfreq(N, d=1/fs)

# 6. 从 FFT 幅值恢复单频正弦的峰值、RMS、电压谱等

# 6.1 幅度谱(峰值,针对单频信号)
#     A_est[k] = 2 * |X[k]| / (N * CG)
A_est = 2 * np.abs(X) / (N * CG)
Vrms_line = A_est / np.sqrt(2)

# 6.2 把正弦的那个 bin 标出来看看
k_sig = np.argmin(np.abs(freqs - f_sig))
print("信号频率 bin:", k_sig, "对应频率:", freqs[k_sig], "Hz")
print("估计 Vrms:", Vrms_line[k_sig], "V")

# 7. 噪声谱:计算近似“电压噪声密度”(V/√Hz)
#    Vrms_line 是每个 bin 的等效 RMS(包含信号+噪声)。
#    对于噪声,可以除以 sqrt(ENBW) 得到近似噪声密度。
Vn_density = Vrms_line / np.sqrt(ENBW)

# 8. 转换为 dBV 与 dBV/√Hz
spec_dBV = 20 * np.log10(Vrms_line / 1.0 + 1e-20)
spec_dBV_Hz = 20 * np.log10(Vn_density / 1.0 + 1e-30)

# 9. 作图
plt.figure(figsize=(10, 6))
plt.semilogx(freqs, spec_dBV, label="Line spectrum (dBV)")
plt.xlabel("Frequency (Hz)")
plt.ylabel("Amplitude (dBV)")
plt.grid(which="both", ls=":")
plt.legend()
plt.title("FFT Spectrum (windowed, Hann)")
plt.tight_layout()
plt.show()

plt.figure(figsize=(10, 6))
plt.semilogx(freqs, spec_dBV_Hz, label="Noise density (dBV/√Hz)")
plt.xlabel("Frequency (Hz)")
plt.ylabel("Noise density (dBV/√Hz)")
plt.grid(which="both", ls=":")
plt.legend()
plt.title("Estimated Noise Spectral Density")
plt.tight_layout()
plt.show()
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开始研究
    • FFT 分辨率与采样率
    • 量化误差
  • 一条条的研究
    • 噪声的影响
      • 修改代码:
    • 窗函数的选择
      • 修改代码:
    • FFT分辨率与采样率
      • 修改代码:
    • 量化误差
      • 修改代码:
    • 24bit ADC
  • 数学建模详细的证明
    • 信号采样与量化过程
      • 采样与量化公式
      • 量化误差
    • 噪声密度与频谱的关系
      • 噪声功率谱密度
      • 通过FFT计算噪声谱密度
    • 窗函数对频谱的影响
    • 等效噪声带宽(ENBW)
  • 后记
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档