信号的采样和重构是数字信号处理中重要的基础概念之一。采样是将连续时间信号转换为离散时间信号的过程,而重构则是将离散时间信号还原为连续时间信号的过程。在信号处理中,通常会采用周期采样和非周期采样两种方式进行信号采样。
周期采样
周期采样(也称为等间隔采样)是一种将连续时间信号转换为离散时间信号的方法,它的思想是在固定的时间间隔内对信号进行采样,即在等间隔的时间点上采样。这些时间点称为采样时刻,采样时刻的间隔称为采样周期。
假设连续时间信号为 x(t)x(t),采样周期为 TsT_s,则采样时刻为 t=nTst=nT_s,其中 nn 是整数。那么采样后的离散时间信号为:
其中 x[n]x[n] 表示采样信号在第 nn 个采样时刻的取值。
需要注意的是,周期采样有一个重要的限制条件,即采样周期 TsT_s 必须满足采样定理。采样定理指出,对于一个最高频率为 fmaxf_{max} 的信号进行采样,采样周期 TsT_s 必须小于等于信号周期的一半,即 Ts≤12fmaxT_s leq frac{1}{2f_{max}}。否则,会出现采样失真现象,即由于采样率不足而无法还原原始信号。
下面是一个使用 Python 实现的周期采样的示例代码:
import numpy as np
import matplotlib.pyplot as plt
# 原始信号
t = np.linspace(-1, 1, 1000)
x = np.sin(2 * np.pi * 5 * t)
# 周期采样
Ts = 0.1 # 采样周期
n = np.arange(-10, 10) # 采样点序列
xn = np.sin(2 * np.pi * 5 * n * Ts) # 采样信号
# 绘图
plt.plot(t, x, label='Original signal')
plt.stem(n*Ts, xn, label='Sampled signal')
plt.legend()
plt.show()
在这个示例中,我们生成了一个正弦信号 x(t)=sin(2πft)x(t)=sin(2pi f t),并使用周期采样对其进行采样。图中的蓝色曲线为原始信号,橙色的圆点表示采样时刻的离散时间点,红色的竖线表示采样值。
非周期采样
非周期采样也称为不等间隔采样,是指采样时间间隔不固定的采样方式。设采样时刻为 t1,t2,…,tnt_1,t_2,…,t_n,则得到的采样信号为:
其中,NN 表示采样点数。可以看出,采样信号 xs(t)x_s(t) 是由原始信号 x(t)x(t) 与一串在离散时刻 t1,t2,…,tnt_1,t_2,…,t_n 处取值的单位脉冲序列相乘得到的。
非周期采样通常使用时间间隔 ΔtDelta t 来表示采样率,即 fs=1/Δtf_s = 1/Delta t,其中 fsf_s 是采样率。对于连续时间信号 x(t)x(t),我们可以使用采样定理,即 Nyquist-Shannon 采样定理,来确保采样后的信号不失真。
Nyquist-Shannon 采样定理指出,如果信号 x(t)x(t) 的频率范围在 [0,fs/2][0, f_s/2] 之内,那么在采样率为 fsf_s 时,我们可以完全恢复信号。因此,我们可以使用以下公式对信号进行采样:
其中 nn 是采样点的整数序列。
然后,我们可以使用插值方法来重构原始信号。最简单的方法是使用零阶保持插值,也称为阶梯插值,它假定在两个采样点之间的信号值保持不变。这意味着,在 [nΔt,(n+1)Δt][nDelta t, (n+1)Delta t] 时间间隔内,信号值是常数 x[n]x[n]。
重构后的信号为:
其中,rect(t)mathrm{rect}(t) 是矩形函数,定义为:
下面是 Python 代码示例,我们可以看到采样后的信号与原始信号非常接近:
import numpy as np
import matplotlib.pyplot as plt
# 原始信号
t = np.linspace(-1, 1, 1000)
x = np.sin(2 * np.pi * 5 * t)
# 非周期采样
fs = 50 # 采样率
ts = 1 / fs # 采样间隔
n = np.arange(0, len(t))
xn = x[n*int(ts/t[1])] # 采样信号
# 零阶保持插值
tr = np.linspace(-1, 1, 1000)
xr = np.zeros_like(tr)
for i in range(len(n)):
xr += xn[i] * np.sinc((tr - n[i] * ts) / ts)
# 绘图
plt.plot(t, x, label='Original signal')
plt.stem(n*ts, xn, label='Sampled signal')
plt.plot(tr, xr, label='Reconstructed signal')
plt.legend()
plt.show()
重构
重构是将离散时间信号还原为连续时间信号的过程。设采样信号为 xs(t)x_s(t),采样周期为 TsT_s,则重构信号为:
其中,sinc(x)sinc(x) 表示 sin(x)xfrac{sin(x)}{x} 函数。可以看出,重构信号 xr(t)x_r(t) 是由采样信号 xs(t)x_s(t) 在每个采样时刻处乘上一个 sincsinc 函数的值并求和得到的。
下面是 Python 代码实现:
import numpy as np
import matplotlib.pyplot as plt
# 原始信号
t = np.linspace(-1, 1, 1000)
x = np.sin(2 * np.pi * 5 * t)
# 周期采样
Ts = 0.1 # 采样周期
n = np.arange(-10, 10) # 采样点序列
xn = np.sin(2 * np.pi * 5 * n * Ts) # 采样信号
# 重构
tr = np.linspace(-1, 1, 1000)
xr = np.zeros_like(tr)
for i in range(len(n)):
xr += xn[i] * np.sinc((tr - n[i] * Ts) / Ts)
# 绘图
plt.plot(t, x, label='Original signal')
plt.stem(n*Ts, xn, label='Sampled signal')
plt.plot(tr, xr, label='Reconstructed signal')
plt.legend()
plt.show()
在这个示例中,我们先生成了一个正弦信号 x(t)=sin(2πft)x(t)=sin(2pi f t),然后使用周期采样对其进行采样,并最终使用 sincsinc 函数重构了原始信号。重构信号与原始信号非常接近,这证明了采样和重构的有效性。
信号的重构通常使用一种名为插值的方法,该方法将采样信号与一种基函数相乘,并将它们相加以获得连续信号。在这里,我们将使用基函数 sinc(x)sinc(x),它是一个非常常见的插值函数。
假设我们有一个离散时间序列 x[n]x[n],它是由原始信号进行周期采样得到的。在周期采样中,我们将原始信号 x(t)x(t) 采样为:
其中 TsT_s 是采样周期,nn 是整数。
现在,我们希望通过重构方法得到连续的信号 xr(t)x_r(t),并使用 sinc(x)sinc(x) 函数进行插值。那么,插值信号可以表示为:
其中,sinc(x)sinc(x) 函数定义为:
上面的式子意味着对于任何时刻 tt,我们可以通过将 sinc(x)sinc(x) 函数与采样点 x[n]x[n] 相乘,然后对所有采样点求和,从而得到该时刻的连续信号 xr(t)x_r(t)。这种重构技术被称为零阶保持插值(zero-order hold interpolation)。
下面是 Python 代码实现:
import numpy as np
import matplotlib.pyplot as plt
# 原始信号
t = np.linspace(-1, 1, 1000)
x = np.sin(2 * np.pi * 5 * t)
# 周期采样
Ts = 0.1 # 采样周期
n = np.arange(-10, 10) # 采样点序列
xn = np.sin(2 * np.pi * 5 * n * Ts) # 采样信号
# 重构
tr = np.linspace(-1, 1, 1000)
xr = np.zeros_like(tr)
for i in range(len(n)):
xr += xn[i] * np.sinc((tr - n[i] * Ts) / Ts)
# 绘图
plt.plot(t, x, label='Original signal')
plt.stem(n*Ts, xn, label='Sampled signal')
plt.plot(tr, xr, label='Reconstructed signal')
plt.legend()
plt.show()
在这个示例中,我们先生成了一个正弦信号 x(t)=sin(2πft)x(t)=sin(2pi f t),然后使用周期采样对其进行采样,并最终使用 sincsinc 函数重构了原始信号。重构信号与原始信号非常接近,这证明了采样和重构的有效性。