说到随机信号,很多理工科同学的第一反应可能是头疼。毕竟,确定性信号(比如正弦波、方波)是“听话”的,给个输入就知道输出是什么;但随机信号就像是个调皮的孩子,你没法预知它下一秒的具体数值,只能猜它的“脾气”和“习惯”。
别怕,今天咱们不背枯燥的定义,而是通过几个经典的习题场景,把随机信号处理的核心逻辑像剥洋葱一样层层揭开。我会用大白话配合严谨的数学推导,顺便给点编程实操的建议,保证让你不仅会做题,还能真正理解背后的物理意义。
第一关:从“不确定”到“可预测”——均值与方差
核心痛点:随机变量 \(X\) 和随机过程 \(X(t)\) 到底有啥区别?
很多初学者混淆这两个概念。简单来说,随机变量是某一时刻的“快照”,而随机过程是一组随时间变化的随机变量的集合。
经典例题:白噪声的统计特性
题目:设 \(n(t)\) 是一个均值为0,功率谱密度为 \(N_0/2\) 的高斯白噪声。求其自相关函数 \(R_n(\tau)\),并解释其物理含义。
解析思路: 这道题看似简单,却是随机信号处理的基石。我们不需要去推导复杂的积分,直接利用傅里叶变换的性质即可秒杀。
已知条件:
- 均值 \(E[n(t)] = 0\)
- 功率谱密度 (PSD) \(S_n(f) = \frac{N_0}{2}\) (常数,这就是“白”的意思,像白光包含所有频率)
关键公式: 维纳-辛钦定理(Wiener-Khinchin Theorem)告诉我们:自相关函数和功率谱密度是一对傅里叶变换对。 $\( R_n(\tau) = \mathcal{F}^{-1}[S_n(f)] = \int_{-\infty}^{\infty} S_n(f) e^{j2\pi f \tau} df \)$
计算过程: 由于 \(S_n(f)\) 是常数 \(\frac{N_0}{2}\),代入积分: $\( R_n(\tau) = \frac{N_0}{2} \int_{-\infty}^{\infty} e^{j2\pi f \tau} df \)$
这里有一个数学上的“魔术”。我们知道狄拉克 \(\delta\) 函数的傅里叶逆变换性质: $\( \int_{-\infty}^{\infty} e^{j2\pi f \tau} df = \delta(\tau) \)$
所以: $\( R_n(\tau) = \frac{N_0}{2} \delta(\tau) \)$
物理含义解读: 这个结果非常反直觉但又极其重要。\(\delta(\tau)\) 意味着只有当时间间隔 \(\tau = 0\) 时,自相关函数才有值(无穷大),其他任何非零的时间间隔,自相关函数都是0。
- 翻译成人话:白噪声在任意两个不同的时刻是完全不相关的(对于高斯白噪声,不相关等价于独立)。上一秒的值对下一秒没有任何预测价值。它是最“混乱”的信号。
Python 实战验证
光说不练假把式。我们用 Python 生成一段高斯白噪声,看看它的自相关函数是不是真的像 \(\delta\) 函数那样“尖”。
import numpy as np
import matplotlib.pyplot as plt
def simulate_white_noise():
# 设置参数
fs = 1000 # 采样率 1kHz
duration = 1.0 # 时长 1秒
t = np.arange(0, duration, 1/fs)
# 生成高斯白噪声: 均值0, 标准差1 (对应功率谱密度相关)
noise = np.random.normal(0, 1, len(t))
# 计算自相关函数
# np.correlate 计算的是互相关,我们需要归一化并处理滞后
# 这里使用 numpy 的 correlate 模式 'full' 然后裁剪
corr = np.correlate(noise, noise, mode='full')
# 归一化处理,使其峰值为1
corr = corr / corr[len(t)//2]
# 只取正半轴用于绘图 (因为自相关是对称的)
lags = np.arange(-len(t)+1, len(t))
pos_lags = lags[lags >= 0]
pos_corr = corr[len(t)-1:]
# 绘图
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(t[:100], noise[:100]) # 只画前100个点以免太乱
plt.title('Time Domain: White Noise')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.subplot(1, 2, 2)
plt.stem(pos_lags / fs, pos_corr, use_line_collection=True)
plt.title('Autocorrelation Function')
plt.xlabel('Lag Time (s)')
plt.ylabel('Correlation Coeff')
plt.grid(True)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
simulate_white_noise()
代码说明: 注意看右边的图,除了 \(\tau=0\) 处有一个巨大的尖峰外,其他地方虽然因为有限样本长度会有微小的波动(这是估计误差,理论上是0),但整体趋势非常接近0。这直观地验证了 \(R_n(\tau) = \frac{N_0}{2}\delta(\tau)\)。
第二关:平稳性的陷阱——严平稳 vs 宽平稳
核心痛点:为什么题目说它是平稳的,我算出来均值却变了?
这是随机信号中最容易掉坑的地方。严平稳要求所有统计特性都不随时间平移改变,这太难满足了。工程中常用的是宽平稳(WSS, Wide-Sense Stationary)。
宽平稳的两个硬性指标:
- 均值 \(E[X(t)]\) 是常数(不随时间 \(t\) 变化)。
- 自相关函数 \(R_X(t, t+\tau)\) 只依赖于时间差 \(\tau\),而与具体的起始时间 \(t\) 无关。
经典例题:调制信号的平稳性判断
题目:设随机过程 \(Y(t) = X(t) \cos(2\pi f_c t + \Theta)\),其中 \(X(t)\) 是宽平稳随机过程,\(\Theta\) 是在 \([0, 2\pi]\) 上均匀分布的随机变量,且 \(\Theta\) 与 \(X(t)\) 相互独立。判断 \(Y(t)\) 是否为宽平稳?
解析思路: 这种题型在通信原理中太常见了(比如AM调制)。我们要按部就班地检查那两个指标。
第一步:检查均值
\[ E[Y(t)] = E[X(t) \cos(2\pi f_c t + \Theta)] \]
利用独立性,期望可以拆开: $\( E[Y(t)] = E[X(t)] \cdot E[\cos(2\pi f_c t + \Theta)] \)$
先算后面那个余弦项的期望。因为 \(\Theta \sim U[0, 2\pi]\),概率密度函数 \(f_\theta(\theta) = \frac{1}{2\pi}\)。 $\( E[\cos(2\pi f_c t + \Theta)] = \int_{0}^{2\pi} \cos(2\pi f_c t + \theta) \cdot \frac{1}{2\pi} d\theta \)\( \)\( = \frac{1}{2\pi} [\sin(2\pi f_c t + \theta)]_{0}^{2\pi} = \frac{1}{2\pi} (\sin(...) - \sin(...)) = 0 \)$
所以: $\( E[Y(t)] = E[X(t)] \cdot 0 = 0 \)$ 均值是常数 0。✅ 第一个条件满足。
第二步:检查自相关函数
\[ R_Y(t, t+\tau) = E[Y(t) Y(t+\tau)] \]
\[ = E[ X(t)\cos(2\pi f_c t + \Theta) \cdot X(t+\tau)\cos(2\pi f_c (t+\tau) + \Theta) ] \]
再次利用 \(X\) 和 \(\Theta\) 的独立性,将 \(X\) 部分和 \(\Theta\) 部分分开: $\( = E[X(t)X(t+\tau)] \cdot E[\cos(2\pi f_c t + \Theta)\cos(2\pi f_c (t+\tau) + \Theta)] \)$
前半部分就是 \(X(t)\) 的自相关函数 \(R_X(\tau)\)(因为假设 \(X\) 是宽平稳的,所以只依赖 \(\tau\))。
后半部分利用积化和差公式 \(\cos A \cos B = \frac{1}{2}[\cos(A-B) + \cos(A+B)]\): 令 \(A = 2\pi f_c t + \Theta\), \(B = 2\pi f_c (t+\tau) + \Theta\) 则 \(A-B = -2\pi f_c \tau\) \(A+B = 4\pi f_c t + 2\pi f_c \tau + 2\Theta\)
所以期望变为: $\( E[\dots] = \frac{1}{2} E[\cos(-2\pi f_c \tau)] + \frac{1}{2} E[\cos(4\pi f_c t + 2\pi f_c \tau + 2\Theta)] \)$
第一项 \(\cos(-2\pi f_c \tau)\) 是确定性函数,期望就是它自己。 第二项中,\(\Theta\) 在 \([0, 2\pi]\) 均匀分布,\(2\Theta\) 在 \([0, 4\pi]\) 均匀分布。对一个完整周期或整数倍周期的余弦函数求积分,结果必为0。 即: $\( E[\cos(C + 2\Theta)] = \int_{0}^{2\pi} \cos(C + 2\theta) \frac{1}{2\pi} d\theta = 0 \)$
因此,后半部分简化为: $\( \frac{1}{2} \cos(2\pi f_c \tau) \)$
最终得到: $\( R_Y(\tau) = \frac{1}{2} R_X(\tau) \cos(2\pi f_c \tau) \)$
结论: \(R_Y\) 只依赖于 \(\tau\),与绝对时间 \(t\) 无关。加上均值为常数,所以 \(Y(t)\) 是宽平稳随机过程。✅
给小朋友的比喻: 想象你在玩跷跷板(\(X(t)\)),它的重量分布是稳定的(宽平稳)。现在有人拿着一个固定的节奏在上下抖动整个跷跷板的支点(\(\cos\) 项)。虽然看起来抖动很厉害,但如果那个抖动节奏是非常规律的(确定性信号),并且和跷跷板本身的重量变化没关系(独立),那么从长期统计来看,系统的“平均状态”和“内部关联模式”依然是稳定可控的。
第三关:线性系统对随机信号的影响
核心痛点:随机信号进了滤波器,输出还是随机的吗?谱密度怎么变?
这是考试和工程应用的重灾区。记住一个黄金法则:线性时不变系统(LTI)不会改变随机过程的平稳性。如果输入是宽平稳的,输出也是宽平稳的。
核心公式:输出功率谱密度
如果输入 \(X(t)\) 的 PSD 是 \(S_X(f)\),系统的频率响应是 \(H(f)\),那么输出 \(Y(t)\) 的 PSD \(S_Y(f)\) 为: $\( S_Y(f) = |H(f)|^2 S_X(f) \)$
这就好比:系统是个“筛子”,它不产生新的噪声能量,只是把输入信号中不同频率的成分按照 \(|H(f)|^2\) 的比例进行放大或衰减。
经典例题:低通滤波后的噪声功率
题目:白噪声 \(n(t)\) (PSD: \(N_0/2\)) 通过一个理想低通滤波器,截止频率为 \(B\) Hz。求输出噪声的平均功率。
解析思路: 平均功率等于自相关函数在 \(\tau=0\) 处的值,也等于功率谱密度在整个频域上的积分。
确定输出的 PSD: 理想低通滤波器的频率响应: $\( H(f) = \begin{cases} 1, & |f| \le B \\ 0, & |f| > B \end{cases} \)$
所以输出 PSD: $\( S_Y(f) = |H(f)|^2 \cdot \frac{N_0}{2} = \begin{cases} \frac{N_0}{2}, & |f| \le B \\ 0, & |f| > B \end{cases} \)$
计算总功率 \(P_Y\): $\( P_Y = R_Y(0) = \int_{-\infty}^{\infty} S_Y(f) df \)\( \)\( P_Y = \int_{-B}^{B} \frac{N_0}{2} df \)\( \)\( P_Y = \frac{N_0}{2} \cdot [f]_{-B}^{B} = \frac{N_0}{2} \cdot (B - (-B)) = \frac{N_0}{2} \cdot 2B = N_0 B \)$
答案:输出噪声功率为 \(N_0 B\)。
直观理解: 白噪声在所有频率都有能量。但是你的低通滤波器像个水桶,只接住了 \(-B\) 到 \(B\) 这一段的水。这段带宽是 \(2B\)。每一赫兹的能量密度是 \(N_0/2\)。所以总能量 = 密度 × 带宽 = \((N_0/2) \times 2B = N_0 B\)。非常简单!
第四关:实战中的“坑”——数字信号处理视角
核心痛点:理论是连续的,代码是离散的,怎么对应?
在实际工程中,我们处理的是离散序列。这时候要注意采样定理和混叠问题。
离散白噪声的自相关
如果连续白噪声被采样,且采样间隔为 \(T_s\),得到的离散序列 \(x[n]\) 的自相关函数 \(r_x[k]\) 为: $\( r_x[k] = \sigma^2 \delta[k] \)\( 其中 \)\sigma^2$ 是离散噪声的方差。
注意:这里的 \(\delta[k]\) 是离散单位脉冲,只有 \(k=0\) 时为1,其余为0。这意味着离散白噪声在不同采样点之间也是完全不相关的。
MATLAB/Python 仿真小贴士
如果你在做作业或者项目,发现生成的“白噪声”自相关函数在 \(\tau \neq 0\) 时有明显的非零值,通常有两个原因:
- 样本量不够大:统计估计有偏差。尝试增加
duration或降低fs(保持总点数足够多)。 - 数据预处理错误:确保你没有无意中给数据加了直流分量(均值不为0),或者没有正确地减去均值后再计算自相关。
修正后的 Python 代码片段(更严谨的计算方式):
def calculate_acf_clean(signal):
"""
计算去均值后的信号的自相关函数
"""
# 1. 去均值
signal_centered = signal - np.mean(signal)
# 2. 计算互相关
# mode='full' 返回所有滞后的相关系数
acf_full = np.correlate(signal_centered, signal_centered, mode='full')
# 3. 归一化
# 除以最大滞后时的自相关值(即方差),使得 lag=0 时值为 1
acf_normalized = acf_full / acf_full[len(signal_centered)-1]
return acf_normalized
# 使用示例
noise = np.random.randn(10000) # 生成1万个点的标准正态分布噪声
acf = calculate_acf_clean(noise)
# 查看前10个lag的值
print("ACF values for first 10 lags:", acf[-1:9:-1])
# 理论上应该非常接近 [1, 0, 0, 0...]
总结与建议
学习随机信号,最难的不是公式,而是思维方式的转变。
- 确定性信号看“波形”,随机信号看“统计规律”。
- 不要试图去预测某一个具体的 \(n(t)\) 是多少,要去关心它的能量分布在哪里(PSD),以及它自己和过去的关系有多紧密(自相关)。
给你的备考/学习建议:
- 死磕定义:把宽平稳的两个条件刻在脑子里。
- 熟记变换对:白噪声 \(\leftrightarrow\) \(\delta\) 函数;理想低通 \(\leftrightarrow\) Sa 函数(Sinc)。
- 多用仿真:像上面那样,写几行代码跑一跑,看着波形和数据,你会瞬间理解那些抽象的积分是什么意思。
希望这篇解析能帮你理清思路。如果有具体的某道难题卡住了,欢迎随时拿出来,我们继续拆解!
