在信号处理过程中,噪声通常被认为是无用的,甚至我们会想出很多方法来滤除信号中的噪声,提高信号的信噪比,比如带限滤波器、周期信号取平均等。然而噪声真的一无是处吗?下面通过一个例子,向你展示噪声不为人知的另一面!
1. ADC采样量化过程
我们所处的世界是连续的,而计算机却只能处理离散信号。为此,需要对连续信号进行离散化处理,这个过程靠模数转换器(Analogy-to-Digital Converter, ADC)来实现。
ADC最重要的参数包括:1)采样率
f
s
f_s
fs,决定了ADC离散样点的时间精度,采样率越高,离散信号越逼近于原始连续信号;2)量化bit位数
N
N
N和参考电压
V
r
e
f
V_{ref}
Vref,决定了ADC量化的电压精度,量化误差
Δ
V
\Delta V
ΔV服从均匀分布
U
(
−
V
r
e
f
2
N
−
1
,
V
r
e
f
2
N
−
1
)
U(-\frac{V_{ref}}{2^{N-1}},\frac{V_{ref}}{2^{N-1}})
U(−2N−1Vref,2N−1Vref)。本文仅考虑电压量化精度。
下面首先通过一个仿真案例(仿真代码见附录1),直观了解量化的影响。利用高采样率的离散样点来模拟连续信号,每隔
Δ
\Delta
Δ个样点从高采样率的离散样点中取值以模拟采样过程,将采样得到的样点进行2/4/8bit的量化。从下图可以看出,量化bit数越小,量化阶梯现象越严重,可表征的电压精细度越差。
2. 噪声赋能量化过程
若要用ADC采集一个幅度很小的信号,甚至小于ADC的一个量化单位,则量化后无法获取任何有效信息。如下图所示(代码见附录2),信号幅度为0.03V,小于ADC 的LSB=0.0625V,此时量化后的所有采样点均为0。
现在在上图中的采样信号中加入RMS=0.03V的高斯噪声,再进行量化处理,并将量化后的信号进行低通滤波,得到下图所示结果。现在噪声提高了信号的幅度,超过了ADC的量化单元,是的量化后保留了部分有效信号的信息,再经过后续的滤波器消除噪声影响,可以部分恢复有效信号。
综上所述,不能思维定式地认为噪声都是无用的,换个角度看,噪声也是宝!!
【附录1】:图2代码
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 使用微软雅黑字体
plt.rcParams['axes.unicode_minus'] = False # 处理负号显示异常
if __name__ == '__main__':
f0 = 100
fs = 100000
delta = 10
v_ref = 4
bits = np.array([2, 4, 8])
N = int(fs / 10)
t = np.arange(0, N, 1) / fs
sig = np.sin(2 * np.pi * f0 * t) # 用高采样率模拟连续信号
plt.figure()
plt.plot(t, sig, 'b', linewidth=3)
for i in range(len(bits)):
lsb = v_ref / (2 ** bits[i])
sampled_sig = sig[0::delta] # 原始采样信号
sampled_sig = (np.round(sampled_sig / lsb)) * lsb
plt.plot(t[0::delta], sampled_sig, '.')
plt.legend(['连续信号', 'ADC bit=2', 'ADC bit=4', 'ADC bit=8'])
plt.show()
【附录2】:图3代码
if __name__ == '__main__':
f0 = 100
fs = 100000
delta = 10
v_ref = 4
bits = 6
N = int(fs / 10)
t = np.arange(0, N, 1) / fs
sig = 0.01 * np.sin(2 * np.pi * f0 * t) # 用高采样率模拟连续信号
plt.figure()
lsb = v_ref / (2 ** bits)
sampled_sig = sig[0::delta] # 原始采样信号
quantitative_sig = (np.round(sampled_sig / lsb)) * lsb
plt.plot(t[0::delta], sampled_sig, 'b')
plt.plot(t[0::delta], quantitative_sig, 'r.')
plt.legend(['采样信号', '量化信号'])
plt.show()
【附录3】:图4代码
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as signal
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 使用微软雅黑字体
plt.rcParams['axes.unicode_minus'] = False # 处理负号显示异常
if __name__ == '__main__':
f0 = 100
fs = 100000
delta = 10
v_ref = 4
bits = 6
N = int(fs / 10)
t = np.arange(0, N, 1) / fs
sig = 0.03 * np.sin(2 * np.pi * f0 * t) # 用高采样率模拟连续信号
lsb = v_ref / (2 ** bits)
sampled_sig = sig[0::delta] # 原始采样信号
noise = np.random.normal(loc=0, scale=0.03, size=len(sampled_sig))
sampled_sig = sig[0::delta] + noise
quantitative_sig = (np.round(sampled_sig / lsb)) * lsb
# 第信号进行滤波
cutoff = f0 * 3
nyquist_freq = fs / delta / 2
normal_cutoff = cutoff / nyquist_freq
b, a = signal.bessel(5, normal_cutoff, btype='low', analog=False)
filtered_data = signal.lfilter(b, a, quantitative_sig)
plt.figure()
plt.plot(t[0::delta], sampled_sig, 'b')
plt.plot(t[0::delta], quantitative_sig, 'g.')
plt.plot(t[0::delta], filtered_data, 'k.')
plt.plot(t[0::delta], sig[0::delta], 'r')
plt.legend(['采样信号', '量化信号', '滤波信号', '理想信号'])
plt.show()