
简介南京理工大学随机信号处理仿真报告以伪随机相位编码脉冲雷达为核心案例系统讲解伪随机编码信号原理、雷达不模糊距离与不模糊速度的制约关系、距离/速度分辨力的影响因素以及多普勒敏感现象和多普勒容限等关键理论。实验部分通过m序列的单周期与多周期自相关函数、码元采样点数对频谱的影响、单目标回波分析等演示了脉冲压缩中匹配滤波器的窄脉冲变换过程并利用FFT实现频域多普勒提取从而将抽象公式转化为可视化仿真结果。资源包为1个docx文档大小8.44MB文件包含题目描述、符号说明、理论依据、仿真条件清单及实验仿真等章节结构完整且便于按目录检索。目前已有821人浏览学习适合雷达信号处理课程设计、考研复试或工程入门者快速建立从理论到仿真的整体框架也可作为高校仿真报告撰写的参照范本。1. 随机信号处理仿真报告看起来像作业其实是系统工程一份随机信号处理仿真报告表面上是课程作业实际上是把你对一个随机过程的全部理解压缩成一段可运行、可复现、可检验的代码。很多人在这一步被“随机”两个字卡住生成的序列不像随机信号功率谱估计曲线抖成噪声滤波器系数加进去之后波形直接飞掉。出这些问题的原因不是代码能力不够而是没有把采样率、帧长、窗函数、随机种子和蒙特卡洛次数当成一个完整系统来设计。无论是做通信仿真、雷达回波模拟还是设备噪声分析这套思路都是通的。下面从理论模型讲起给出一个可以在 Python 或 MATLAB 里直接改参数的实现路径并把最容易让结果失真、甚至仿真发散的几个坑单独拎出来说清楚。2. 随机信号处理仿真的数学底子与工具选择2.1 仿真报告真正要回答的三个问题随机信号处理仿真不是“生成几个随机数画张图”交差。它要回答的是三个问题信号本身的统计特性是否被正确建模从有限样本估计出来的均值、自相关、功率谱是否接近理论值经过滤波、检测或谱估计处理之后系统的增益和误差是否符合预期。这三个问题贯穿整份报告决定了你选什么模型、跑多长数据、做几次平均。2.1.1 随机信号凭什么可以被仿真随机信号在物理世界是真实存在的但在计算机里只能靠伪随机数发生器来逼近。伪随机数序列一旦确定种子后续结果完全可复现这对仿真报告极其重要同一个随机信号跑两遍结果不一样评审根本无法验证。所以你需要在报告开头就说明随机种子和生成器类型。另一个关键假设是各态历经性。大多数教科书里的随机过程理论都是用集平均定义的但实际仿真里只有一条有限长样本。如果过程平稳且各态历经就可以用一条样本的时间平均去估计集平均。仿真报告里最常见的错误就是样本长度不足把时间平均出来的结果当成了理论值误差大却不知道原因。2.1.2 必须写进报告的三个统计量随机信号处理的核心是均值、自相关函数和功率谱密度。自相关描述信号在不同时刻的相关程度功率谱密度是自相关的傅里叶变换。对仿真而言你是在用“估计值”去逼近“理论值”所以报告里除了画出估计曲线还要叠加理论曲线以及置信区间。2.2 常用随机信号模型与适用场景仿真报告里不可能把所有随机过程都做一遍通常围绕四类模型展开。白噪声模型最简单它的功率谱平坦自相关只在零延迟处非零适合做系统噪声底。带限噪声是白噪声通过滤波器后的产物在通信仿真和雷达回波模拟里更接近实际。正弦加噪声模型用来检测正弦信号在噪声中的可检测性是功率谱估计最经典的验证场景。AR 模型则能通过少量系数生成具有特定谱形的时间序列适合模拟窄带干扰。这四种模型看起来差别很大但实现路径是统一的先用伪随机数生成高斯白噪声序列再通过滤波或叠加确定性信号得到目标随机过程。很多人在这个环节直接把 MATLAB 的randn当成万能工具没有想过randn只是高斯白噪声的样本并不包含“带限”“相关”等信息。2.3 工具选型Python 还是 MATLAB对比维度Python NumPy/SciPyMATLAB代码可读性较好语法接近自然语言较好但矩阵操作符号多信号处理函数scipy.signal 覆盖大部分需求有专业工具箱使用方便蒙特卡洛批量跑容易并行和循环循环较慢需要向量化报告集成借助 Jupyter 和 Matplotlib依赖 publish 或导出图片许可成本开源任意环境可复现有版权限制我一般选 Python。原因是随机信号处理仿真大量涉及参数扫描和多次试验Python 写起来更紧凑也不会受工具授权限制。如果是学校实验室指定用 MATLAB原理完全一样只需要把np.fft.fft换成fft把scipy.signal.welch换成pwelch。下面的实现全部用 Python 写方便直接改参数复现。3. 用 Python 跑通随机信号处理仿真最小闭环3.1 最小代码骨架从白噪声到功率谱估计先写一个最基础的流程生成高斯白噪声、去直流、估计自相关、画出功率谱。这一段代码解决的是“像不像随机信号”的问题。import numpy as np from scipy import signal import matplotlib.pyplot as plt fs 1000 # 采样率单位 Hz T 1.0 # 采样时长单位 s N int(fs * T) # 采样点数 rng np.random.default_rng(42) # 固定随机种子保证可复现 x rng.normal(0.0, 1.0, N) # 生成标准高斯白噪声 x x - np.mean(x) # 去直流消除均值偏移这段代码里default_rng(42)是 NumPy 1.17 之后推荐的随机数接口42 是种子。固定种子之后报告里每一个波形和曲线都可以被读者重新跑出来。采样率 1000 Hz、时长 1 秒意味着只用了 1000 个样本这个数量对功率谱估计来说偏少后面会讨论应该如何增加。接着估计自相关函数。注意使用有偏估计否则算出来的谱可能出现负值。def estimate_acf(x, max_lag100): n len(x) x x - np.mean(x) # 再次去直流避免均值干扰 acf np.correlate(x, x, modefull)[n-1:nmax_lag] # 取正延迟部分 acf acf / n # 有偏估计 return np.arange(max_lag), acfnp.correlate的full模式返回完整相关序列取n-1:nmax_lag得到从零延迟开始的非负部分。除以 n 而不是除以n-max_lag就是有偏估计虽然会带来一定偏差但方差更小也更常见。功率谱估计不要直接用np.fft.fft对整段数据一次变换而应该用 Welch 方法重叠分段平均。这里用scipy.signal.welch一行完成。f, Pxx signal.welch(x, fsfs, nperseg256, noverlap128, return_onesidedTrue)nperseg是每段长度noverlap是段间重叠点数。重叠一半是最常见的配置能让相邻段之间的相关性降低平均出来的谱曲线更平滑但也会让频率分辨率略微下降。3.2 仿真正弦信号加噪声的标准场景随机信号处理报告里“正弦信号淹没在噪声中”是绕不开的案例。它用来验证一件事仿真程序能不能准确识别出已知频率的谱峰。f0 100 # 正弦信号频率单位 Hz A 1.0 # 正弦幅度 noise_std 0.5 # 噪声标准差 x_sin A * np.sin(2 * np.pi * f0 * t) noise_std * rng.normal(0, 1, N)这里信噪比约为 20 * log10(1/0.5) ≈ 6 dB属于比较明显的信号。为了减小频谱泄露先乘一个汉宁窗再算 FFT。w signal.windowing.hann(N) X np.fft.fft(x_sin * w) freq np.fft.fftfreq(N, 1/fs) plt.plot(np.fft.fftshift(freq), 20*np.log10(np.abs(np.fft.fftshift(X)))) plt.xlim(0, 200) plt.xlabel(频率 (Hz)) plt.ylabel(幅度 (dB))这一段里fftfreq计算的就是离散频率轴。乘汉宁窗会让主峰宽度变大一些但能有效压低旁瓣。注意如果只关心功率谱而不是幅度谱应该取|X|^2而且需要补偿窗函数带来的能量损失。补偿系数是窗函数的均方值w的mean(w**2)。3.3 设计滤波器并观察统计特性变化随机信号处理仿真的下一个层次是让信号通过一个线性时不变系统。常见做法是用巴特沃斯低通滤掉高频噪声再对比滤波前后的功率谱和方差变化。b, a signal.butter(4, 150/(fs/2), btypelow) # 4阶巴特沃斯低通 y signal.lfilter(b, a, x_sin) # 丢弃前 100 个点避开滤波器初始瞬态 y_valid y[100:]butter的第二个参数是归一化截止频率单位是奈奎斯特频率的倍数所以这里 150 Hz 对应 150/500 0.3。lfilter直接对整段数据滤波但输出起始段受初始条件影响数字滤波器在开始时有瞬态响应这段数据统计特性与稳态不一致。报告里如果要用滤波后的信号估计方差必须把这部分丢弃。滤波之后可以对比滤波前后的功率谱曲线观察高频成分是否被压制。如果想更精确应该用signal.sosfilt代替lfilter因为高阶直接型滤波器可能有数值稳定性问题。scipy.signal.butter默认输出传递函数形式4 阶问题不大但如果阶数超过 8最好换成butter(..., outputsos)并配合sosfilt。4. 随机信号处理仿真结果里的关键参数与坑4.1 五个必须先定下来的参数仿真报告里最怕的是“参数随手一写结果无法解释”。我在跑随机信号仿真时会先把下面这些参数确定下来再开始写程序。参数推荐值直接影响采样率 fs大于 2 倍最高关心频率留出余量频率混叠采样时长 T覆盖最低关心频率 10 个以上周期频率分辨率 1/TFFT 窗类型汉宁或汉明频谱泄露与旁瓣Welch 每段点数256 至 1024根据频率分辨率要求选功率谱方差与分辨率随机种子固定一个值如 42可复现性4.1.1 采样率和采样时长采样率决定能看到的最高频率采样时长决定频率分辨率。如果你要分辨 99 Hz 和 100 Hz 的两个相邻谱峰1 秒数据对应的分辨率只有 1 Hz根本分不开。这时候需要把时长加到 10 秒以上而不是单纯增加 FFT 点数。FFT 点在尾部补零不会提高真实分辨率只是把谱线画得更密。4.1.2 Welch 平均段数Welch 方法把长序列切成若干段并平均。段数越多功率谱曲线越平滑但频率分辨率越低。一个经验值是每段长度取 256 到 1024重叠 50%。如果你想观察窄带信号段数要尽量短如果你想获得稳定的噪声底段数要长一些。4.1.3 随机种子固定种子唯一缺点是被固定住的随机序列相当于“确定性的噪声”它只代表随机过程的一次实现。所以仿真报告里只放一条曲线是不够的应该在固定种子完成调试之后再换多个种子做蒙特卡洛平均。4.2 三个最容易让结果“不像随机信号”的坑4.2.1 频谱泄露与窗函数选择直接对截断序列做 FFT矩形窗的旁瓣会淹没你真正关心的弱信号。下面这段代码对比加窗和未加窗的差异x_rect x_sin[:256] x_hann x_rect * signal.windowing.hann(256) freq_1 np.fft.rfftfreq(256, 1/fs) spec_rect np.abs(np.fft.rfft(x_rect)) spec_hann np.abs(np.fft.rfft(x_hann))观察两个频谱的旁瓣高度你会发现矩形窗的旁瓣只比主瓣低约 13 dB而汉宁窗可以压到 31 dB 以下。仿真报告里如果只贴矩形窗结果弱正弦分量可能完全被旁瓣掩盖。注意加窗之后频谱幅度会变小需要乘以补偿系数否则谱峰幅度和真实幅度对不上。4.2.2 自相关估计的有偏性自相关估计用np.correlate时如果除以的是n - k得到的是无偏估计除以 n 是有偏估计。教科书里功率谱是自相关的傅里叶变换理论上无偏估计的谱更符合定义。但无偏估计在后面的延迟处方差特别大画出来的曲线像刺猬。工程上默认用有偏估计代价是谱峰会略微变缓。报告中如果两者混用功率谱面积和信号方差对不上很容易被评审问住。4.2.3 滤波器初始瞬态数字滤波器是从某个初始状态开始的lfilter默认初始状态为零。这会让输出前几百个点出现一段明显的起跳或衰减过程。顶到需要处理的信号上就变成了“假信号”。常见做法是丢弃滤波后序列的前半段或者用signal.lfilter的zi参数设置稳态初始状态。对付大阶数滤波器最好用sosfilt并用signal.sosfilt的zi做初始条件。4.3 仿真发散先查采样率和极点位置随机信号处理仿真里的“发散”通常不是数值溢出而是波形出现越来越大的振荡。这种现象一开始看起来像随机噪声但十几步之后变成固定频率的大信号。先检查采样率是不是低于奈奎斯特频率再检查滤波器极点的模是否接近甚至超过 1。在 Cadence 瞬态仿真里常见的不收敛问题很多也是因为初始条件或步长给错这里思路类似。poles np.roots(a) if np.max(np.abs(poles)) 1.0: print(滤波器不稳定极点模值超过 1)这条检查代码可以放在滤波器设计之后。如果报告里出现了发散画一下滤波器极点位置比反复调整输入信号更有用。还有一种情况是随机数表示范围不够randn理论上可能产生很大的值但概率极低。一旦碰到重新换种子或增加采样点数即可。5. 让随机信号处理仿真结果有说服力的验证技巧5.1 用理论曲线叠图来验证代码仿真报告里最有效的验证方法是把理论功率谱和实测估计画在一张图上。白噪声的功率谱理论上是平坦的幅度与噪声方差成正比。你可以在图里叠加这条水平线然后调 Welch 参数直到曲线在中频段贴近理论线。正弦加噪声场景下理论谱是冲激加噪声底仿真谱里表现为一个主峰加平坦底噪。如果主峰位置和输入频率差超过一个频率分辨率单元代码里大概率有频率轴或者采样率配错的 bug。5.2 蒙特卡洛平均法单条功率谱曲线始终是抖的这是随机过程的固有特性。报告里想要展示“估计算法确实有效”应该固定其他条件只更换随机种子重复 50 次把每次估计出的谱峰位置和幅度记录下来。然后计算均值和标准差并和理论值比较。这样得到的误差棒才有统计意义。f0_est [] for seed in range(50): rng np.random.default_rng(seed) x_cur A * np.sin(2 * np.pi * f0 * t) noise_std * rng.normal(0, 1, N) f_cur, P_cur signal.welch(x_cur, fsfs, nperseg1024) f0_est.append(f_cur[np.argmax(P_cur)]) print(np.mean(f0_est), np.std(f0_est))这段代码只有一个目的证明估计算法不是靠运气跑出来的。把均值误差控制在频率分辨率以内之后这份报告才真正有说服力。5.3 从单次波形到统计判据仿真报告的最后一层是判断准则。比如在正弦加噪声场景中除了画出频谱还可以设定检测门限统计 100 次实验中能够检测到正确谱峰的比例。这个比例就是检测概率它比单条波形更有说服力。我一般会报告两个数频率估计的均方根误差和检测概率。前者告诉读者算法准不准后者告诉读者算法稳不稳。最后留下一个小技巧在做蒙特卡洛时先固定一个种子把程序调通再换成多个种子跑批量否则程序日志全是噪声。本文还有配套的精品资源点击获取