也是昨天的群友问的,今天写第二篇。
首先这个问题涉及 欠采样(undersampling) 和 混频采样(heterodyne sampling,或下变频) 两种不同的频谱搬移策略,但最终的 SNDR(Signal-to-Noise and Distortion Ratio) 衡量方式有共通也有差异之处。
信噪失真比(也称为 SINAD)指输入正弦波时,RMS 信号功率与 (a) 总噪声功率和 (b) 输出端(不含 DC)的所有其他频率分量功率加上所有其他谐波分量功率的 RMS 和的比值。用于衡量数据转换器的动态性能的关键参数之一,因为 SNDR 包含奈奎斯特带宽上的所有噪声和杂散。
也说明的是输入信号的质量;SNDR 越大,输入功率中的噪声和杂散比率越小;我理解SNDR 就是衡量一个信号“干净不干净”的指标。
通俗来说这个参数可以告诉你:在你想要的信号旁边,有没有太多杂七杂八的噪声或奇怪的东西(比如谐波、干扰);
表达式是:SNDR = 信号功率 ÷ (噪声 + 失真功率)
通常在 FFT 分析中:
看公式知道信号的能量越大、杂音和失真越小,SNDR 就越高。
衡量标准是看信号在目标频段(通常是基带)中,相对于其他杂散成分的清晰度。
测一个高频信号,但 ADC(模拟转数字转换器)“听不到”那么高的声音(频率太高了),所以有两个方法采集:
也称 带通采样(Bandpass Sampling),直接用低采样率 ADC 采样高频信号,但要求信号本身是带通信号;频谱会“折叠”进入 [0, Fs/2] 范围,对时钟抖动和 ADC 带宽要求高,这里补充一点,欠采样是和时钟抖动也有关系的。
ADC 的 SNR 受采样时钟抖动(jitter)影响:
假设:抖动为 10ps(很优秀了),输入信号频率 f = 40 kHz vs 5 kHz
计算:
40 kHz:SNR ≈ 105 dB
5 kHz:SNR ≈ 119 dB
大概可以这样说越高频,越容易因为抖动造成 SNR 损失。
接上文,也就是把 ADC 的采样速度故意设得低一点;利用数学特性,让高频信号“折叠”下来,变成低频信号。
比如听见一台发动机的嗡嗡声,其实它是高速运转的,但你听到的是一个比较低的频率。容易混进别的声音(其他频率的信号也折叠过来)。
使用模拟混频器将 RF 信号混频(与 LO 相乘)后变到基带或中频(IF),再用 ADC 采样;适用于宽带或多个信号搬移,需要 LO 和滤波器。
就像你把一个超高音的乐器录音,先用一个转换器把它的音调调低,再用普通麦克风录下来。这个转换器就是“混频器”。它把信号“下变频”到了 ADC 能处理的范围里。
可以看到两种采样方式:都在做“频率搬家”
比如听一场音乐会:
最后你拿录音文件来评分,不管你是怎么录的,只看最终录到的声音有没有杂音和失真——这就是 SNDR 的评估。
所以无论哪种方式,最终的 SNDR 都是对进入 ADC 后的频谱结果进行如下处理:
评估项 | 欠采样(Undersampling) | 混频器搬移(Heterodyne) |
---|---|---|
最终 SNDR 测量方式 | 在基带频谱窗口内分析(FFT 取峰值与噪声+谐波) | 同样在基带窗口分析 |
关键影响因素 | - 采样时钟抖动(直接影响 SNR)- ADC 采样带宽(需能采样原始频率分量)- 频谱折叠失真 | - 混频器非线性失真(IM3、LO 泄漏)- LO 相位噪声- 中频滤波器品质 |
是否要频谱搬移回原频点 | 否,直接分析折叠后的频谱 | 否,变频后分析 |
带宽设定 | 通常设定带通信号带宽 | 通常设定中频通带范围 |
校准策略 | 对时钟抖动 / 带宽效应建模 | 对混频器非线性和杂散分量做建模 |
我这里仿真以前的模型有问题,但是出来结果还是挺好看的(
要处理的是 40 kHz 的窄带信号):
原信号(40kHz) × LO(35kHz) →→ 混频后产生 5kHz(目标)+ 75kHz(镜像)→ 滤波器抑制 75kHz 分量(-30 dB)→ ADC 正常采样(比如 100kHz)
原信号(40kHz) →→ 直接用 35kSps ADC 采样(欠采样)→ 频谱折叠 → 5kHz 落入基带
结果
方案 | SNDR(模拟值) | 说明 |
---|---|---|
混频方案(频率搬移+滤波后采样) | 约 37.7 dB | 目标频率集中,失真和噪声有效抑制 |
欠采样方案(35kSps 直采 40kHz) | 约 23.9 dB | 虽然目标频率落在基带,但混叠导致失真更大 |
总结一下:
应用情况 | 推荐方案 |
---|---|
对 SNDR 要求高(>90 dB) | 混频方案,可更稳定控制频谱和失真 |
对系统复杂度要求低,功耗和硬件极简 | 欠采样方案可行,但要小心混叠和带外干扰 |
只处理一个窄带信号,带外无干扰 | 欠采样也能达到较好效果(注意前级滤波) |
可以容忍一点复杂度换更高性能 | 混频 + 滤波后采样是更稳妥选择 |
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import butter, lfilter, fftconvolve
from numpy.fft import fft, fftfreq
# 设置参数
fs_high = 100_000 # 高采样率用于混频方案
fs_low = 35_000 # 欠采样率
f_signal = 40_000 # 原始信号频率
f_lo = 35_000 # 混频本振频率
duration = 0.01 # 10ms 信号持续时间
t_high = np.arange(0, duration, 1/fs_high)
t_low = np.arange(0, duration, 1/fs_low)
# 生成信号:40kHz 正弦波 + 微小失真项 + 噪声
signal = np.sin(2 * np.pi * f_signal * t_high)
signal += 0.01 * np.sin(2 * np.pi * 2 * f_signal * t_high) # 二次谐波
signal += 0.005 * np.random.randn(len(t_high)) # 噪声
# 混频方案
lo = np.sin(2 * np.pi * f_lo * t_high)
mixed_signal = signal * lo # 乘法混频
# 滤波器设计:带通滤波器,通带5kHz ± 2.5kHz
def bandpass_filter(data, fs, lowcut, highcut, order=5):
nyq = 0.5 * fs
b, a = butter(order, [lowcut/nyq, highcut/nyq], btype='band')
return lfilter(b, a, data)
filtered_mixed = bandpass_filter(mixed_signal, fs_high, 2.5e3, 7.5e3)
# 重新采样(模拟ADC采样)
def downsample(signal, orig_fs, target_fs):
factor = int(orig_fs / target_fs)
return signal[::factor]
mixed_sampled = downsample(filtered_mixed, fs_high, fs_low)
# 欠采样方案(直接35k采样原始40k信号)
signal_alias = np.sin(2 * np.pi * f_signal * t_low)
signal_alias += 0.01 * np.sin(2 * np.pi * 2 * f_signal * t_low)
signal_alias += 0.005 * np.random.randn(len(t_low))
# 计算 SNDR
def compute_sndr(signal, fs):
N = len(signal)
fft_vals = np.abs(fft(signal))[:N//2]
freqs = fftfreq(N, d=1/fs)[:N//2]
peak_idx = np.argmax(fft_vals)
signal_power = fft_vals[peak_idx] ** 2
total_power = np.sum(fft_vals ** 2)
noise_dist_power = total_power - signal_power
sndr = 10 * np.log10(signal_power / noise_dist_power)
return sndr, freqs, fft_vals
sndr_mixed, freq_mixed, fft_mixed = compute_sndr(mixed_sampled, fs_low)
sndr_alias, freq_alias, fft_alias = compute_sndr(signal_alias, fs_low)
# 画图
plt.figure()
plt.plot(freq_mixed, 20*np.log10(fft_mixed), label=f'Mixed Sampling SNDR={sndr_mixed:.2f} dB')
plt.plot(freq_alias, 20*np.log10(fft_alias), label=f'Undersampling SNDR={sndr_alias:.2f} dB')
plt.title("FFT Comparison of Mixed Sampling vs Undersampling")
plt.xlabel("Frequency (Hz)")
plt.ylabel("Magnitude (dB)")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()
参考文献?没有,我就是自己的参考文献(😂)