简介:这份资源面向通信工程、电子信息类专业学生及数字调制技术初学者,围绕8PSK数字调制系统提供一套可运行的MATLAB仿真代码,帮助读者从原理到实现理解多进制相位调制。压缩包共14个文件,以11个.m脚本和3个.mdl仿真模型为主,整体约29KB,脚本侧重相位映射、调制解调与误码率计算,模型文件则便于在Simulink中直观观察星座图与波形变化。内容覆盖8PSK的相位状态划分、二进制码元映射、载波恢复与位定时同步等关键环节,并可与BPSK、QPSK在频谱效率与抗噪性能上做对比实验。已有192人学习,适合作为课程设计、实验报告或自学练手的参考素材,帮助读者快速搭建仿真环境、验证调制解调流程并分析不同信噪比下的误码表现。
1. 8PSK 数字调制系统拆包:从 chapter7.zip 到能跑通的仿真链路
拿到chapter7.zip的时候,我第一反应是这包名起得真够随意的——chapter7,一看就是某本通信原理教材或者课程配套的仿真代码包。解压之后果然,里面躺着 15 个文件:ex1.m到ex11.m一堆脚本,外加ex2.mdl、ex4.mdl、ex7.mdl三个 Simulink 模型,还有ex2sim.m、ex4sim.m、ex7sim.m三个配套的仿真回调脚本。这套东西的核心主题就一个:8PSK 数字调制系统的建模与仿真。
如果你正在学通信原理、做课程设计,或者需要快速验证一个多进制相位调制链路的误码率性能,这个包能帮你省掉从零搭模型的时间。它覆盖了从星座映射、脉冲成型、载波调制到相干解调、误码统计的完整流程,而且脚本和 Simulink 模型双线并行——想快速看结果就跑.m,想看清每个模块的信号流向就开.mdl。适合通信工程专业的学生、刚入行的基带算法工程师,以及需要快速复现 8PSK 链路做对比实验的人。
不过先说清楚:这包不是那种“一键出图”的成品工具,它更像是一套教学演示代码,参数需要你自己根据场景调,部分脚本的默认信噪比设置偏高,直接跑出来的误码率曲线会好看得不太真实。下面我按实际拆包和跑通的顺序,把关键环节和踩过的坑一个个说清楚。
2. 文件结构与运行环境:先搞清楚每个 .m 和 .mdl 的分工
2.1 15 个文件到底怎么分类
解压后别急着双击运行,先把文件按功能分个组,不然很容易在ex5.m和ex7sim.m之间绕晕。我整理了一张表,按“信号生成—调制—信道—解调—误码统计”这条链路来归类:
| 文件 | 类型 | 在链路中的角色 | 建议运行顺序 |
|---|---|---|---|
ex1.m | 脚本 | 基础星座映射与波形观察 | 1 |
ex2.m+ex2.mdl+ex2sim.m | 脚本+模型 | 8PSK 调制器建模与仿真 | 2 |
ex3.m | 脚本 | 脉冲成型滤波器设计与频谱 | 3 |
ex4.m+ex4.mdl+ex4sim.m | 脚本+模型 | 加性高斯白噪声信道仿真 | 4 |
ex5.m | 脚本 | 相干解调与星座判决 | 5 |
ex6.m | 脚本 | 误码率理论值与仿真值对比 | 6 |
ex7.m+ex7.mdl+ex7sim.m | 脚本+模型 | 完整链路 Simulink 集成 | 7 |
ex8.m~ex11.m | 脚本 | 扩展实验:相位噪声、频偏影响等 | 按需 |
ex2.mdl、ex4.mdl、ex7.mdl这三个 Simulink 模型是层层递进的:ex2只搭调制,ex4加入信道,ex7是完整收发链路。对应的ex2sim.m、ex4sim.m、ex7sim.m不是用来直接跑的,它们是模型打开时自动加载参数的初始化脚本,里面定义了载波频率、符号率、信噪比范围这些变量。如果你改了模型里的参数但没同步改*sim.m,仿真结果会对不上。
2.2 MATLAB 版本与工具箱依赖
这套代码我分别在 R2018b 和 R2022a 上跑过,都能运行,但有几个注意点。Simulink 模型用的是经典库模块,没有依赖太新的通信工具箱函数,所以版本兼容性还算好。不过ex6.m里用到了berawgn函数来算理论误码率,这个函数在通信工具箱里,没装的话会报错。
检查工具箱的命令很简单:
% 检查通信工具箱是否安装 ver('comm') % 如果返回空,说明没装,需要补装 % 另外确认 Simulink 可用 ver('simulink')如果ver('comm')返回空,ex6.m和部分涉及理论曲线的脚本会跑不了。替代方案是自己写一个 8PSK 理论误码率公式,但精度和berawgn有差异,后面第 5 章会讲怎么处理。
提示:R2018b 之前的版本,Simulink 模型的
.mdl格式可能打不开,需要先另存为.slx。如果双击.mdl没反应,在 MATLAB 命令窗口用open_system('ex7.mdl')试试。
3. 从 ex1.m 到 ex5.m:手动跑通一条 8PSK 调制解调链路
3.1 星座映射与符号速率设置
ex1.m是整个包的入口,它做的事情很基础:生成随机二进制序列,按 3 bit 一组映射到 8PSK 的 8 个相位点上。8PSK 每个符号携带 3 个二进制位,相位间隔 45°,这是它比 QPSK 频谱效率高的根本原因。
打开ex1.m,核心代码大概长这样:
% ex1.m 核心片段:8PSK 星座映射 M = 8; % 调制阶数 k = log2(M); % 每符号比特数 = 3 numSymbols = 1000; % 仿真符号数 dataBits = randi([0 1], numSymbols*k, 1); % 生成随机比特流 % 将比特流按 3 bit 分组,转为十进制符号 dataSym = bi2de(reshape(dataBits, k, numSymbols).', 'left-msb'); % 8PSK 相位映射:0~7 对应 0, 45, 90, ..., 315 度 phases = 2*pi*dataSym/M; modSignal = exp(1j*phases); % 复基带信号 % 画星座图 scatterplot(modSignal); title('8PSK 星座图');这里有几个参数需要你根据实际场景改。numSymbols默认 1000,做误码率曲线时至少要调到 10^5 量级,不然低信噪比下的误码统计会很不稳定。bi2de的'left-msb'选项决定了比特到符号的映射顺序,如果你要和某个标准(比如 DVB-S)对齐,映射表可能不一样,需要手动改相位对应关系。
跑完ex1.m,你会看到 8 个点均匀分布在单位圆上。如果星座点看起来偏移或者幅度不对,检查exp(1j*phases)前面有没有做归一化——有些教材代码会乘一个sqrt(Es),这里默认是单位功率。
3.2 脉冲成型与频谱观察
ex3.m负责脉冲成型。8PSK 信号如果直接用矩形脉冲,频谱旁瓣衰减很慢,实际系统里会用根升余弦滤波器来压缩带宽。这个脚本里用的常见参数是滚降系数 0.35、每符号 4 个采样点。
% ex3.m 核心片段:根升余弦脉冲成型 sps = 4; % 每符号采样数 rolloff = 0.35; % 滚降系数 span = 6; % 滤波器跨度(符号数) % 设计根升余弦滤波器 rrcFilter = rcosdesign(rolloff, span, sps, 'sqrt'); % 上采样并滤波 modSignalUpsampled = upsample(modSignal, sps); txSignal = conv(modSignalUpsampled, rrcFilter, 'same'); % 画频谱 pwelch(txSignal, [], [], [], sps); title('8PSK 发射信号功率谱');sps这个参数直接影响仿真速度和频谱分辨率。设成 4 是速度和精度的折中,如果你要看更精细的频谱细节,可以调到 8 或 16,但仿真时间会成倍增加。span控制滤波器截断长度,6 个符号跨度在滚降 0.35 时已经够用,再大对频谱改善不明显,反而增加计算量。
跑完这个脚本,你会看到功率谱主瓣宽度大约在(1+rolloff)*Rs/2的位置开始滚降。如果旁瓣抑制不够,先检查rcosdesign的'sqrt'参数有没有漏掉——不加这个参数设计出来的是升余弦而不是根升余弦,收发匹配会出问题。
3.3 加噪、解调与误码统计
ex4.m和ex5.m是连在一起用的。ex4.m给发射信号加高斯白噪声,ex5.m做相干解调和星座判决。这里的关键是信噪比的换算——awgn函数默认按符号信噪比Es/N0加噪,但误码率曲线通常看的是Eb/N0,两者差一个log2(M)的因子。
% ex4.m + ex5.m 核心片段:加噪与解调 EbN0_dB = 10; % 每比特信噪比 EsN0_dB = EbN0_dB + 10*log10(k); % 换算为符号信噪比 rxSignal = awgn(txSignal, EsN0_dB, 'measured'); % 匹配滤波 rxFiltered = conv(rxSignal, rrcFilter, 'same'); % 下采样 rxDownsampled = rxFiltered(1:sps:end); % 星座判决:找最近的相位点 rxPhases = angle(rxDownsampled); rxSym = mod(round(rxPhases/(2*pi/M)), M); rxBits = de2bi(rxSym, k, 'left-msb'); rxBits = rxBits(:); % 误码统计 [numErrors, ber] = biterr(dataBits, rxBits(1:length(dataBits))); fprintf('Eb/N0 = %d dB, BER = %.4e\n', EbN0_dB, ber);这段代码里最容易翻车的地方是下采样时刻。rxFiltered(1:sps:end)假设匹配滤波器的峰值正好在采样点上,但实际因为滤波器延迟,最佳采样点可能有偏移。如果你跑出来的误码率比理论值高很多,先把rxDownsampled的星座图打出来看看,点是不是散开的。如果是,试着调整下采样偏移量,比如改成rxFiltered(span*sps/2+1:sps:end)。
另外awgn的'measured'选项会让函数先测量信号功率再按指定信噪比加噪,如果你已经对信号做了归一化,可以去掉这个选项直接指定功率。两种方式出来的结果在低信噪比下会有细微差异,做对比实验时要统一。
4. Simulink 模型 ex7.mdl:完整链路的模块级拆解
4.1 模型打开与参数初始化
ex7.mdl是这个包里最完整的 Simulink 模型,包含了从信源、8PSK 调制、根升余弦滤波、AWGN 信道、匹配滤波、解调到误码统计的整条链路。直接双击打开之前,先在 MATLAB 命令窗口跑一遍ex7sim.m,它会把模型需要的所有参数加载到工作区。
% ex7sim.m 关键参数定义 M = 8; % 调制阶数 k = log2(M); % 每符号比特数 Rs = 1000; % 符号率 1000 Baud sps = 4; % 每符号采样数 rolloff = 0.35; % 滚降系数 EbN0_dB = 0:2:12; % 信噪比扫描范围这些变量名必须和模型里各模块引用的变量名一致,否则打开模型会报“未定义变量”。如果你改了EbN0_dB的范围,记得同步检查误码统计模块里的阈值设置。
打开模型用open_system('ex7.mdl'),不要直接双击文件,因为有些系统关联会把它当文本打开。模型打开后,先别急着点运行,按Ctrl+E打开配置参数,确认“求解器”设置的是固定步长、离散求解器,步长和1/(Rs*sps)匹配。
4.2 关键模块参数与信号流向
模型里几个核心模块的参数需要你手动核对:
- Bernoulli 信源:概率设 0.5,输出数据类型 double,采样时间
1/(Rs*k)。 - 8PSK 调制器:用“M-PSK Modulator Baseband”模块,M 设为 8,星座图参数选“Binary”或“Gray”看你的映射需求。Gray 映射在低信噪比下误码率更低,但和
ex1.m里的自然映射不一致,做对比时要注意。 - 根升余弦滤波器:收发各一个,参数用
rcosdesign(rolloff, span, sps)生成的系数,或者直接用“Raised Cosine Transmit Filter”模块,滚降系数设 0.35。 - AWGN 信道:信噪比模式选
Eb/N0,输入EbN0_dB变量,符号周期设1/Rs。 - 误码统计:用“Error Rate Calculation”模块,接收延迟要设成滤波器群延迟的总和,一般是
span*sps左右,具体值看ex7sim.m里的delay变量。
信号流向是:信源 → 8PSK 调制 → 上采样 → 根升余弦滤波 → AWGN → 匹配滤波 → 下采样 → 8PSK 解调 → 误码统计。每个模块的采样时间要匹配,否则 Simulink 会报采样时间冲突。
4.3 运行仿真与误码率曲线导出
模型跑起来之后,误码统计模块会实时显示误码率。但要做完整的误码率曲线,需要在外层套一个for循环扫描EbN0_dB,每次跑完用sim命令取结果。
% 批量运行 ex7.mdl 并收集误码率 EbN0_dB = 0:2:12; berSim = zeros(size(EbN0_dB)); for i = 1:length(EbN0_dB) assignin('base', 'EbN0_dB', EbN0_dB(i)); sim('ex7.mdl'); berSim(i) = BER(end); % BER 是误码统计模块的输出变量名 end % 画曲线 semilogy(EbN0_dB, berSim, 'o-'); grid on; xlabel('Eb/N0 (dB)'); ylabel('BER'); title('8PSK 误码率曲线(Simulink 仿真)');这里BER变量名取决于误码统计模块里设置的变量名,打开模块看一下“变量名”那一栏填的是什么。如果跑完berSim全是零,说明信噪比范围设太高了,8PSK 在Eb/N0超过 12 dB 之后误码率已经低到 10^-5 以下,需要加大仿真符号数才能统计到。
注意:Simulink 跑误码率曲线时,每个信噪比点至少需要 10^5 个符号才能保证统计稳定性。如果模型里信源每帧只有 1000 个符号,需要把仿真时间设长,或者用
Frame-Based模式一次处理多帧。
5. 避坑与排查:跑 8PSK 仿真时最容易翻车的五个地方
5.1 误码率曲线和理论值对不上
现象:ex6.m跑出来的仿真误码率比berawgn算的理论值高一个数量级,或者曲线斜率不对。
原因:最常见的是信噪比换算错了。awgn函数如果没加'measured',它默认信号功率是 1 W,但你的发射信号经过脉冲成型后功率可能不是 1。另外Eb/N0和Es/N0的换算漏掉log2(M)也会导致曲线平移。
解决:在加噪前先算一下发射信号的实际功率mean(abs(txSignal).^2),然后手动指定噪声功率。或者统一用Es/N0做横轴,最后再换算成Eb/N0画图。
5.2 Simulink 模型报采样时间冲突
现象:点运行后弹窗报错“采样时间不匹配”或者“所有模块的采样时间必须是离散的”。
原因:模型里有的模块继承了-1(继承采样时间),有的模块显式设了1/(Rs*k),两者不一致。特别是信源和调制器之间、滤波器和下采样之间容易出这个问题。
解决:在模型配置里把求解器设为“固定步长/离散”,步长统一设为1/(Rs*sps)。然后逐个检查模块的采样时间参数,信源和调制器用1/(Rs*k),滤波器和信道用1/(Rs*sps),下采样之后恢复成1/Rs。
5.3 星座图旋转或发散
现象:解调后的星座图整体旋转了一个角度,或者点散得很开,误码率居高不下。
原因:载波相位没有对齐。8PSK 对相位偏移非常敏感,哪怕 10° 的固定相位误差都会让误码率显著恶化。ex5.m里的相干解调假设接收端载波和发射端完全同频同相,但实际仿真中滤波器延迟、下采样时刻偏移都会引入相位误差。
解决:在解调前加一个相位估计和校正步骤。简单做法是用星座点的平均相位作为参考,把接收信号乘上exp(-1j*meanPhase)。如果要做更真实的仿真,可以加一个 Costas 环或者判决反馈相位估计。
5.4 ex6.m 报错找不到 berawgn
现象:运行ex6.m时提示“未定义函数或变量 'berawgn'”。
原因:MATLAB 没装通信工具箱,或者工具箱路径没加载。
解决:先ver('comm')确认。如果确实没有,可以自己写一个 8PSK 理论误码率近似公式:
% 8PSK 理论误码率近似(高信噪比) EbN0_lin = 10.^(EbN0_dB/10); berTheory = (2/k) * qfunc(sqrt(2*EbN0_lin*k) * sin(pi/M));这个近似在Eb/N0大于 8 dB 时和berawgn结果很接近,低信噪比下会偏乐观,做对比时心里有数就行。
5.5 仿真速度慢到无法忍受
现象:跑一次误码率曲线要几个小时,ex7.mdl尤其慢。
原因:Simulink 模型默认用变步长求解器,或者符号数设得太大,每个信噪比点都重新编译模型。
解决:把求解器改成固定步长离散,关闭“仿真参数”里的“自动编译”选项。另外把EbN0_dB的扫描点数减少,比如从0:1:12改成0:2:12,中间点用插值补。如果还是慢,把sps从 4 降到 2,精度损失不大但速度翻倍。
6. 进阶技巧:用 ex8.m 到 ex11.m 做相位噪声与频偏敏感性分析
ex8.m到ex11.m这四个脚本是这个包里最容易被忽略的部分,但它们恰恰是 8PSK 从“能跑通”到“能评估实际性能”的关键。8PSK 相比 QPSK 最大的劣势就是对相位噪声和频率偏移敏感,这四个脚本分别从不同角度量化了这种敏感性。
ex8.m做的是相位噪声注入。它在发射信号上乘一个exp(1j*phaseNoise),其中phaseNoise是一个零均值高斯随机过程,标准差从 0 到 10° 扫描。跑完你会看到一条曲线:相位噪声标准差每增加 2°,误码率在Eb/N0=10 dB时大约恶化 0.5 到 1 dB。这个数据在选晶振或者评估锁相环带宽时很有参考价值。
% ex8.m 核心:相位噪声敏感性扫描 phaseNoiseStd = 0:2:10; % 相位噪声标准差(度) berPhaseNoise = zeros(size(phaseNoiseStd)); for i = 1:length(phaseNoiseStd) noise = phaseNoiseStd(i) * pi/180 * randn(size(modSignal)); rxSignal = modSignal .* exp(1j*noise); % 后续加噪、解调、误码统计... berPhaseNoise(i) = ber; endex9.m和ex10.m分别做频率偏移和定时误差的影响。频率偏移会让星座图整体旋转,ex9.m里扫描的频偏范围是符号率的 0.1% 到 1%。8PSK 在频偏超过符号率 0.5% 之后误码率急剧上升,这个阈值比 QPSK 严格得多。ex10.m的定时误差扫描则告诉你采样时刻偏移多少会让误码率翻倍——经验值是超过sps的 10% 就需要加定时同步算法了。
ex11.m是我个人觉得最有用的一个,它把前面几个敏感性分析的结果汇总成一张表,对比了 8PSK 在相位噪声、频偏、定时误差分别作用下的性能退化程度。你可以直接拿这张表去评估你的系统需不需要加额外的同步模块。
从那以后我每次跑 8PSK 仿真,都会先把ex8.m到ex11.m过一遍,确认当前参数下相位噪声和频偏的容忍度,再回头调主链路的信噪比预算。这个习惯帮我省了很多次“链路跑通了但实际指标不达标”的后悔药。希望这套拆包笔记能帮到你。
本文还有配套的精品资源,点击获取