简介:面向通信类专业学生及 Matlab 初学者,这份代码以 BPSK 与 QPSK 调制方案对比为主线,通过参数化编程和详细注释,展示两种常见数字调制方式在相位表示、频谱利用率和接收复杂度上的差异,可直接服务于课程设计、期末大作业或毕业设计中的仿真环节。压缩包共 2 个文件,包含 1 个 m 格式的 Matlab 主程序和 1 个 txt 格式的说明文件,整体仅 844B,结构精简,适合快速研读和修改参数。已有 68 人浏览/下载学习。代码支持在 Matlab 2014/2019a/2024a 等版本运行,用户可方便地调整信噪比、调制参数等观察性能变化;同时附有可直接运行的脚本,省去数据准备与调试时间,便于学习者对照理解 BPSK 的低复杂度特性和 QPSK 的高频谱效率优势。对于希望从理论走向实践的读者,这是一份轻量而完整的参考。
1. BPSK和QPSK的比较代码:课设曲线和工程选型都需要的Matlab方案
当课设要求在“BPSK和QPSK调制方案的比较”里画出误码率曲线时,大部分人的第一反应是去拼一个Matlab脚本,结果搜到的m文件要么只有发射端星座图、要么把AWGN信道写成固定信噪比,最后画出来的两条曲线根本对不上教科书。这个标题里的rar,本质上是一套可复现的比较链路:同一份随机比特流,分别走BPSK和QPSK的调制、AWGN信道、接收判决,最终用误码率曲线把两种方案的差异说清楚。它回答的是两个层面的问题——对做课设和复试的人来说,是怎么快速得到一条能交代的曲线;对做选型的人来说,是BPSK和QPSK到底在带宽、功率、误码率上差多少,QPSK省下的带宽是用什么换来的。整个过程只用Matlab基础语法,不依赖通信工具箱,适合从零搭仿真的人照着改。
2. 先把理论摆正:BPSK与QPSK在带宽、功率、误码率上的取舍
在动手跑代码之前,需要先把两件事理清:星座图差异和比较基准。否则就会出现后面仿真里最常见的翻车——误码率曲线整体比理论高3dB,却分不清是代码问题还是理论写错了。
2.1 从星座图看本质区别:BPSK是两个点,QPSK是四象限
BPSK把0和1映射成两个幅度相等的实信号,归一化后就是-1和+1,星座图上是横轴上两个点,每符号携带1比特。QPSK把两位比特拼成一个符号,用实部和虚部同时传输信息,归一化后落在复平面的四个象限上,每符号携带2比特。从I/Q分解的角度看,QPSK本质上就是两路正交的BPSK:I路和Q路各有一个±1的实信号,分别乘上cos和-sin载波后相加。
这个拆分决定了QPSK的带宽效率翻倍:信息速率一致时,QPSK的符号速率只有BPSK的一半,主瓣带宽也就接近减半。代价呢?归一化符号能量后,QPSK四个星座点到原点的距离相同,但相邻星座点的欧式距离从BPSK的2变成了√2,因为每符号要摊两份比特的能量。欧式距离越小,同样噪声下判错的概率越高,这就是后面误符号率比BPSK高的来源。
这个区别也会直接反映在仿真脚本的结构设计上:BPSK的调制和判决都只要处理一个实数向量,QPSK则必须引入复数符号和I/Q两路分开判决。为了让两种方案在同一个脚本里公平对比,发射端不能让双方各用各的符号速率,而是应该固定总比特数,让BPSK产生N个符号、QPSK产生N/2个符号,再去比较谁的误码率更低。
2.2 Eb/N0与Es/N0:不同符号速率公平比较的基准
比较两种调制方案,横轴不能用信噪比,也不能只用Es/N0,必须用Eb/N0。因为QPSK每个符号携带2比特能量,BPSK只有1比特,如果横轴是符号信噪比,QPSK等于占了双倍符号能量的便宜,曲线自然更好看。把横轴换算成每比特能量Eb/N0后,两种方案才站在同一起跑线上比效率。
换算关系是Es/N0 = log2(M)·Eb/N0。M=4时,QPSK的Es/N0比BPSK高3dB。这3dB只是符号能量换比特数带来的差,不代表QPSK本身更抗噪。事实上,在无编码AWGN信道、相干解调、格雷映射这三个前提同时满足时,QPSK的误比特率理论公式与BPSK完全相同:
BPSK误比特率:Pb = 0.5·erfc(sqrt(Eb/N0))
QPSK(格雷映射)误比特率:Pb = 0.5·erfc(sqrt(Eb/N0))
QPSK误符号率:Ps = 2Q(sqrt(2Eb/N0)) - Q²(sqrt(2Eb/N0))
误符号率的表达式在Matlab里直接写成erfc形式更方便:Ps = erfc(sqrt(Eb/N0)) - 0.25·erfc²(sqrt(Eb/N0))。后面第3章的代码里,理论曲线就来自这几个公式,仿真曲线要和它们对照才算验证通过。误比特率重合不代表代码写错,这是教科书结论。
| 对比项 | BPSK | QPSK(格雷映射) |
|---|---|---|
| 每符号比特数 | 1 | 2 |
| 星座点数 | 2 | 4 |
| 相同比特率下符号速率 | Rb | Rb/2 |
| 通带主瓣带宽约 | 2Rb | Rb |
| 相同Eb/N0下误比特率 | 0.5·erfc(√(Eb/N0)) | 与之相同 |
| 接收判决 | 一维实数阈值 | I/Q两路分别判决 |
这张表里的数据是后面所有代码断言的基础。比如带宽那一行,决定了为什么QPSK在带宽受限的移动通信系统里更吃香;误比特率那一行,又决定了为什么不能简单说“QPSK比BPSK误码率低”。仿真脚本最后画出来的曲线,本质上就是给这张表的两个关键行为打上实验证据:误比特率重合、误符号率偏高。
2.3 复杂度代价:相位模糊和接收判决差异
误码率之外,还有两个工程上很现实的差异。第一是相位模糊:QPSK的四象限星座,接收端如果锁相失步90°,星座整体旋转,没有差分编码或导频辅助时判决结果会成段错位。BPSK只有两个点,对180°相位模糊可以通过差分BPSK处理,实现上更直接。第二是接收判决的维度:BPSK只比较一个实数的正负,QPSK要同时判断实部和虚部,而且恢复比特时要注意映射顺序,这一部分恰好是写Matlab代码时最容易埋雷的地方。
在工程选型上,这个差异直接决定接收机复杂度:低信噪比、突发传输、接收机成本敏感的场景,BPSK往往更稳;带宽受限、需要提升频谱效率的场景,QPSK是绕不开的选择。这也是为什么仿真脚本里把两个解调器设计得如此不对称——BPSK的解调只有一行判定,QPSK却要先拆I/Q再重排比特。理解了这层取舍,后面读代码时就不会觉得QPSK部分是多余的了。
3. 用Matlab把两种调制跑通:发射、AWGN信道、判决的抄作业代码
下面是可直接运行的Matlab脚本核心段落。为了避免不同电脑上通信工具箱版本不一致导致跑不起来,全部用基础语法实现。整体结构是先构造随机比特源,再分BPSK、QPSK两条链路分别完成调制、加噪、判决,最后统计误码率和误符号率。
3.1 发射端:用同一份随机比特喂给两种调制器
比较的前提是输入信息一致,所以先统一生成N个随机比特,BPSK直接映射,QPSK按两位一组映射。
% 参数区:样本数固定为偶数,便于QPSK按2比特分组 N = 1e6; % 蒙特卡洛试验总比特数,越大曲线越平滑 rng(2026); % 固定随机种子,保证两次运行结果可比 bits = randi([0 1], N, 1); % (N,1) 等概率随机比特 % ---- BPSK调制:0 -> -1,1 -> +1,平均符号功率为1 ---- sym_bpsk = 2 * bits - 1; % 实数基带符号,长度N % ---- QPSK调制:每2比特为一组,格雷映射 ---- bit_pairs = reshape(bits, 2, N/2); % 每列一个QPSK符号 b1 = bit_pairs(1, :); % I路比特 b2 = bit_pairs(2, :); % Q路比特 map_I = 2 * b1 - 1; % I路幅度 +-1 map_Q = 2 * b2 - 1; % Q路幅度 +-1 sym_qpsk = (map_I + 1j * map_Q) / sqrt(2); % 每个符号平均功率归一化为1逻辑说明:bits源只用一次,BPSK链路和QPSK链路消费的比特内容完全一致,只是QPSK按两行重排后传输。格雷映射表对应关系是00→第一象限、01→第四象限、11→第三象限、10→第二象限,相邻象限只差一个比特。除以sqrt(2)这一步不是可有可无的细节,它让每个QPSK符号的模长平方恒为1,与BPSK的符号功率对齐,后面计算噪声功率才能用同一套Eb/N0公式。如果省略这一步,符号功率会变成2,Es/N0整体偏大3dB,画出来的曲线会合到理论曲线上但对应关系完全是错的。
3.2 AWGN信道:按Eb/N0手工加噪,不走awgn函数
常见的翻车方式是用awgn函数直接加“信噪比”,但awgn的SNR参数指的是信号功率和噪声功率的比值,与误码率曲线横轴的Eb/N0是两码事。这里手工计算噪声方差,保证横轴定义严格对应教科书公式。
EbN0_dB = 0:2:12; % 横轴范围,单位dB ber_bpsk = zeros(size(EbN0_dB)); % 存放BPSK误码率 ber_qpsk = zeros(size(EbN0_dB)); % 存放QPSK误码率 ser_qpsk = zeros(size(EbN0_dB)); % 存放QPSK误符号率 for k = 1:length(EbN0_dB) EbN0 = 10^(EbN0_dB(k) / 10); % 转线性值 % ---- BPSK加噪:实AWGN,噪声方差 N0/2,其中 N0 = 1/EbN0 ---- noise_var_bpsk = 1 / (2 * EbN0); % 因为BPSK符号功率Es=Eb=1 rx_bpsk = sym_bpsk + sqrt(noise_var_bpsk) * randn(N, 1); % ---- QPSK加噪:复AWGN,每维噪声方差 N0/2,N0 = 1/(2*EbN0) ---- N0_qpsk = 1 / (2 * EbN0); % Es=1,且 Es/N0 = 2*Eb/N0 noise_var_per_dim = N0_qpsk / 2; % 实部、虚部分摊噪声功率 rx_qpsk = sym_qpsk + sqrt(noise_var_per_dim) * (randn(1, N/2) + 1j*randn(1, N/2));参数说明:EbN0_dB取0到12dB、步进2dB,这个范围对BPSK足够展示从10⁻²到10⁻⁵的下降趋势;如果只看10⁻³以下的区间,可以追加到14dB,但样本数N要同步加大。randn生成的是标准正态分布随机数,乘上sqrt(噪声方差)后,方差就变成对应数值。QPSK的复噪声拆成实部、虚部两个独立的randn,每一维方差是N0/2,这里最容易写错成sqrt(N0),那样噪声总功率会偏大3dB,曲线整体偏移。
如果想快速验证链路是否跑通,把N改成1e5、EbN0_dB改成0:2:8,一分钟内就能出结果。正式画图时再回到大样本量。
3.3 接收判决与误码统计:QPSK的比特对齐
接收端BPSK只需要对实数符号做阈值判决;QPSK分别判决I/Q实虚部的正负,映射回比特流时按发射时的顺序拼接。注意QPSK接收判决出来的比特流长度是N,与发射bits完全对应,不需要额外截断。
% ---- BPSK判决:>0判为1,<0判为0,与发射映射一致 ---- bits_hat_bpsk = (rx_bpsk > 0); % ---- QPSK判决:I路对应每组第一位,Q路对应第二位 ---- I_hat = real(rx_qpsk) > 0; % 0/1逻辑向量 Q_hat = imag(rx_qpsk) > 0; % 0/1逻辑向量 bits_hat_qpsk = reshape([I_hat; Q_hat], N, 1); % 恢复为列向量 % ---- 误码率统计 ---- ber_bpsk(k) = mean(bits_hat_bpsk ~= bits); ber_qpsk(k) = mean(bits_hat_qpsk ~= bits); ser_qpsk(k) = mean((I_hat ~= b1) | (Q_hat ~= b2)); % 一个符号任一位错就算符号错 end逻辑说明:mean(bits_hat ~= bits)计算的是错误比特占比,等价于sum(...)/N。QPSK的误符号率单独统计,判断条件是I路或Q路任一比特出错就算该符号错误,对应前面理论公式里的Ps。QPSK链路从头到尾没有补位操作,因为N在参数区就设计成了偶数;任何一次reshape都要确认维度是2×(N/2),最后恢复成(N,1)列向量再比较。发射比特对齐这一点,跑仿真的人十有八九在这翻过车。
循环结束后画图:
figure; semilogy(EbN0_dB, 0.5*erfc(sqrt(10.^(EbN0_dB/10))), 'k--', 'LineWidth', 1.2); hold on; semilogy(EbN0_dB, ber_bpsk, 'bo-', 'LineWidth', 1); semilogy(EbN0_dB, ber_qpsk, 'rs-', 'LineWidth', 1); semilogy(EbN0_dB, ser_qpsk, 'm^--', 'LineWidth', 1); grid on; xlabel('Eb/N0 (dB)'); ylabel('误码率 / 误符号率'); legend('理论BER(BPSK/QPSK)', '仿真BER BPSK', '仿真BER QPSK', '仿真SER QPSK', 'Location', 'southwest');画完以后预期看见的景象是:BPSK和QPSK两条误比特率曲线几乎重合,且贴住理论曲线;QPSK的误符号率曲线明显高于误比特率曲线,大约在误码率10⁻³附近高出1.5到2倍左右。如果看见的是QPSK误比特率大幅高于BPSK,优先检查格雷映射的顺序和reshape的对齐方式,这两处是绝大多数bug的来源。
4. 画准误码率曲线:主脚本结构与三个必调参数
第3章的代码是链路核心,但解压后的工程通常还会有一个主脚本把这些段落组织起来,并把参数集中到文件头部。这里讲脚本的组织方式和调参经验。
4.1 主脚本骨架:参数、发射、信道、画图分开
常见做法是把脚本分成4段:参数区、发射端、AWGN循环、画图区。第3章的代码按这个方式归位后,主脚本的骨架是这样:
% bpsk_qpsk_compare.m 主脚本骨架 % 1) 参数区 N = 1e6; % 样本比特数 rng(2026); % 随机种子 EbN0_dB = 0:2:12; % 横轴范围 % 2) 发射端:构造同一份bits,生成sym_bpsk、sym_qpsk bits = randi([0 1], N, 1); sym_bpsk = 2 * bits - 1; bit_pairs = reshape(bits, 2, N/2); b1 = bit_pairs(1, :); b2 = bit_pairs(2, :); sym_qpsk = ((2*b1-1) + 1j*(2*b2-1)) / sqrt(2); % 3) AWGN循环:按Eb/N0手工加噪,统计BER/SER % (代码见3.2、3.3节,循环体内只做加噪、判决、统计三件事) % 4) 画图区:误码率曲线、星座图 % (代码见4.3节)这样组织不是为了好看,而是为了排错时能定位。曲线对不上理论时,先怀疑第1段参数有没有改错,再看第3段循环里的噪声功率公式,最后才怀疑第2段映射。按这个顺序排查,五分钟内就能把问题缩小到某个具体段落。
另外,Matlab脚本和函数的选择也有讲究。课设规模用脚本就够了,直接F5运行;如果后面要复用调制部分,再把发射端和判决抽成function,输入参数换成比特流和调制阶数。脚本里用变量名覆盖函数名的隐患也要注意,比如变量名取了awgn或ber,会遮蔽同名内建函数,运行时不报错但行为诡异。
4.2 三个必调参数:N、EbN0范围、随机种子
第一个参数是样本数N。N直接决定误码率曲线的下限和抖动程度。想看到10⁻⁴的误码率,N至少取10⁵;想看到10⁻⁵,N至少10⁶。因为误码率统计本质上是伯努利实验,统计误差和√(Pb(1-Pb)/N)成正比。曲线在低误码率段出现锯齿时,第一反应是增大N,而不是怀疑判决写错。
第二个参数是EbN0_dB的范围与步进。课设常用0:2:12,想延伸低误码区可以改成0:1:14,步进1dB曲线更平滑,但循环次数翻倍。注意EbN0最大值要和N联动:N=1e6时,14dB的BPSK误码率大约在10⁻⁷量级,一次运行里可能一个错误比特都没有,统计结果掉到0,semilogy画图会断线。所以要么把N加到10⁷以上,要么把最大值收到12dB。
第三个参数是随机种子rng。固定种子意味着每次运行结果可复现,改代码后能准确判断曲线变化是代码改动引起的还是随机抖动引起的。答辩时同一个图如果两次运行完全不同,解释起来非常被动。我一般习惯把所有随机源放在同一个rng种子之后生成,包括后面要扩展的16QAM仿真,保证整套代码从头到尾可复现。
这三个参数在代码里通常只改头部几行,但很多人忽略它们之间的联动关系。样本量N、最高Eb/N0、随机种子三者要一起评估,单独调大其中一个会带来运行时间暴涨或曲线残缺的副作用。
4.3 星座图和曲线双重验证:8dB下该看见什么
误码率曲线之外,还要画接收端星座图。散点图能直观暴露映射错误和功率归一化问题,比只盯数值效率高得多。
% 选8dB附近的接收信号画星座图,需要把对应ebn0点的rx单独存下来 idx = find(EbN0_dB == 8, 1); rx_bpsk_plot = rx_bpsk; % 最后一次循环的结果 rx_qpsk_plot = rx_qpsk; figure; subplot(1,2,1); plot(real(rx_bpsk_plot), zeros(size(rx_bpsk_plot)), 'b.', 'MarkerSize', 3); hold on; plot([-3 3], [0 0], 'k-'); xlabel('I路'); ylabel('Q路'); title('BPSK接收星座 (8dB)'); axis([-3 3 -1 1]); grid on; subplot(1,2,2); plot(real(rx_qpsk_plot), imag(rx_qpsk_plot), 'r.', 'MarkerSize', 3); hold on; plot([-1.5 1.5], [0 0], 'k-'); plot([0 0], [-1.5 1.5], 'k-'); xlabel('I路'); ylabel('Q路'); title('QPSK接收星座 (8dB)'); axis equal; grid on;注意这段代码假设rx_bpsk和rx_qpsk是最后一次循环(12dB)的结果,如果想指定8dB,在循环里把对应信噪比的接收信号另存一份即可。8dB下BPSK星座图会看到两团散点在±1附近,云团的半径反映了噪声功率;QPSK的四团散点中心在±0.7附近,相邻象限之间还有明显间隙。如果QPSK四个中心出现在±1附近,而不是±0.7附近,就是功率归一化的sqrt(2)被漏掉了。看到这个现象时不用怀疑是信道问题,直接回发射端检查映射代码。
运行时间上,N=1e6、7个Eb/N0点的脚本循环在普通笔记本上大约几十秒内跑完;N改成1e7会到分钟级。画星座图时如果散点太多导致图上糊成一团,可以对rx信号做随机抽样,比如rx_qpsk_plot(1:100:end),每100个点取1个显示,图像会清爽很多。
5. 仿真避坑指南:Eb/N0、噪声功率与样本数的5个排查点
BPSK和QPSK仿真的坑几乎都集中在横轴定义、噪声功率和样本量这三件事上。代码长度总共不到100行,翻车点却非常固定。下面按现象、原因、解决的顺序整理5个高频问题。
5.1 曲线整体偏移3dB:噪声功率和符号功率没对上
现象:仿真误码率曲线比理论曲线向右偏移约3dB,同等误码率下仿真需要的Eb/N0大了3dB。
原因:最常见的来源有两个。一是QPSK符号功率没有归一化,符号能量变成2而不是1,导致Es/N0偏小3dB;二是复噪声加噪时用了sqrt(N0)而不是sqrt(N0/2),噪声功率偏大3dB。这两个错误正好都表现为“整体偏移3dB”,很难凭肉眼区分。
解决:先查发射端平均功率,再查噪声公式。在代码里插入这两行:
mean(abs(sym_bpsk).^2) % 期望输出 1 mean(abs(sym_qpsk).^2) % 期望输出 1如果QPSK功率输出是2,补上除以sqrt(2)。然后核对加噪段:BPSK实噪声方差是1/(2·EbN0),QPSK每维复噪声方差是1/(4·EbN0)。这两处对上了,3dB偏移基本就消失了。
5.2 BPSK和QPSK误码率曲线重合:代码没错,是结论正确
现象:在Eb/N0横轴下,BPSK和QPSK的误比特率仿真曲线几乎重合,有人以为是代码写错了,QPSK应该更差才对。
原因:这个“重合”恰恰是教科书结论。格雷映射的QPSK在相同Eb/N0下误比特率理论值与BPSK一致,它和BPSK的真正差异体现在误符号率和带宽上,不在误比特率。如果强行把QPSK曲线调得比BPSK差,反而违背理论。
解决:不用改代码,把QPSK的误符号率SER曲线一起画出来。SER高于BER,也高于BPSK的BER,这才是QPSK在噪声性能上付出的代价。报告里说明“误比特率相同、误符号率更高、带宽减半、星座点距离更近”这套完整结论,比单独秀两条重合的BER曲线有说服力得多。
5.3 用awgn函数加噪后曲线对不上:SNR不是Eb/N0
现象:用snr = EbN0_dB调用awgn函数加噪,再以EbN0_dB为横轴画图,结果与理论曲线对不上,且偏差不是固定值。
原因:awgn函数的SNR参数指的是信号功率与噪声功率之比,单位dB,和误码率曲线横轴的Eb/N0是两套定义。调制映射后符号功率被归一化成1,此时SNR与Es/N0对应,而Es/N0与Eb/N0还差一个log2(M)的换算因子,QPSK正好是3dB。这个偏差在不同Eb/N0点上都存在,但画成log坐标后看起来像整体偏移。
解决:最稳妥的做法是放弃awgn函数,用randn手工加噪,公式按3.2节来。如果因为某些原因必须用awgn,换算关系是:对BPSK,snr_dB = EbN0_dB;对QPSK,snr_dB = EbN0_dB + 10*log10(2)。但要记得awgn默认把信号功率按1计算,如果发射端做了功率归一化之外的其他缩放,这个换算又要重算。实践下来,手工加噪的代码不过多两行,换来的是横轴定义完全可控,血泪经验是仿真里能用randn的地方就别用awgn。
5.4 低误码率抖动甚至掉零:样本量不足怎么救
现象:Eb/N0在8dB以上,仿真曲线上下跳动,某个点误码率统计出来恰好是0,semilogy图里线段断开。
原因:样本量不足。误码率统计的波动随N增大按√(1/N)下降,Eb/N0越高错误越少,少量错误比特的随机波动就主导了曲线。当预期误码率是10⁻⁶、N只有10⁵时,期望错误数只有0.1个,跑出0个错误非常正常。
解决:按目标误码率反推N,原则是每个点至少要有几十个错误比特。比如目标BER是10⁻⁵,N取10⁶时错误数约10个,曲线能看但抖动;N取10⁷更稳。如果只想快速看趋势,可以接受10⁻⁴以上的点,N=1e5够用。对于掉零的点,画图前把0值替换成NaN,semilogy会自动跳过该点,或者干脆把EbN0范围收窄到N能支撑的区间。
5.5 QPSK补位导致比特错位:reshape和长度对齐
现象:QPSK误码率统计出来比理论高好几倍,高信噪比点也不收敛,曲线整体像平移了一个符号周期。
原因:发射端为了把N个比特按2分组,给奇数长度的bits补了一位0;接收端恢复出来的比特流长度比原始bits多一个,直接用mean(hat ~= bits)比较时维度对不上,Matlab会隐式扩展或者错位比较,导致成片判决错误。
解决:从源头避免补位。参数区写死N为偶数,比如N=1e6而不是N=1e6+1;QPSK发射时用reshape(bits, 2, N/2),接收时用reshape([I_hat; Q_hat], N, 1),两端维度严格对应。如果需要处理任意长度比特流,通用做法是把有效长度记录成变量N_valid,统计时只对比前N_valid个判决比特,补位部分不计入。但这份比较代码场景里,固定N为偶数是最省心的写法,不要为通用性牺牲正确性。
6. 进阶玩法:把比较代码改造成通用调制性能验证工具
这套代码的价值不只是交一份BPSK/QPSK课设,稍微改一下就能变成验证其他调制方案的通用工具。核心改造点是把发射端映射和接收端判决各抽成一个函数,入口参数加一个M,M=2就是BPSK,M=4就是QPSK,M=16就是16QAM。以16QAM为例,映射时把比特流按log2(M)位分组,星座点用标准格雷映射铺到±1、±3格点上再做功率归一化;接收判决先按象限定位大区,再按阈值判细分比特。信道和噪声功率部分不用重写,只有映射函数和判决函数在变。这样要对比8PSK、32QAM时,改动面非常小,而且能直接复用已经调通的AWGN信道和画图代码。
验证方法上有一个值得养成的习惯:在仿真报告里把每个Eb/N0点的样本数N和目标误码率一起记录。因为误码率的统计误差大致是√(Pb(1-Pb)/N),N=1e6时,BER=10⁻³处的绝对误差约3×10⁻⁵,相对误差3%左右;到BER=10⁻⁵处,绝对误差约10⁻⁵,相对误差接近100%,几乎不可信。所以低误码率区域的每个点,都要检查错误比特数量是否足够。我后来跑仿真养成一个固定习惯:每个Eb/N0点的样本数按该点目标误码率倒数的100倍去设,比如预期BER=10⁻⁵就取N=10⁷,而不是所有点统一用同一个N。这样曲线既平滑,又知道每个点的可信度边界。
回到标题里这个rar,它给的比较脚本解决的是一个完整的判断问题:BPSK和QPSK在误比特率上等价,差在带宽和符号级错误率上。这个结论靠背公式容易忘,但自己跑一遍曲线、再对着星座图看8dB和12dB的散点分布,会比任何文档都直观。把映射、加噪、判决这三段代码按模板改一改,这套方法论还能继续用在16QAM、8PSK甚至更高阶调制的课设和项目预研里。希望帮到你。
本文还有配套的精品资源,点击获取