
简介这份资源围绕MATLAB Simulink中的通信系统建模与仿真聚焦数字信号载波传输的源码实现适合通信工程专业学生或相关工程师用于学习调制解调与系统仿真。压缩包共含十八个文件其中十一个m脚本用于实现信号生成、调制、加噪与解调等核心算法三个slx文件为Simulink可视化模型可直接打开查看信号流和参数设置另有二个mat数据文件和xml与slxc配置缓存辅助仿真过程整体压缩后仅八十一KB轻巧且便于下载。截至目前该资源已有一百九十一人学习。包内按DPSK、FSK、PSK、PAM、QAM等典型调制方式组织文件名清晰可辨每个调制方式均配有对应模型与脚本由于文件命名规则清晰目录结构简洁用户能快速定位所需代码。读者可结合源码直观对照掌握从随机信号生成、载波调制、信道加噪到解调恢复的完整链路对通信原理课程设计、仿真实验或毕业设计中的通信模块开发有直接参考价值。1. 数字信号载波传输建模与仿真从信源脚本到 BER 曲线把一串随机比特送进 Simulink经过调制、成形滤波、加噪再解调出来数错了几位——这条链路就是数字信号载波传输仿真的骨架。做 MATLAB Simulink 通信系统建模与仿真时最常见的困惑不是找不到模块而是波形能见、星座也成形BER 曲线却总比理论值高一截。问题往往不在数学而在信源怎么进、采样时间怎么设、AWGN 通道的 SNR 按什么单位算。这篇按信源→调制→信道→接收→验证的顺序拆开讲适合要做基带验证的、在搭 OFDM 前端链路的以及拿着 Demo 例程不知道从哪下手改参数的人。2. 发射端链路从比特脚本到复基带调制信号2.1 先用脚本生成比特和符号把随机数握在手里Simulink 里也可以直接放 Bernoulli Binary Generator但做载波传输仿真时我更建议先在脚本里生成一段已知比特写成变量再通过 From Workspace 送进模型。原因是接收端判决完要逐位对比数据源必须是同一段序列而工作区变量随时可以保存下来做离线统计。rng(42); frameLen 1024; bits randi([0 1], frameLen, 1); % BPSK 映射0 - -1, 1 - 1 symbols 2 * bits - 1; save(tx_data.mat, bits, symbols, frameLen);这段代码里rng(42)固定随机种子保证每次仿真拿到同一段帧方便复现symbols是复基带符号的实部BPSK 没有虚部。做 QPSK 时用qammod(bits, 4, InputType, bit, UnitAveragePower, true)就能拿到复数符号。保存成.mat后再从模型里加载比在模块里填随机数参数更灵活因为分析脚本和模型共用同一个数据源。2.1.1 数据源是整数数组时的处理很多工程场景的数据源来自文件比如 CAN 报文的负载段或某段采集到的 16 进制数据。用hex2dec转成十进制后要留意 MATLAB 默认把最高位当符号位的情况建议用typecast显式转换raw hex2dec({FF; 7F; 80; 01}); signed8 typecast(uint8(raw), int8);typecast按内存布局重新解释字节int8类型下的负数判断才和协议栈一致如果直接对raw做 128判断等于自己实现了一遍符号扩展容易和后面的解调判决逻辑写拧。仿真链路里宁可多写一行显式转换也不要依赖 MATLAB 的隐式类型规则。2.2 用 Rectangular QAM Modulator Baseband 做基带调制通信系统建模里最常用的调制模块是 Communications Toolbox 里的 Rectangular QAM Modulator BasebandBPSK、QPSK、16QAM 都是它。把它拖进模型后双击看三个关键参数Normalization method、Constellation ordering、Minimum distance。Normalization method 选Average power星座图点的平均功率才是 1后面 AWGN Channel 的 SNR 计算才有统一基准。Constellation ordering默认Binary工程上对比误码率时建议改Gray相邻星座点只差 1 bit同样的 SNR 下 BER 会低一些。Minimum distance 一般不动让它随 M 值和归一化方式自动算。模块输入可以是帧或样点流。从工作区来的symbols是列向量如果 Simulink 端设置 Samples per frame 1那要先把符号按列处理如果按帧处理就在模块的 Input processing 参数里告诉它按列。这里最容易踩的坑是维度不匹配工作区是 1024x1模块却按 1 帧 1 采样来读仿真会直接报错或更隐蔽地只取第一个元素。2.3 Raised Cosine 成形滤波与频谱观察基带符号是冲激序列直接拉个 Scope 看是跳变的阶梯波不代表实际发射信号。数字载波传输仿真一般加根升余弦成形调制模块后面接 Raised Cosine Transmit Filter。% 对应脚本里常用的设计参数 rolloff 0.22; % 频谱效率与过冲的折中 sps 8; % 每符号采样数后面同步和眼图都用它 span 10; % 滤波器截断长度单位是符号周期 fir rcosdesign(rolloff, span, sps, sqrt);rcosdesign生成的系数可以直接在工作区预览频响Simulink 里则把 Rolloff factor 和 Filter span in symbols 填成对应值。sps8是常用起点定时同步的精度够仿真步数又不至于太高。如果你把sps设成 2眼图会张开得更快但后面加载波频偏时相位跳变难补偿调试起来反而慢。成形之后用一个 Spectrum Scope 看信号频谱正常情况是左右对称、带外衰减明显的基带谱。这里注意 Spectrum Scope 的 Sample time 要填成1/fsfs 符号速率 * sps填错整个频谱横轴都是错的。少数场景下需要插一段自定义 C 逻辑可以在滤波器后接 S-Function 或 C Caller 模块但单纯验证链路性能时标准滤波器模块已经够用不必一开始就上 C 代码。3. 信道与接收端AWGN、频偏和定时同步的建模差异3.1 AWGN Channel 的 SNR 到底按什么算发端之后接 AWGN Channel这个模块的参数表最短但坑也最集中。它的SNR (dB)参数默认按符号信噪比 Es/N0 算不是按比特信噪比 Eb/N0BPSK 里两者差 0 dBQPSK 里差 3 dB16QAM 就差更多。要跟理论曲线对比时得先在脚本里做换算EbNo 0:2:10; k log2(modOrder); % QPSK 是 216QAM 是 4 EsNo EbNo 10*log10(k); snr EsNo; % 给 AWGN Channel 的参数Signal power参数直接填1因为调制模块已按 Average power 归一化。如果你改用了非归一化星座图这里填错会把加噪功率放错一个倍数表现就是解调后星座点整体膨胀或收缩BER 曲线平移好几个 dB。先用 BPSK 跑通再用 16QAM 验证换算是很稳妥的检查方法。提示AWGN Channel 模块在模型里看起来只有一行参数但 Es/N0 和 Eb/N0 的换算决定了你的仿真曲线和理论曲线是否对齐建议在脚本里显式写换算过程方便别人复查。3.2 理想同步 vs 带粗频偏补偿的接收结构仿真的接收端经常直接接和发送端一样的滤波器然后判决全程假设载波同步和定时同步都已知。这个理想模型用于算法验证是合理的但它会让每个刚模仿的人误以为同步不是事。实际数字载波传输链路里接收端要拆成三件事帧同步、符号定时、载波频偏估计。Simulink 里没有现成的“一整套同步”模块常见做法是分两步先用 Course Frequency Compensator 处理大频偏再用细同步环路纠正残余相位。入门不想碰环路时至少要在接收链路里加一个 Phase Offset 模块手动给一个固定相位旋转观察它对判决距离的影响。% 用一段已知训练序列估计粗频偏序列长度越长估计越准 t (0:length(symRx)-1).; phaseIncrement angle(symRx. * conj(trainingSeq)) / mean(t); compensated symRx .* exp(-1j * phaseIncrement * t);这是教科书里延迟相乘法的简化写法angle(...)/mean(t)得到的相位增量会发飘工程上应该用最小二乘拟合相位但作为链路前期验证足够。把compensated送回判决模块星座图从“转圈”变成“四点聚拢”时说明频偏量级判断正确了。3.2.1 定时同步在仿真里怎么表达帧同步用 PN 序列相关就能解决定时同步最直接的表现是接收滤波器前要不要加 Buffer 和整数延迟。基带仿真里rx信号的采样率已经是sps倍符号率所以定时偏差只会出现在小数倍采样点之间。对多数入门链路把发送滤波器和接收滤波器共享同一个rcosdesign(...,sqrt)系数就是匹配滤波残余定时误差用眼图观察即可不必先上 Gardner 环。眼图模块是 Eye Diagram Scope采样点设成sps能看到清晰的“眼中”区域如果眼中宽度只有采样间隔的一半先查接收滤波器是否和发送端同根再查 Buffer 的帧对齐参数不要急着改环路。3.3 用简单的判决模块完成解调同步完成后解调只需要符号判决和比特映射。BPSK 用 Sample and Hold 取符号跟 0 比较大于 0 判 1小于等于 0 判 0。Simulink 里对应的是 Compare To Zero 模块把 Relational Operator 的输出从 boolean 转成 double再和发射的bits做差分。% 离线脚本里完成的判决和模型内模块逻辑一致 rxBits double(real(rxSymbols) 0); errs sum(rxBits ~ bits(1:length(rxBits))); ber errs / length(rxBits);这一段脚本的价值在于模型里任何模块参数变化最后都能用这段脚本对同一份rxSymbols输出重新判决不必每次打开 Scope 去看星座图。errs 不为 0 时把rxSymbols画成复数点图就能看出是噪声主导还是相位旋转主导相位旋转导致的是整体圆弧噪声导致的是散点弥散。4. 仿真时钟、帧长和采样时间参数怎么凑在一起4.1 先从符号率推出 Sample Time再填 Scope新建模型时不少人直接拖模块默认 Sample time -1继承拖到最后 Scope 不是炸就是毛。正确顺序是先在脚本里定好符号速率和过采样率再把值填到模块里。比如符号速率 1 Mbpssps8那么系统采样时间Ts 1/(1e6*8) 125 ns。Rs 1e6; % 符号速率单位 Hz sps 8; % 每符号采样数 fs Rs * sps; % 系统采样率 Ts 1/fs; % 仿真步长用Ts填到所有模块的 Sample time 参数避免 Simulink 在变步长求解器下自动插值带来的相位不平滑。仿真停止时间填frameLen * sps * Ts或者等价的frameLen/Rs正好覆盖一帧数据。VariableStepDiscrete求解器下固定步长设成TsScope 的采样周期才能稳定连续求解器拿来跑这种离散基带链路只会更慢没有额外收益。如果后续要导成 FMU 做联合仿真固定步长离散模型也是最容易跨工具迁移的形式。4.2 帧长对 BER 统计的影响帧长不是越大越好。BER 统计通常要求至少有 100 个错误位SNR 高时一帧全对SNR 低时一帧错一半两者都不能给出可信的 BER 点。常见做法是让仿真按帧循环跑累计错误位再除以累计比特数而不是跑完单帧就结算。totalBits 0; totalErrs 0; for ebno EbNo % 每次改变噪声功率后重新生成一帧或复用同一帧 ber runSimulation(ebno); totalBits totalBits frameLen; totalErrs totalErrs round(ber * frameLen); end berEst totalErrs ./ totalBits;如果你的模型用 Constant 模块固定了帧输入工作区里就得用sim命令在循环里反复调用模型或者把帧存成timeseries然后让仿真停止时间覆盖多帧。后者更省事缺点是帧首尾衔接时滤波器状态会跨帧统计时要丢弃每帧前span个符号再判决。4.2.1 需要验证频谱时把仿真输出导出成 CSV 再 FFTSimulink 的 Scope 能看波形但文档和报告里往往要一张频谱图。把信号用 To Workspace 模块导出成变量再在脚本里fft比截屏准确得多。导出的信号经常带时间戳readmatrix再从 CSV 读回来也一样。data readmatrix(rx_waveform.csv); % 第一列时间第二列幅度 t data(:,1); x data(:,2); Fs 1 / mean(diff(t)); % 从时间列反推采样率 X fftshift(fft(x)); f (-length(x)/2 : length(x)/2-1) * Fs / length(x); plot(f, 20*log10(abs(X)));fftshift把零频挪到中间横轴f要和X对齐。若波形里带了直流分量频谱中央会有个耸起信号本身是中心对称的看到单边不对称先查是不是导出时截断了信号首尾。4.3 一套可以抄的默认链路参数下表是 BPSK 基带载波传输链路我常用的默认值帧长、滚降系数、过采样都可以据此微调。参数名默认值调整方向信源帧长1024 bit调大提高统计精度调小加速仿真调制阶数2BPSK换 QPSK 时记着改 Es/N0 换算过采样率 sps8降到 4 可提速升到 16 利于频偏估计滚降系数0.220.35 对定时同步更敏感根升余弦阶数10 个符号周期过小带外泄漏大AWGN SNR按 Es/N0 填和理论曲线对比时换算仿真时间frameLen/Rs多帧统计时按帧数扩展这一组参数在 Simulink 里能直接跑通 BPSK 链路换成 16QAM 时只需替换调制模块的 M 值并重新换算 SNR滤波器参数不需要动。5. 源码组织的三种套路和排错顺序5.1 三段式组织生成脚本、模型、分析脚本“源码”不是模型的 slx 文件就够了我一般把工程拆成三段gen_source.m生成比特和参考星座main_model.slx只做信号链路analyze_rx.m负责 BER、星座图、频谱统计。模型里尽量不写常量所有参数从gen_source.m设置的 base workspace 变量读入。这样做的好处是换一组帧长或滚降系数时只改脚本头部的参数块模型文件本身不动Simulink 里的 Constant 模块填变量名比填数字可追溯得多。sim(main_model)也可以从脚本触发循环跑批只在分析脚本里做。5.2 排错顺序从信源到信道不要从 Scope 往前猜波形异常时按“信源写入→调制映射→成形滤波→信道→接收滤波→判决对比”的顺序逐级检查。先用示波器看调制模块输出星座图应落在标准点上再看成形后频谱是否对称最后才怀疑 AWGN 参数。外部模式调试在 Simulink 里值得优先用打开 External 模式后把模块参数改成可调模型运行时不重新编译在线扭 Phase Offset 看星座图旋转非常直接。如果用的是嵌入式目标机这一步还能顺便验证目标机上跑出来的数据和仿真一致。5.3 再往下可以做的小扩展跑通 BPSK-AWGN 后下一步值得做的是把 AWGN 换成交织信道、把单载波换成 OFDM 符号块或者把发射机里的 Raised Cosine Filter 换成 S-Function 写好的 C 滤波器验证同一套基带参数配置在 C 执行环境下是否仍成立。OFDM 的调制解调模块用法和单载波没有本质差异子载波数、循环前缀长度和导频位置才是新参数。如果需要把模型导出给其他工具做联合仿真再考虑 FMU 导出或 C 代码生成在这之前先把基本链路的 BER 跑出理论曲线来再扩展否则换工具后会同时面对建模错误和接口错误定位成本会翻倍。本文还有配套的精品资源点击获取