MATLAB Simulink信道仿真源码解析:AWGN与瑞利衰落建模
简介面向通信系统建模与仿真学习者的MATLAB Simulink源码与信道模型包聚焦AWGN、Rayleigh衰落、多径传播等信道建模与仿真实现适合通信工程专业学生、算法工程师及对Simulink仿真实战有需求的开发者参考。压缩包共22个文件包含12个.m脚本、4个.mat数据文件、2个.slx模型文件及配套的.slxc缓存与xml配置整体仅62KB结构紧凑.m脚本提供调制、信道及误码率分析等仿真代码.slx模型可直接打开观察模块连接与参数设置。已有600人学习浏览。通过阅读源码与运行模型可直观理解通信链路中信号发送、信道影响与接收处理的过程掌握AWGN、Rayleigh模型的搭建方法并基于自带数据或仿真结果分析误码率、信噪比等系统性能为后续自定义信道模型与通信系统优化提供可复用的参考实现。1. 从 AWGN 到瑞利这套信道仿真代码包里到底有什么拿到详解MATLAB Simulink通信系统建模与仿真 源码 信道.zip解压后第一眼会觉得文件有点乱awgn_1.m到awgn_4.m、AWGNchanel_6.m、AWGNchanel_7.m、rayleigh_9.m、rayleigh_10.m、duojing_8.m外加awgnmodel.slx和awgnrayleighmodel.slx两个 Simulink 模型以及slprj、sim这些自动生成的缓存目录。但把这些文件按名字归类后实际上就是一条完整的学习路线AWGN 信道建模、Rayleigh 多径衰落信道建模、两者在 Simulink 中的图形化实现以及配套的 MATLAB 脚本验证。对通信方向的学生、刚接触物理层仿真的工程师来说这套代码的价值在于它把「理论公式」和「可运行的仿真模型」对应起来了解决了最常遇到的问题知道 AWGN 信道公式怎么推导但不知道在 Simulink 里参数该填多少、脚本里噪声方差怎么算。2. 信道模型的数学底子AWGN 与瑞利衰落为什么放在一起学2.1 AWGN 信道噪声功率、信噪比和仿真中真正的输入参数加性高斯白噪声Additive White Gaussian Noise是所有信道模型里最容易实现、也最容易理解错误的。它的数学定义是接收信号 ( r(t) s(t) n(t) )其中 ( n(t) ) 是单边功率谱密度为 ( N_0 ) 的高斯白噪声。但落到 MATLAB 脚本里你不能直接设置 ( N_0 )你需要设置的是噪声方差。对 BPSK 调制的基带等效模型每个符号的噪声方差与 Eb/N0 的关系是[ \sigma_n^2 \frac{N_0}{2} \frac{1}{2 \cdot k \cdot (E_b/N_0)} ]其中 ( k \log_2(M) )M 是调制阶数。BPSK 时 k1QPSK 时 k2。这个公式在awgn_1.m这类脚本里会反复出现很多人直接把 randn 的标准差设为 1然后在信道输出端乘一个衰减系数这是不对的因为 randn 产生的是单位方差噪声你需要根据目标 SNR 反推方差而不是把噪声功率固定后再改变号幅度。Simulink 里的 AWGN Channel 模块对此做了封装它提供了三种参数模式Signal to noise ratio (Eb/N0)、Signal to noise ratio (SNR)、Variance from mask。前两者需要你额外指定信号功率和符号周期第三种直接把方差写在模块参数里。从工程角度我建议脚本里用 Eb/N0 模式因为它把调制阶数 k 和每个符号的能量都考虑进去了比对 SNR 手动换算要少一步出错的可能。2.2 瑞利衰落多径、时延扩展和多普勒频移的物理含义瑞利衰落信道描述的是信号在传播过程中遇到建筑物、地面等散射体经过多条路径到达接收端且没有直射路径LOS的情况。接收信号包络服从瑞利分布相位服从均匀分布。Simulink 的 Rayleigh Fading Channel 模块和 MATLAB 的comm.RayleighChannel系统对象都实现了这个模型但它们的参数不是直接让你输入衰落因子而是让你输入多径物理参数。三个关键参数分别是路径时延PathDelays单位秒指各条多径相对第一条路径到达的时间差。典型城区环境时延扩展在几百纳秒到几微秒之间。平均路径增益AveragePathGains单位 dB指每条路径的平均功率相对第一条路径的衰减。第一条路径通常是 0 dB后续路径衰减逐渐增大。最大多普勒频移MaximumDopplerShift单位 Hz由移动台速度和载波频率决定公式是 ( f_d v \cdot f_c / c )v 是移动速度( f_c ) 是载频c 是光速。4G/5G 通信里 2.1 GHz 载频、120 km/h 移动速度对应的多普勒频移大约是 233 Hz仿真时一般取整到 100 Hz 或 200 Hz 就能看出误码率曲线的明显差异。2.3 Simulink 模块参数与物理模型的对应关系把理论映射到模块参数是这套源码里最容易踩坑的地方。awgnrayleighmodel.slx之所以叫这个名字是因为它在一条链路上同时串联了 AWGN 和 Rayleigh 两个信道模块。AWGN 处理的是热噪声瑞利处理的是多径衰落两者物理机制不同所以不能合并成一个模块只能串联。下表列出我在打开这两个模型进行参数检查时的常用配置基准这套参数和 R2020b 之后的版本默认配置兼容模块参数项推荐初值说明AWGN ChannelModeSignal to noise ratio (Eb/N0)用 Eb/N0 而非 SNR避免调制阶数换算误差AWGN ChannelEb/N0 (dB)1010 dB 下 BPSK 理论 BER 约为 3.9e-6适合肉眼验证AWGN ChannelNumber of bits per symbol1BPSKQPSK 改成 2AWGN ChannelInput signal power (watts)1与发送端 Signal From Workspace 幅度设置对应Rayleigh FadingMultipath number3三条路径典型城区模型Rayleigh FadingPath delays (s)[0 0.3e-6 0.7e-6]时延间隔越小频率选择性越弱Rayleigh FadingPath gains (dB)[0 -3 -6]按指数衰减近似Rayleigh FadingMax Doppler shift (Hz)100对应低速移动场景这里特别提醒一个细节Rayleigh 模块的输入信号功率假设是 1 瓦如果你在前面接了增益模块把信号幅度放大到了 2 或 0.5瑞利模块内部的衰落乘性因子不会自动归一化输出信号的 SNR 会被改变。所以要么保持整个链路信号功率为 1要么在瑞利模块之后加一个 normalize 模块做功率归一化否则你会看到误码率曲线整体偏移 2~3 dB。3. Simulink 模型构成awgnmodel.slx 与 awgnrayleighmodel.slx 的模块拓扑3.1 基础链路从信号源到误码统计的完整闭环打开awgnmodel.slx可以看到一条完整的发送-信道-接收链路。这条链路的拓扑在数字通信仿真里几乎是标准模板伯努利二进制源生成比特BPSK 调制器完成比特到星座点的映射AWGN 信道叠加噪声接收端用符号判决恢复比特最后通过 Error Rate Calculation 模块统计误码率。这个模型里最值得看的是信号源和信道模块的衔接方式。伯努利二进制生成器Bernoulli Binary Generator的 Sample time 参数要设置成和符号周期一致。如果调制方式是 BPSK一个符号对应一个比特那么 Sample time 就是符号周期如果是 QPSK则需要在调制器之前接一个 Serial to Parallel 转换器把比特流两两分组。awgnmodel.slx默认是 BPSKSample time 设为 1e-4即符号速率 10 kbps。信号从 0/1 比特映射为 1/-1 幅度后功率正好是 1 瓦这与 AWGN 模块里 Input signal power1 的设置是对应的。Error Rate Calculation 模块的输出有三个端口误码率数值、错误比特数、仿真总比特数。可以接一个 Display 模块实时显示也可以把输出存到 Workspace供脚本在仿真结束后读取并画 BER 曲线。整个模型的运行截止时间设在 100000 个符号对 1e-4 秒的符号周期仿真时间是 10 秒的仿真时间实际运行不到两秒。3.2 瑞利-多径模型awgnrayleighmodel.slx 的差异化设计awgnrayleighmodel.slx在awgnmodel.slx的基础上插入了一个 Rayleigh Fading Channel 模块位置在调制器和 AWGN 信道之间。这个插入顺序是有讲究的先过瑞利多径再加高斯白噪声。因为物理上多径衰落是信道对信号的乘性干扰而热噪声是加性干扰乘性干扰必须先作用在信号上再加噪声这样得到的接收信号才是[ r(t) h(t) * s(t) n(t) ]其中 ( h(t) ) 是瑞利信道的冲激响应* 表示卷积。如果你把 AWGN 模块放在前面让信号先加噪再通过瑞利模块噪声会同样被多径滤波器整形变成有色噪声这就和实际信道不符了。这个模型里还放入了一个 Multipath 模块的变体——AWGNRayleighchanel_11.m对应的是在脚本模式下用comm.RayleighChannel实现同样链路的版本方便你做脚本和 Simulink 的交叉验证。对比两者你会发现脚本里rayleighchan的PathDelays、AveragePathGains和MaximumDopplerShift三个参数与 Simulink 模块里的参数完全一一对应只是单位略有区别脚本里路径增益的单位是 dB时延单位是秒Simulink 里也一样所以两者可以直接互通。3.3 仿真配置求解器选择和 slprj 缓存目录的用途打开这两个.slx模型的 Model Configuration Parameters会看到仿真类型是 Acceleration加速模式求解器是离散固定步长discrete fixed-step。这个选择是有原因的通信系统建模中信号处理都是离散事件连续求解器如 ode45会引入数值积分误差对误码率统计没有意义还会拖慢仿真速度。固定步长设置成信号采样周期的整数倍比如 1e-4 秒保证每个符号周期内完成一次有效采样。slprj目录是 Simulink 自动生成的工程缓存文件夹存放加速模式下的 C 代码生成中间文件。.slxc文件是编译后的模型二进制缓存。如果你把.zip解压后放到新机器上打开模型Simulink 发现slprj里的缓存和当前 MATLAB 版本不匹配会自动重新编译这是正常的不要删除slprj但也不用刻意保留。真正需要保留的是.slx模型文件和.m脚本它们是源码本体。4. 脚本源码解析awgn_1.m 到 AWGNRayleighchanel_11.m 的仿真链4.1 AWGN 脚本的公共骨架参数定义、噪声叠加、误码统计把awgn_1.m到awgn_4.m这组脚本打开对比可以发现它们共享同一套骨架差别只在调制方式和信噪比扫描范围上。下面是这组脚本的典型结构我按可读性重写了部分命名% awgn_ber_sweep.m - AWGN 信道下 BPSK 误码率扫描 clear; clc; M 2; % BPSK 调制 k log2(M); % 每符号比特数 EbN0_dB 0:2:12; % Eb/N0 扫描范围单位 dB numBits 1e6; % 蒙特卡洛仿真的总比特数 berSim zeros(size(EbN0_dB)); for idx 1:length(EbN0_dB) EbN0 10^(EbN0_dB(idx)/10); % 线性值 noiseVar 1/(2*k*EbN0); % 噪声方差 data randi([0 1], numBits, 1); % 随机比特 txSym 2*data - 1; % 0--1, 1-1 rxSym txSym sqrt(noiseVar)*randn(numBits,1); % 加性高斯白噪声 rxData rxSym 0; % 判决门限 0 berSim(idx) sum(rxData ~ data) / numBits; % 误比特率 end % 理论值BPSK 在 AWGN 下的误码率 Q(sqrt(2*Eb/N0)) berTheory qfunc(sqrt(2*10.^(EbN0_dB/10))); figure; semilogy(EbN0_dB, berSim, o-); hold on; semilogy(EbN0_dB, berTheory, r-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER); legend(仿真值,理论值,Location,southwest);这段代码的关键在噪声方差的计算和判决门限的设置。randn(numBits,1)生成的是零均值、单位方差的高斯随机数乘上sqrt(noiseVar)后等效噪声功率就是 ( N_0/2 )。这样得到的仿真误码率曲线会紧贴着理论曲线在 10 dB 时误差大约在 5% 以内。如果你看到仿真曲线比理论值高或低很多优先检查noiseVar公式里的k因子是否写错——BPSK 时 k1QPSK 时 k2这是最常见的出错点。4.2 瑞利与多径脚本rayleigh_9.m 和 duojing_8.m 的核心差异rayleigh_9.m、rayleigh_10.m和duojing_8.m在同样的骨架上增加了瑞利衰落信道。它们的核心不再是用sqrt(noiseVar)*randn直接加噪而是先构造一个瑞利信道对象让信号先通过这个信道再加 AWGN。以下是comm.RayleighChannel的典型构造方式% rayleigh_10.m 信道路段核心逻辑 fs 1e6; % 采样率 1 MHz pathDelays [0 0.5e-6 1e-6]; % 三条路径时延扩展 1 微秒 pathGains [0 -3 -6]; % 路径增益 dB maxDoppler 100; % 最大多普勒频移 100 Hz chan comm.RayleighChannel(... SampleRate, fs, ... PathDelays, pathDelays, ... AveragePathGains, pathGains, ... MaximumDopplerShift, maxDoppler, ... RandomStream, mt19937ar with seed, ... Seed, 17); % 信号通过瑞利信道 txSym 2*data - 1; fadedSym chan(txSym); % 乘性衰落 多径叠加 % 再叠加 AWGN方差按每个符号的 Eb/N0 计算 noiseVar 1/(2*k*EbN0); rxSym fadedSym sqrt(noiseVar)*randn(size(fadedSym));duojing_8.m里的「多径」其实就是把PathDelays和AveragePathGains参数从单径改成多径的过程。单径瑞利信道只有一条路径多径信道有两到三条接收端看到的是多条路径信号的叠加会产生频率选择性衰落。时延扩展越大频率选择性越强对宽带信号的损害越大。你可以在duojing_8.m中把PathDelays从[0 0.3e-6 0.7e-6]改成[0 1e-6 5e-6]会看到误码率曲线明显抬高——因为时延扩展加大后符号间干扰ISI加剧仅靠接收端的判决门限已经无法恢复原始数据。这个现象对应了实际工程中为什么需要使用均衡器或 OFDM 系统来对抗多径。4.3 运行脚本时常见的三个运行时错误和排查方法解压后第一次运行这些脚本最容易遇到三个问题。第一个是comm.RayleighChannel报错提示需要 Communications Toolbox这是依赖工具箱缺失的问题在 R2017a 之后该对象从 Communications System Toolbox 改名确认版本即可脚本本身没有改动必要。第二个问题是slprj目录和当前 MATLAB 版本不匹配导致.slx模型打开时报静态链接库错误。处理方法是在 MATLAB 命令行执行clean_slprj——没有这个内置命令需要手动删除项目根目录下slprj和sim文件夹再重新打开模型。缓存不存在时 Simulink 会全量重新编译第一次加载会慢 10~20 秒但结果正确。第三个问题在脚本和模型联合使用时出现Simulink 模型中 Error Rate Calculation 模块输出的 BER 是累计值而你希望在脚本端画出每个 SNR 点的误码率。常见做法是在模型中勾选 Output data to workspace把误码率数据导出到 MATLAB 工作区再用脚本循环修改 SNR 参数并逐次调用sim函数。如果导出的变量是ytout而不是ber说明你把仿真输出配置成了波形信号需要在配置参数里把输出选项改为单输出变量并确认是旧的误码统计结果。5. 复用这套代码写一个蒙特卡洛 BER 扫描的扩展验证脚本把awgnmodel.slx和rayleigh_10.m里的链路逻辑抽象出来可以进一步改造为一个完整的蒙特卡洛扫描脚本。这个脚本的价值有两个一是用系统对象替代 Simulink 模型方便批量跑批二是引入最小错误数终止条件避免在高信噪比区域为了统计到误差极小的误码率而浪费计算时间。% ber_montecarlo_scan.m - 带终止条件的 BER 扫描 clear; clc; % 通用参数 EbN0_dB 0:2:16; numMaxBitsPerSNR 5e6; % 每个 SNR 点的最大仿真比特数 minNumErrors 100; % 最小错误数达到即提前终止 % 调制方式QPSK M 4; k log2(M); rayleighChan comm.RayleighChannel(... SampleRate, 1e6, ... PathDelays, [0 0.3e-6], ... AveragePathGains, [0 -3], ... MaximumDopplerShift, 50); berMeasured zeros(size(EbN0_dB)); for snrIdx 1:length(EbN0_dB) EbN0 10^(EbN0_dB(snrIdx)/10); noiseVar 1/(2*k*EbN0); bitErrors 0; numBitsSimulated 0; % 按块仿真的帧结构 while numBitsSimulated numMaxBitsPerSNR bitErrors minNumErrors blockSize min(1e5, numMaxBitsPerSNR - numBitsSimulated); data randi([0 1], blockSize, 1); dataSym bi2de(reshape(data, k, []), left-msb); txSym pskmod(dataSym, M, pi/M, gray); fadedSym rayleighChan(txSym); rxSym fadedSym sqrt(noiseVar)*(randn(size(txSym)) 1j*randn(size(txSym)))/sqrt(2); rxDataSym pskdemod(rxSym, M, pi/M, gray); rxData de2bi(rxDataSym, k, left-msb); rxData rxData(:); lenDiff length(data) - length(rxData); if lenDiff 0 rxData [rxData; zeros(lenDiff, 1)]; elseif lenDiff 0 rxData rxData(1:length(data)); end newErrors sum(rxData ~ data); bitErrors bitErrors newErrors; numBitsSimulated numBitsSimulated blockSize; end berMeasured(snrIdx) bitErrors / numBitsSimulated; fprintf(Eb/N0 %2d dB, BER %.3e\n, ... EbN0_dB(snrIdx), berMeasured(snrIdx)); end semilogy(EbN0_dB, berMeasured, bd-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER); title(QPSK over Rayleigh Fading Channel);这个脚本里两个设计点值得单独说明。第一是块仿真block-wise simulation配合while循环让每个 SNR 点独立控制仿真停止时机当错误数达到 100 时就提前跳出高信噪比区域不需要硬跑满 5e6 比特时间开销大幅下降。第二是 QPSK 复基带仿真中噪声方差的计算方式——实部和虚部各除以 ( \sqrt{2} )保证总噪声功率仍然等于 ( N_0/2 )。如果直接套用 BPSK 的randn写法会在 QPSK 仿真中引入 3 dB 的 SNR 偏移。把这段脚本生成的 BER 曲线和awgnrayleighmodel.slx在相同 SNR 点的 Display 输出对照两者的差在 10% 以内就说明模型和脚本的参数设置一致。反之如果 Simulink 模型显示 BER 明显偏高检查模型的固定步长是否大于符号周期的 1/10步长太大会在信道滤波时丢失采样点导致误码率虚高。这套代码的整体逻辑和参数体系是一以贯之的理解了脚本里的方差计算与终止条件回头再调 Simulink 模型里的 AWGN 和 Rayleigh 块参数基本不会有不知道填什么的情况。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →