简介:一份基于Simulink的AM、DSB、SSB调制解调仿真完整文档,面向通信工程与电子信息类学生,以及需要完成课程设计、期末实验的开发者。文档系统讲解三种调制的原理、带宽与解调方法,并给出Simulink建模流程,含调制信号5Hz、载波50Hz等具体参数,且对比了AM相干解调与包络检波、SSB滤波法与相移法。压缩包为单个doc文档,约390KB,按设计原理、Simulink建模、仿真结果、结果分析四部分组织,结构清晰。目前已有4772人学习浏览,是通信仿真类热门参考。文档在均值为0、方差为1的高斯白噪声条件下比较恢复波形与抗噪声性能,可帮助读者直观理解各类调制的特点、参数影响与系统优化思路。
1. 为什么我用 Simulink 做 AM、DSB、SSB 调制解调仿真而不是写代码
第一次接到“基于Simulink的AM、DSB、SSB调制解调仿真”这个题目时,我下意识想用 Python 直接写调制解调代码,结果被导师劝住:通信原理里最容易被忽略的频谱搬移、滤波器过渡带、载波同步误差,在纯代码里不直观,而在 Simulink 里能直接用 Scope 和 Spectrum Analyzer 看到每一级信号长什么样。后来我做过一次用来验收的课程设计,也帮 A 同学排查过一份可以运行的模型,发现大部分人卡住的不是“不会调”,而是“不知道哪一级信号该长什么样”。这篇笔记就按我自己的仿真习惯来写:从调制端三个方案的差异讲起,给出一套能复用的模块连接和参数配置,再落到解调端最现实的问题——滤波器参数和载波同步偏差。适合正在做通信课程设计、准备通信原理实验,或者想快速搭一套调制解调验证链路的从业者。
2. 把理论基础落成 Simulink 模块:AM、DSB、SSB 的调制端差异
2.1 AM 调制:直流偏置和过调幅,为什么仿真里一定要看包络
在 Simulink 里搭 AM 调制,最直接的方式有两个:用Product做乘法器手动搭,或者直接用DSB AM Modulator Passband这样的通信模块集。我推荐手动搭,因为这样能清楚看到直流偏置加在哪里,也方便控制调幅度的数值。
AM 的数学表达式是 s(t) = [A0 + m(t)] · cos(ωc t),其中 A0 是直流偏置,m(t) 是调制信号,cos(ωc t) 是载波。这里的核心参数是调幅度 ma,ma = max|m(t)| / A0。当 ma 小于等于 1 时,调制信号的包络和原信号成正比,接收端可以用包络检波直接解调;一旦 ma 大于 1,包络会削底,包络检波出来的波形会多出倒置成分,听起来和看起来都像“过调幅”。
在模块层面,我一般用Constant设置直流偏置 A0,用Sine Wave作为调制信号,用另一个Sine Wave作为载波,再用Product做乘法。关键不是模块多,而是怎么把调幅度调到目标值。比如想验证 ma=0.5 的常规调幅,调制信号振幅要设为 0.5·A0。实际调试时不要只盯公式,要在 Scope 里同时看三个信号:原始调制信号、[A0 + m(t)] 的时域波形、最终调制输出。只有当第三个信号的包络明显复现第一个信号,且波形的负半周没有触底时,AM 调制才是合格的。
值得一提的是,如果只是在 Simulink 里摆模块,默认会用变步长求解器,这对 AM 仿真问题不大,但会掩盖离散化带来的采样点不足问题。所以我习惯在模型里先放一个Zero-Order Hold,把连续信号变成固定步长信号,后面接滤波器时行为更可控,这也方便后续把模型转成代码时保持采样周期一致。
2.2 DSB 调制:抑制载波后,频谱里为什么只剩两个边带
DSB 的表达式是 s(t) = m(t) · cos(ωc t),和 AM 的唯一区别就是没有直流偏置 A0。去掉了载波分量后,频谱里只有上边带和下边带,载波频率位置被抑制。很多人在仿真时以为“没有载波就是载波为0”,这是错的。DSB 的意思是没有离散载波谱线,但并不是信号里没有 cos(ωc t) 这个乘法动作。
在 Simulink 里实现 DSB 非常简单:把 AM 链路里的Constant设为 0,或者直接拿Product乘两个Sine Wave,那就是 DSB。需要注意的一点是,包络不再直接反映 m(t) 的波形。因为 DSB 的输出过零时会发生相位翻转,示波器上看到的“包络”其实是 |m(t)| 的轮廓,会在调制信号过零处出现包络打结。如果这时候还想着用包络检波去解调,就一定会解出“双峰整流”的怪波形。
从仿真验证的角度看,DSB 正确与否要看频谱而不是时域。用Spectrum Analyzer观察输出信号频谱,如果看到载波频点处有一条明显谱线,说明模型里漏掉了什么,最常见的原因是常数模块的值不是0,或者乘法器的前级信号里带有直流分量。另一个容易被忽略的问题是信号源本身如果有直流偏置,也会在载波位置产生残留谱线。所以给调制信号做直流隔离是 DSB 仿真里的一个基本功。我用DC Block或者在信号源参数里直接把偏置设为0,都会在初始化脚本里写清楚。
DSB 的优点是功率利用率比 AM 高,所有功率都用于传输边带,缺点是接收端必须相干解调。如果载波不同步,解调输出的 m(t) 会乘上一个 cos(Δφ) 衰减因子,相位偏差90度时信号直接消失。这个特性在仿真里很容易复现,也是理解后续 SSB 解调困难的铺垫。
2.3 SSB 调制:希尔伯特变换和相移法,哪个更接近工程实现
SSB 只保留一个边带,频谱占用是 AM、DSB 的一半。在 Simulink 里有两条搭建路线:一是用滤波法,直接用带通滤波器滤掉一个边带;二是用相移法,生成两个正交信号再相加相减。我实际仿真中更推荐相移法,因为滤波法需要滤波器有极陡的过渡带,直接和“理想低通”较劲往往会得到一版幅度畸变严重的结果,而且滤波器的阶数一高,仿真时间立刻暴涨。
相移法的本质是把调制信号变成希尔伯特变换对。假设 m(t) 是实信号,那么需要构造 m(t) 和希尔伯特变换 m̂(t)。在 Simulink 里可以用Hilbert Transform Filter或者用MATLAB Function做希尔伯特变换,再把两个支路分别乘上同相载波和正交载波,最后相加得到上边带,相减得到下边带。
用相移法搭 SSB 时,调试顺序很关键。我一般先把两条支路分别拉出来看,确认希尔伯特变换得到的信号幅度没有异常衰减,再进入乘法器和加法器。很多人直接搭完整链路,一看到输出不对就怀疑模块或采样时间,实际上问题可能只是希尔伯特滤波器的阶数不够,导致高频分量幅度明显降低。尤其在调制信号带宽比较高时,希尔伯特滤波器需要在通带内平坦,这就要在模块参数里把滤波器阶数从默认值往高调,同时观察频谱确认。
SSB 和 DSB 在频谱上最直观的区别是:SSB 频谱关于载波不再对称,只有一侧有边带。用复信号表示更容易理解,但 Simulink 的Spectrum Analyzer对实信号显示双边谱,最好先把输出信号用Real-Imag to Complex转成复信号,或者直接把载波频率设得足够高,让正负频谱在显示界面里分得开。
参数对比表:调制端三个方案的 Simulink 落地要点
| 方案 | 模块组合 | 关键参数 | 调试重点 |
|---|---|---|---|
| AM | Constant + Product + 两个 Sine Wave | A0、ma | 观察包络,避免 ma>1 |
| DSB | Product + 两个 Sine Wave | 调制信号直流偏置=0 | 看频谱无载波谱线 |
| SSB | 相移法(Hilbert + 两路乘法 + 加/减) | 希尔伯特滤波器阶数、载波正交偏差 | 对比两条支路幅度,看单边带 |
3. 在 Simulink 里搭出可复现的调制解调仿真链路:从信号源到示波器
3.1 搭建 AM 调制解调的最小仿真链路:模块连接与参数设置
我比较反感那种“把所有模块拖进模型就完事”的教程,因为真正能复现的模型一定依赖一套明确的参数。这里给出一版我最近在用的 AM 最小链路配置:调制信号用频率 fm=1kHz 的正弦波,载波频率 fc=50kHz,采样时间 Ts=1/200kHz,也就是载波频率的4倍采样。这个倍数不是随便定的,后面在讲解调滤波器的时候会解释为什么 4 倍只是一个起点。
模块连接顺序是:Sine Wave(m) →Add(加入 DC Constant) →Product→Analog Filter Design(低通) →Scope。这里的Analog Filter Design不是必须的,但它能模拟信道中的带宽限制。为了让“解调后恢复信号”有意义,我会在调制输出后串一个小截止频率的低通,避免高频噪声进入解调端。
初始化脚本写在 MATLAB 端,模型里每个模块的参数用变量引用。这样改参数只需要改一个脚本,不用在模型里到处点。常见的初始化脚本结构如下:
% 初始化脚本:AM_DSB_SSB_params.m fs = 200e3; % 采样频率,单位 Hz,200kHz Ts = 1/fs; % 采样时间,单位 s fm = 1e3; % 调制信号频率,单位 Hz fc = 50e3; % 载波频率,单位 Hz A0 = 1; % AM 直流偏置,调幅度调整用 Am = 0.5; % 调制信号振幅,此时 ma = Am/A0 = 0.5 Amp_c = 1; % 载波振幅 % 低通滤波器:信道带宽限制,防止噪声混叠 chan_filter_order = 4; chan_filter_fc = 5e3; % 信道带宽 5kHz逻辑说明:这里把所有关键频率和幅度都提到脚本顶部,模型里只写 fs、Ts 这样的变量名。好处是后面改载波频率、改成 DSB 时不需要在 Simulink 里逐个模块找参数。参数说明:采样频率 fs 和建议最基础的载波频率比不要低于 4,否则频谱显示会混叠;调制信号频率控制在载波带宽内;调幅度 ma 用 Am/A0 计算,我习惯把 A0 固定为 1,这样 Am 的数值就是 ma。
写完脚本后在 MATLAB 工作区直接运行,再用 Ctrl+D 让模型参数从工作区刷新,Simulink 里所有引用同一变量的模块会同步更新。这一步经常被忽视,但它是“可复现参数”的核心。
3.2 给 DSB 和 SSB 复用同一链路:开关切换与参数表
同一个模型里把 AM、DSB、SSB 都跑起来,有两种做法。一种是把每个方案的完整链路都画出来,再用Manual Switch切换;另一种是把不同方案封装成子系统,外面留一个选择变量。我在课程设计里用的是第二种,因为子系统可以把内部乱七八糟的导线收起来,答辩时看的人也更容易找到重点。
子系统划分我按“信号源 → 调制器 → 信道 → 解调器 → 分析显示”来做。其中调制器可以是三种方案的任意一种类型,通过一个外部变量MOD_TYPE来切换子系统的内部开关。这个变量定义在初始化脚本里,初始化为'AM'、'DSB'、'SSB'中的一个。
% 调制方案选择 MOD_TYPE = 'SSB'; % 可改为 'AM' 或 'DSB'当模型里需要根据这个变量选择不同模块时,不能直接让模块“消失”,但可以用Variant Subsystem来实现多条实现路径互斥激活。这个方案的好处是编译之后只有当前选择的那个分支参与仿真,不会让另外两个分支也消耗计算资源。需要说明的是,Variant Subsystem的配置稍微有一点弯弯绕绕:先建一个空子系统,右键选择Variant Choices,关联到两个或三个不同子系统,每个子系统分别对应 AM、DSB、SSB 的调制实现。之后在模型工作区里给MOD_TYPE赋值,模型会自动选择对应分支。
如果你只是做仿真演示而不用跑成大模型,我建议直接用Manual Switch简单切换,速度更快,也免得在变体子系统上踩版本兼容的坑。参数表如下:
| 模型组件 | AM 分支 | DSB 分支 | SSB 分支 |
|---|---|---|---|
| 信号源 | Sine Wave,Am=0.5 | Sine Wave,Am=0.5 | Sine Wave,Am=0.5 |
| 直流偏置 | Constant=1 | 0 | 0 |
| 乘法器 | Product 与载波相乘 | Product 与载波相乘 | 同上,但有两路正交载波 |
| 希尔伯特变换 | 无 | 无 | Hilbert Transform Filter,阶数默认或适当增加 |
| 输出信号预期 | 有载波、双边带 | 无载波、双边带 | 无载波、单边带 |
这张表看起来简单,但真正能跑出正确波形的人还不多,原因是不同分支的采样时间必须完全一致。比如 AM 分支里载波模块的采样时间写成Ts,DSB 分支里载波模块的采样时间也要写成Ts,不能一个用1/fs、一个用0.001。仿真步长不一致时,输出信号的频谱会在同一频点出现若干根杂散谱线,排查起来非常费劲。
3.3 仿真时间与采样频率的设置:先看频谱再调步长
很多同学把仿真时间直接默认成 10 秒,结果 Scope 里的波形密密麻麻什么都看不清。我一般根据调制信号的周期来设,仿真时长取 5 到 10 个调制信号周期。例如 fm=1kHz,那么仿真时长设 0.01 也就是 10 个周期,足够看清包络。载波频率是 50kHz,10 个调制周期里包含 500 个载波周期,示波器上仍然能看出载波填充形状,恰到好处。
频谱分析时仿真时间可以适当加长,因为频谱分辨率等于 1/仿真时长。如果你把仿真时间设置成 0.01 秒,频谱分辨率只有 100Hz,载波 50kHz 旁边的边带间隔 1kHz 倒是能分开,但边带附近的细节会糊。想要看到更干净的边带结构,可以把仿真时间加大到 0.05 或 0.1 秒,再用Spectrum Analyzer,注意这时候 Scope 里的波形会挤密一些,二者不可能同时完美。
这里还有一类隐含参数,叫“求解器步长”。使用默认变步长时,Simulink 会自适应调整步长,可能在载波快速变化区间把步长缩得很小,导致仿真数据量非常大。固定步长时反而容易预测,我一般用ode1(欧拉法)或ode4(四阶龙格库塔),步长设为Ts。不要为了让仿真跑得快把步长放大到 1e-4,那样载波一个周期只有 5 个点,解调后波形必然严重失真。实际判断标准是:频谱分析仪里的波形没有明显混叠毛刺,且时域包络光滑。
4. 解调端设计与滤波器参数:从相干解调到包络检波
4.1 包络检波只适合 AM,DSB/SSB 必须相干解调
解调端的设计比调制端更考验对原理的理解。AM 可以用包络检波,这是因为它保留了直流偏置,包络就是调制信号的形状。在 Simulink 里搭包络检波,最常见的是用Abs取出绝对值,再接一个低通滤波器滤掉载波分量。也可以直接用Envelope Detector模块,但它在某些版本里需要额外安装通信工具箱,没有的话用Abs + 低通更稳妥。
包络检波有一个内在前提:调制信号的最高频率要远低于载波频率,低通滤波器的截止频率要落在两者之间。如果载波是 50kHz、调制信号最高频率 5kHz,那么低通截止频率取 10kHz 到 15kHz 都是合理区间。低于 5kHz 会把有用信号一起滤掉,高于 50kHz 则载波残波滤不干净。这个经验范围可以在仿真里试出来,但更建议用Spectrum Analyzer看解调输出的频谱,观察是否有明显载波剩余。
DSB 和 SSB 就不能用包络检波了。DSB 的信号过零时会发生相位翻转,直接取绝对值等于是做全波整流,会把倒置的包络再翻上来,解调结果变成“双倍频率”的畸变信号;SSB 没有双边带对称性,包络检波出来的东西几乎没有可用信息。所以 DSB/SSB 要用相干解调:接收端产生一个和发送端同频同相的载波,与接收信号相乘,再过低通滤波器。
相干解调的 Simulink 链路是接收信号 →Product与本地载波相乘 →Analog Filter Design低通滤波 → 再接一个增益补偿。本地载波用Sine Wave产生,频率必须等于发送端载波频率,初始相位也要对齐。如果模型里发送端载波相位是 0,接收端也用 0,那就能得到最理想的结果。实际通信里不可能完全同步,所以我要在仿真里故意加入相位和频偏,用来说明同步误差的影响。
4.2 低通滤波器截止频率怎么定,才能让解调信号不塌陷
相干解调乘法器的输出里包含两部分:基带分量(调制信号的若干倍)和二倍载频分量。低通滤波器的作用是把二倍载频分量滤掉,同时保留基带分量。因此截止频率的上限是 fc,下限是调制信号最高频率。听起来很简单,但实际仿真里“滤干净”和“保得住”是一对矛盾体。
以一个实际配置为例:调制信号频率 fm=1kHz,载波 fc=50kHz,乘法器输出里的两个分量分别在 1kHz 和 100kHz(也就是 2·fc ± fm)。低通滤波器截止频率设成 20kHz 会很安全,但如果你想看解调后信号的带宽是否被压缩,20kHz 显然不理想。对于单音测试信号,截止频率 5kHz 到 10kHz 都可行,对于带限语音信号,则要根据语音带宽来选。我常设的规则是:
- 截止频率 ≥ 2×最高调制频率,留出过渡带余地;
- 截止频率 ≤ 载波频率/5,确保二倍载频分量被大幅衰减;
- 滤波器阶数不低于 4 阶巴特沃斯,避免过渡带太宽;
- 如果需要更陡的过滤效果,选
Chebyshev Type I或直接提高阶数,但要警惕通带纹波。
参数设置放在脚本里,可以用fdesign.lowpass生成系数:
% 解调低通滤波器参数 f_pass = 2 * fm; % 通带截止频率,2kHz f_stop = fc / 5; % 阻带起始频率,10kHz,留出过渡带余量 filter_order = 8; design_data = fdesign.lowpass('N,Fp,Fst', filter_order, f_pass, f_stop, fs); lpFilt = design(design_data, 'butter');这段代码生成一个 8 阶巴特沃斯低通滤波器,通带到 2kHz,阻带从 10kHz 开始。逻辑说明:我特意把通带截止频率设为 2 倍调制频率,是因为滤波器过渡带不是一条竖直线,如果通带只到 1kHz,由于过渡带实际会衰减一部分 1kHz 附近的成分,解调输出幅度会明显减小。参数说明:f_pass和f_stop之间的宽度决定了过渡带陡峭程度,这里 2kHz 到 10kHz 的宽度足够宽,滤波器阶数不需要很高就能稳定。如果你后续要处理实际语音信号,需要把fm换成语音信号的最高频率,比如 4kHz,那么f_pass相应提高到 8kHz 左右。
在 Simulink 里用滤波器系数有两种方式。简单方式是把Analog Filter Design模块的 “Filter type” 设成Lowpass,然后把“Passband edge frequency”和“Stopband edge frequency” 直接填成上一步计算出的数值。更灵活的方式是用Digital Filter模块,把lpFilt这个对象作为参数填进去。我推荐第二种,因为在 MATLAB 里可以同时绘制幅频响应,确认滤波器的频率响应曲线与你预期一致,避免在 Simulink 里试错。
4.3 载波同步误差对 SSB 解调的影响:频偏和相偏的观察方法
相干解调最理想的情况是本地载波频率和相位完全对齐。实际仿真中,为了演示同步误差,我发现很多教材只会说“有误差会恶化”,但不会告诉你怎样在 Simulink 里设置出这种误差。做法其实很简单:把接收端载波模块Sine Wave的频率参数写成fc + delta_f,相位参数写成delta_phi,然后在 MATLAB 工作区里给这两个变量赋值。
% 载波同步误差设置 delta_f = 100; % 频率偏差,单位 Hz delta_phi = 10; % 相位偏差,单位 degree,换算成弧度用 deg2rad对于 DSB 和 SSB 解调,相偏的影响主要体现在输出幅度上。假设本地载波相位比发送端落后 φ,相干解调后的基带信号会乘以 cos(φ)。也就是相偏 30 度时输出幅度约剩 0.866,相偏 90 度时输出接近零。这是很多人做 SSB 解调仿真时发现信号“消失”的原因,不是模型连接有误,而是相位没对准。
频偏的影响则更隐蔽。如果本地载波频率比发送端高了 100Hz,那么在乘法器输出里,基带信号会被搬移到 100Hz 的位置,而不是 0Hz。你会在频谱仪上看到整个基带信号整体偏移了 100Hz,听起来像“变调”,时域波形则还是正弦但频率变了。对单音信号,这个现象容易被当成“信号频率变了”,对语音信号则会变成明显的机器人声。
观察这些误差有个实用技巧:把解调链路的输出频谱图和原始调制信号频谱图叠在一起看。如果基带信号在低频部分应该落在 1kHz 处,而解调输出谱线落在 1.1kHz,那么频偏就是 100Hz。如果频谱位置正确但幅度变小,那么多数是相偏或滤波器衰减,可以先用脚本算一下理论幅度,再对比仿真值。
5. 避坑与常见问题:仿真结果不对时的排查路线
5.1 现象:频谱里看不到双边带,只有一根载波
刚搭完 AM 链路时,我在Spectrum Analyzer里看到输出只有载波那一根谱线,边带完全看不到。当时第一反应是示波器设置问题,后来才发现是调制信号频率和幅度都太小,边带功率比载波低了 40 多分贝,被频谱仪的显示范围“压”掉了。原因也不复杂:频谱仪默认对数坐标,如果幅度轴不从 -80dB 开始看,边带就会被淹没在噪声底里。
解决方法是先确认时域波形里有明显的包络,然后用频谱仪把纵轴范围调到 -80dBm 到 -10dBm 这个区间,再调整中心频率到 fc 附近。另外,把调制信号振幅调大,比如 Am 从 0.1 改成 0.5,边带幅度大约提升 14dB,频谱上立刻清楚可见。如果时域有包络但频谱还是单根,再检查载波频率是否被不小心设置成调制频率,这种低级错误我也见过。
5.2 现象:解调波形包络是双峰,且和原信号差很远
用包络检波解调 DSB 时,得到的波形会是一个频率为两倍原始信号频率的整流波形。之前辅助排查过一个同学的模型,他直接把 AM 的包络检波链路拿去解调 DSB,Scope 里看到两个“驼峰”,还以为是滤波器参数不对。
原因很清楚:DSB 在半周期的相位翻转让包络检波器把负半周也翻上来了。解决办法是改用相干解调,即插一个本地载波乘法器,再接低通。要确认是否真的是这个问题,可以把乘法器之前的信号直接拉到 Scope 里看,如果输出波形中间能看到明显的相位翻转点,那就可以下结论。另外,如果使用的是Envelope Detector模块,输出和理想包络差很多时,先检查模块内部是否默认添加了直流偏置,有些版本会自动把输入信号加偏置。
5.3 现象:SSB 解调出来有啸叫或直流偏置
SSB 解调后的“啸叫”通常来自两处。第一处是本地载波的频率偏差。比如接收端载波比发送端低 200Hz,那么解调输出会把原始信号整体往下搬移 200Hz,单音信号听起来就是一个频移后的声音,而非正弦的原始频率。第二处是滤波器没滤干净,二倍载频分量进入输出,表现为一个高频残波,听感上像“滋滋”声。
直流偏置也常见。如果 SSB 是用相移法搭的,希尔伯特变换滤波器在低频端会有相位误差,导致两条支路幅度不一致,最终加法器输出里会残留部分载波分量。解决办法是在解调低通后加一个DC Block或者把低通滤波器改成带通,把 0Hz 附近的直流去掉。注意直流是频谱上 0Hz 处的谱线,用DC Block是通用做法。
5.4 现象:波形毛刺多,改变步长就消失
有人把固定步长从 1/200000 改成 1/50000 后,解调波形边缘出现明显毛刺,一开始以为是滤波器不稳定。其实这就是采样不足导致的高频混叠。当步长变大,载波每周期只采 1 个点,恢复出来的包络像锯齿,频谱上会叠出很多混叠分量。
解决办法有两个。一是提高采样频率,至少让载波每个周期有 10 个采样点。对于 50kHz 载波,fs 至少 500kHz,推荐 1MHz,这样解调后的波形边缘更光滑。二是调整 Scope 里的显示采样,把 Scope 数据显示点数降低,避免显示时过度抽取。但治标不治本,固定步长仿真还是建议按“载波每周期 10 个点”来定,别为了图快牺牲波形质量。
5.5 现象:滤波器参数明明按公式算的,解调还是不对
最后这条最坑。我给解调滤波器用fdesign.lowpass生成系数后,在Digital Filter模块里直接填变量lpFilt,仿真结果却完全不按预期衰减。后来才发现,Digital Filter模块里的采样频率和模型求解器步长不是一回事。滤波器系数是基于 fs=200kHz 设计的,但模型里的信号在进入滤波器之前被Zero-Order Hold变成了另一个采样率,两边的采样率不匹配,滤波器实际生效范围就完全变了。
解决方方案是确保链路上每一级信号的采样率一致。我会在模型里用Display模块显示每个信号采样率,或者用Sample Time标注颜色检查。启用 Simulink 工具栏里的 “Sample Time Colors” 功能,不同采样时间的信号会显示不同颜色,非常直观。如果发现滤波器前后的信号颜色不同,就要在滤波器模块参数里设置与前后一致的Sample time,或者在滤波器前重新采样到统一频率。
6. 用信噪比和频谱纯度验收,再叠加真实语音信号
仿真搭到能跑通只是第一步。我接手过的项目问题大多出在“看着能跑,但量化下来性能很差”。这里给出一套我常用的验收流程,不需要额外工具箱,只用 Simulink 自带测量模块和 MATLAB 脚本就能完成。
第一步,把解调输出和原始调制信号分别导出到工作区,用snr函数计算解调信号的信噪比。具体做法是在模型末尾放一个To Workspace模块,保存变量demod_signal,再在脚本里配合原始信号m(t)做对齐和误差计算。注意 Simulink 仿真输出默认带时间向量,要和原始信号做对齐,通常要截掉仿真开头的暂态段,比如前 1ms 的波形不稳定,先切除再算信噪比。
% 验收脚本:计算解调信号 SNR 和 EVM load_system('modem_sim'); out = sim('modem_sim', 'StopTime', '0.1'); demod = out.demod_signal(1000:end, 2); % 去掉前1000个点,避开暂态 orig = out.original_signal(1000:end, 2); snr_demod = snr(demod - mean(demod), orig - mean(orig)); evm = rms(demod - orig) / rms(orig) * 100; fprintf('解调 SNR = %.2f dB, EVM = %.2f%%\n', snr_demod, evm);这段代码里out.demod_signal(1000:end, 2)的取法,是因为在To Workspace默认输出是带时间戳的矩阵,第一列是时间,第二列是信号。逻辑说明:先减直流再算 SNR,因为解调链路难免有直流偏置,直流分量会干扰 SNR 计算。参数说明:切掉前 1000 个采样点是为了躲开滤波器的建立阶段,具体的截断点数取决于滤波器的阶数和截止频率,阶数越高,暂态越长。
第二步,用Spectrum Analyzer直接看解调输出频谱。只验证时域波形不够,要确认在二倍载频位置没有明显滤波残差,原始信号频带内的频谱形状和原信号一致。如果 SNR 很高但 EVM 大于 10%,多半是滤波器相位失真导致的波形畸变,而不是随机噪声。
第三步,把单音信号换成本地录入的真实语音或一段带限噪声,重复上面两条链路。语音信号不是纯正弦,包络起伏大,对 SSB 相移法两条支路的幅度一致性要求更高。很多单音信号能通过的模型,一换语音就露馅。用语音信号测试时,把Spectrum Analyzer的窗口类型从默认矩形窗改成汉明窗,能够减少频谱泄漏,更容易看清边带是否被保留完整。
我自己的习惯是每一版仿真都保留一个参数快照文件,包括调制类型、载波频率、采样频率、滤波器阶数和截止频率、最终 SNR 和 EVM。这样后续跑不同业务场景时,不用重新摸一遍参数,直接对照快照调整。有一次在给某跨平台系统做预研时,我把端到端语音业务切换成带限信号,结果省了一下午的返工时间。所以请你也从第一次仿真开始就养成参数留痕的习惯,这比任何技巧都实用。希望帮到你。
本文还有配套的精品资源,点击获取