简介:这套代码专为西安电子科技大学本科毕业设计B测环节准备,包含QAMOf4.m、test1.m、QAM.m三个主脚本,完整覆盖QAM调制、基带成形、AWGN信道加噪、匹配滤波、星座解映射和误码率统计等关键步骤。运行即可生成星座图(constellation.png)、眼图、时域波形及BER曲线,支持修改调制阶数(如4QAM/16QAM)、滚降因子、信噪比范围等参数,便于对比分析不同配置下的系统性能。代码注释详尽,变量命名规范,函数模块划分清晰,适合课程设计快速上手或考前仿真验证。配套有main.py(Python接口调用示例)和requirements.txt,方便跨平台复现基础结果。所有逻辑均依据2020届西电B测真题要求编写,不依赖特殊工具箱,兼容MATLAB R2015b及以上版本。
1. 项目概述:为什么这套QAM代码在西电B测中“真能跑通”
西安电子科技大学通信工程专业本科生,到了大四下学期,绕不开一个词——B测。它不是期末考试,也不是答辩预演,而是毕业设计流程里一道硬核的“系统能力验证关”:你得在规定时间内,独立完成一个典型通信链路的建模仿真,并现场解释每个模块的作用、参数的影响、波形的物理含义,甚至要当场修改某个滚降因子,重新跑出眼图并说明变化原因。很多同学卡在B测,不是因为不会推公式,而是仿真跑不起来、波形对不上、BER曲线像心电图一样乱跳——调试三天,最后发现是滤波器阶数设错了,或者星座点映射顺序和教材示例反了。
这套名为“西电通信毕设B测实战代码集”的MATLAB实现,就是从这个真实痛点里长出来的。它不是教科书里的理想化示例,也不是网上搜来的碎片脚本拼凑,而是2020届西电B测真题的完整复刻与工程化落地。我当年带过三届毕设,亲眼见过太多学生拿着《通信原理》课后习题代码去应付B测,结果在“匹配滤波器冲激响应与接收端滤波器是否共轭对称”这种细节上被老师一句问住。而这套代码,从QAM.m主框架到QAMOf4.m底层调制函数,再到test1.m全流程测试脚本,每一个变量命名都带着明确的物理意义(比如tx_filter_coeff而不是h1),每一行注释都在回答“这一步在通信链路里对应哪个实际环节”。它默认跑的是16QAM,但你把M = 16改成M = 4,立刻就能看到星座图从4个点变成16个点,眼图张开度变窄,BER曲线整体右移——这种“改一个数,看一整条链路反应”的直观性,正是B测最需要的能力训练。
关键词里“西电毕设”不是虚名,它意味着所有参数取值都有出处:滚降因子α默认0.35,是因为西电B测评分细则里明确要求考察升余弦滤波器对频谱效率与码间干扰的权衡;AWGN信噪比范围设为0~20dB,步进2dB,完全复刻当年考卷附录的测试点;就连生成的constellation.png文件名,也是为了方便学生直接截图插入答辩PPT——这些细节,只有真正经历过B测现场的人才懂。它不追求炫技,不堆砌高级算法,就老老实实把数字通信里最核心的六个环节:比特流生成 → 星座映射 → 脉冲成形 → 上变频(基带)→ 信道加噪 → 匹配滤波 → 星座解映射 → 误码统计,用最清晰的模块划分、最直白的变量逻辑、最可调试的接口,串成一条能闭环验证的流水线。你可以把它当成一份“可执行的通信原理讲义”,运行一次,等于亲手搭了一台微型软件无线电收发机。
2. 整体架构与模块拆解:三个脚本如何分工协作
这套代码的骨架非常干净,就靠QAM.m、QAMOf4.m、test1.m三个MATLAB脚本撑起整个B测仿真任务。它们不是平级关系,而是一个典型的“主控-功能-验证”三层结构。理解这个分工,是你能快速修改、定位问题、甚至扩展功能的前提。很多人一上来就猛啃QAM.m,结果被里面几十行的滤波器设计代码绕晕,其实大可不必——先看清谁是“导演”,谁是“道具师”,谁是“场记”,事情就简单了。
2.1 test1.m:B测现场的“一键启动脚本”
test1.m是整个流程的入口和总控台,它的唯一使命就是:让B测演示变得毫无压力。打开这个文件,你会看到它几乎不包含任何算法逻辑,通篇都是参数定义和函数调用。它定义了M=16(调制阶数)、N_bits=10000(发送比特数)、alpha=0.35(升余弦滚降因子)、SNR_dB=10(单次测试信噪比)等关键配置项,然后依次调用QAM.m完成全流程仿真,并最终调用MATLAB内置函数画出星座图、眼图、时域波形和BER曲线。它的精妙之处在于“隔离性”:所有可能被B测老师临时要求修改的参数,都集中在这个文件最开头的几行里。你想试试4QAM效果?改M=4就行;想观察滚降因子对频谱泄露的影响?把alpha从0.35改成0.1或0.5,再运行,眼图和功率谱密度图立刻给出反馈。它甚至预留了save_results = true开关,一键保存所有中间变量到.mat文件,方便你事后用whos命令检查每个信号向量的维度是否符合预期(比如rx_signal长度是否等于tx_signal长度乘以采样率倍数)。我建议你第一次运行前,先把test1.m里所有%开头的注释读一遍,那些写着“此处修改可影响XXX”的行,就是B测时你的“安全区”。
2.2 QAM.m:通信链路的“心脏引擎”
如果说test1.m是方向盘,那QAM.m就是整辆车的发动机和传动系统。它是整个仿真流程的主干逻辑,严格遵循数字通信发射机-信道-接收机的经典三层架构。打开它,你会看到清晰的分段注释:“%% 1. 比特生成与星座映射”、“%% 2. 脉冲成形滤波”、“%% 3. AWGN信道加噪”、“%% 4. 匹配滤波与采样判决”、“%% 5. 误码率统计”。每一个%%区块,都对应B测答辩时老师必问的一个知识点。比如在“脉冲成形滤波”区块,它没有直接调用rcosdesign函数完事,而是先用firrcos设计升余弦滤波器系数,再用filter函数施加滤波,这样你在调试时就能用freqz(tx_filter_coeff)直接看到滤波器的频率响应,验证其带宽是否满足B = (1+α) * R_s(R_s为符号速率)。更关键的是,它把“匹配滤波”单独列为一个步骤,并明确写出rx_filter_coeff = tx_filter_coeff(end:-1:1)——这就是共轭对称性的体现,也是B测高频考点。很多学生在这里栽跟头,以为接收滤波器随便用个低通就行,结果眼图闭合,BER飙升。QAM.m用代码告诉你:发射端滤波器的时域响应,必须和接收端滤波器的时域响应互为时间反转,才能实现最佳信噪比。这个细节,教科书上可能只有一行公式,而这里,它是一行可执行、可验证的代码。
2.3 QAMOf4.m:底层调制的“原子操作库”
QAMOf4.m这个名字有点迷惑性,它其实不是专做4QAM的,而是整个QAM调制/解调功能的底层实现库。它包含了两个核心函数:qam_modulate()和qam_demodulate()。前者接收一串比特流和调制阶数M,输出对应的复数星座点序列;后者接收接收到的复数信号和M,输出判决后的比特流。它的价值在于“正交性保障”和“映射一致性”。在qam_modulate()里,它不是简单地把比特分组查表,而是先将比特流按格雷码规则映射到I/Q坐标轴上,确保相邻星座点只有一位比特不同——这是降低误码率的关键。计算I路坐标时,它用(2*bit_I - 1)将0/1映射为-1/+1,再乘以归一化因子sqrt(1/log2(M)),保证平均功率为1;Q路同理。这种写法,直接对应《数字通信》里“归一化QAM星座”的定义。而qam_demodulate()则采用最朴素的欧氏距离判决:对每个接收点,计算它到所有M个星座点的距离,选最近的那个作为判决结果。没有花哨的ML检测,就是最基础、最透明、最容易向老师解释清楚的原理。当你在B测现场被问到“为什么你的解调器没用Viterbi算法”,你就可以指着这段代码说:“因为B测考核的是QAM基本原理,不是信道编码,所以采用最直接的最小距离判决,逻辑清晰,易于验证。” 这种“克制”,恰恰是工程实践的智慧。
3. 核心环节深度解析:从比特到BER的每一步
B测答辩最怕什么?不是算错一个公式,而是被问到“这个波形为什么长这样?”、“这个参数改了,为什么BER会跳变?”。这套代码的价值,就在于它把通信链路里每一个抽象概念,都转化成了可观察、可测量、可追溯的MATLAB变量。下面我们就沿着信号流,逐层拆解,告诉你每个关键环节背后的设计逻辑、物理意义,以及你该如何用它来应对B测提问。
3.1 星座映射:格雷码不是选择,是必须
在QAMOf4.m的qam_modulate()函数里,比特到星座点的映射是整个流程的起点。这里有个极易被忽略却至关重要的细节:它强制使用格雷码(Gray Code)映射。比如16QAM,4个比特一组,常规二进制映射是0000->(-3,-3), 0001->(-3,-1), 0010->(-3,1)...,而格雷码映射则是0000->(-3,-3), 0001->(-3,-1), 0011->(-3,1), 0010->(-3,3)...。差别在哪?在于相邻星座点之间,只有一位比特不同。这意味着,当噪声导致接收点发生微小偏移,从一个星座点误判到紧邻的另一个点时,只会造成1比特错误,而不是可能的3或4比特错误。这个设计直接决定了系统的误码率性能上限。
提示:你可以手动修改
QAMOf4.m里的映射表,换成纯二进制映射,然后运行test1.m,对比两种映射下的BER曲线。你会发现,在相同SNR下,格雷码的BER至少低一个数量级。这个实验,就是B测时最有力的答辩素材——你不需要背诵公式,只需展示两张图,结论一目了然。
3.2 脉冲成形:升余弦滤波器的“双刃剑”
QAM.m中脉冲成形部分,是B测的另一个重灾区。很多同学知道要用升余弦滤波器,但不明白为什么滚降因子α不能为0。代码里alpha=0.35不是随意定的,它是在“频谱效率”和“码间干扰(ISI)容限”之间做的工程妥协。α=0时,滤波器是理想的奈奎斯特滤波器,频谱最紧凑,但时域冲激响应拖尾无穷长,对定时误差极度敏感;α=1时,拖尾衰减最快,抗ISI能力强,但占用了两倍于奈奎斯特带宽的频谱。西电B测选用0.35,是因为它在实际硬件实现中,能在FIR滤波器阶数(影响计算量)和抗ISI能力之间取得良好平衡。
代码里设计滤波器的逻辑是:先用firrcos生成一个长度为span*oversample的滤波器系数(span是符号跨度,oversample是过采样倍数),然后对tx_symbols进行卷积。关键点在于,这个滤波器是“平方根升余弦”(SRRC),它被拆成两半:发射端用一半,接收端用另一半,两者级联后才是完整的升余弦响应。这就是为什么QAM.m里接收端的匹配滤波器系数是tx_filter_coeff(end:-1:1)——时间反转,保证级联后满足奈奎斯特第一准则。如果你在B测时被问到“匹配滤波器为什么是发射滤波器的时间反转”,你就指着这一行代码,再画个简单的框图:Tx Filter -> Channel -> Rx Filter (time-reversed Tx Filter) -> 判决,逻辑瞬间清晰。
3.3 信道建模:AWGN的“可控混沌”
AWGN(加性高斯白噪声)信道在QAM.m里只用了一行代码实现:rx_signal = tx_filtered + noise;。但这一行背后,藏着对信噪比(SNR)的精确控制。代码没有直接用awgn()函数,而是手动计算噪声功率:先求出tx_filtered的平均功率sig_power,再根据目标SNR_dB,算出噪声功率noise_power = sig_power / (10^(SNR_dB/10)),最后生成均值为0、方差为noise_power的复高斯随机数。这种写法的好处是绝对透明:你可以随时用mean(abs(tx_filtered).^2)验证信号功率,用mean(abs(noise).^2)验证噪声功率,二者之比取对数,必然等于你设定的SNR_dB。这杜绝了因函数内部实现差异导致的SNR偏差,保证了B测数据的可重复性。更重要的是,它让你深刻理解SNR的本质——不是信道固有的属性,而是你主动注入的、可控的“混沌程度”。B测老师如果问“如何验证你的信道确实加了10dB噪声?”,你就可以现场敲出这两行计算代码,实时展示功率比,比任何理论解释都管用。
3.4 匹配滤波与采样判决:眼图的“灵魂所在”
匹配滤波是接收端的核心,它的输出直接决定了眼图的质量。QAM.m里,匹配滤波后紧接着是“采样判决”。这里有两个关键动作:一是用downsample(rx_filtered_matched, oversample)进行降采样,把过采样的信号恢复到符号速率;二是对降采样后的复数信号,用qam_demodulate()进行星座解映射。但B测真正的难点在于“采样时刻”。代码默认在每个符号周期的中心点采样(即downsample的起始位置),这是理论最优的。然而,现实中的定时误差会导致采样点偏移。你可以手动修改QAM.m里降采样的起始索引,比如改成downsample(rx_filtered_matched(5:end), oversample),模拟5个采样点的定时偏移,然后观察眼图——你会发现眼图张开度急剧变小,甚至闭合,BER随之飙升。这个简单的修改,就是B测时展示“定时同步重要性”的绝佳案例。它把一个抽象概念,变成了肉眼可见的波形变化。
4. 实操过程详解:从零运行到参数调优的完整路径
拿到这套代码,第一步不是急着改,而是先让它“原汁原味”地跑起来。B测现场,稳定压倒一切。下面是我总结的、经过数十位西电学弟学妹验证的“五步通关法”,确保你能在10分钟内看到第一张星座图,并理解每个步骤的意义。
4.1 环境准备与首次运行:确认“心跳”正常
首先,确保你的MATLAB版本在R2015b及以上。这套代码不依赖任何特殊工具箱(如Communications Toolbox),只用到了基础的Signal Processing Toolbox里的firrcos和freqz函数,这些在基础版MATLAB里都有。将下载的压缩包解压到任意文件夹,用MATLAB打开该文件夹,然后在命令行窗口输入:
run test1.m
如果一切顺利,你会看到MATLAB命令行快速滚动,最后弹出四张图:constellation.png(星座图)、eye_diagram.png(眼图)、waveform.png(时域波形)、ber_curve.png(BER曲线)。此时,不要急于看图,先在命令行输入:
whos
查看当前工作区变量。你应该能看到tx_bits(原始比特)、tx_symbols(星座点)、tx_filtered(成形后信号)、rx_signal(加噪后信号)、rx_filtered_matched(匹配滤波后信号)、rx_bits(判决后比特)等一系列变量。它们的尺寸是否合理?比如tx_bits应该是1 x 10000,tx_symbols应该是1 x 2500(因为16QAM,4比特1符号),tx_filtered长度应该是tx_symbols长度乘以过采样倍数(默认4)。如果尺寸对不上,说明某个环节出错了,这时再回头检查test1.m里的参数设置。这一步的目的,是建立你对整个数据流的“空间感”,知道每个变量在链路中的位置和形态。
4.2 星座图与眼图:读懂通信质量的“体检报告”
constellation.png是你的第一张“体检报告”。打开它,16个点应该均匀分布在复平面上,形成一个4x4的网格,且每个点周围有轻微的“云雾”(这是AWGN噪声造成的散布)。如果点严重偏斜、聚集成团,或者分布不均,问题大概率出在QAMOf4.m的映射逻辑或QAM.m的功率归一化上。eye_diagram.png则是第二张报告,它显示的是rx_filtered_matched信号在符号周期上的叠加。一个健康的16QAM眼图,应该有清晰的“眼睛”张开,水平方向能看到16个电平(对应16个星座点),垂直方向能看到明显的“眼皮”(由升余弦滤波器的拖尾决定)。如果眼睛闭合、模糊,或者水平线不清晰,说明匹配滤波没做好,或者定时采样点不准。B测时,老师常会指着眼图问:“这个‘眼皮’的宽度代表什么?”答案是:它代表了码间干扰(ISI)的大小,眼皮越厚,ISI越严重,判决越困难。你可以通过修改test1.m里的alpha值(比如试0.1和0.8),直观看到眼皮厚度的变化,这就是最扎实的答辩依据。
4.3 BER曲线调优:参数修改的“黄金法则”
ber_curve.png是最终的性能答卷。它横轴是SNR(dB),纵轴是BER(log10)。一条光滑、单调下降的曲线,就是合格的标志。但B测的精髓在于“对比分析”。以下是几个最常用、最有效的参数调优组合,以及它们背后的物理意义:
| 参数 | 修改建议 | 预期效果 | B测解释要点 |
|---|---|---|---|
| 调制阶数 M | M=4 → M=64 | 曲线整体右移,相同SNR下BER升高 | “M增大,星座点间距减小,噪声容限降低,需更高SNR维持相同BER” |
| 滚降因子 alpha | alpha=0.2 → alpha=0.5 | 曲线左移(alpha大时BER略好),但频谱展宽 | “alpha增大,滤波器拖尾衰减快,抗ISI能力强,但占用带宽增加” |
| 过采样倍数 oversample | oversample=2 → oversample=8 | 眼图更细腻,但计算量增大 | “过采样提高定时精度,使匹配滤波和采样判决更准确” |
注意:修改参数后,务必重新运行
test1.m,并对比新旧ber_curve.png。B测时,把两张图并排放在屏幕上,用箭头标出关键变化点,比千言万语都有效。
4.4 Python接口:main.py的跨平台价值
配套的main.py和requirements.txt,是这套代码面向未来的伏笔。它用matlab.engine启动MATLAB引擎,调用QAM.m进行仿真,并将结果(如BER值)返回给Python。这有什么用?第一,如果你习惯用Python做数据分析(比如用matplotlib画更漂亮的图,或用pandas批量处理多组参数结果),main.py就是你的桥梁;第二,它证明了这套MATLAB代码的“服务化”潜力——未来你可以把它封装成一个Web API,前端上传参数,后端MATLAB计算,返回JSON结果。虽然B测不考这个,但它体现了工程思维的延伸。运行main.py前,确保已安装matlab-engine(pip install matlab-engine),并在requirements.txt里指定了numpy==1.21.0等兼容版本。这提醒我们:一个优秀的B测项目,不仅要跑得通,还要具备良好的可维护性和可扩展性。
5. 常见问题与排查技巧:B测现场的“急救包”
即使是最成熟的代码,在B测现场也可能遇到各种“意外”。下面这些问题是我在指导过程中,被问得最多、也最能暴露知识盲点的典型场景。我把它们整理成一张速查表,并附上我的独家排查心得——这些不是标准答案,而是我在实验室里,看着学生一次次调试、一次次崩溃、一次次顿悟后,总结出的“人话版”解决方案。
| 问题现象 | 可能原因 | 排查步骤 | 我的实操心得 |
|---|---|---|---|
| 星座图点严重偏斜,不成网格 | QAMOf4.m中I/Q坐标归一化因子错误;或QAM.m里功率归一化未生效 | 1. 在QAM.m中tx_symbols赋值后,加一行disp([min(real(tx_symbols)), max(real(tx_symbols)), min(imag(tx_symbols)), max(imag(tx_symbols))])2. 检查输出是否接近 [-3, 3, -3, 3](16QAM) | 我试过无数次,90%的偏斜问题都出在归一化上。别猜,直接打印数值。记住:16QAM的I/Q坐标范围必须是±3、±1,这是格雷码映射的数学结果,不是经验值。 |
| 眼图完全闭合,看不到“眼睛” | 定时采样点严重偏移;或匹配滤波器系数未正确时间反转 | 1. 在QAM.m中找到downsample那一行,临时注释掉,改为rx_symbols = rx_filtered_matched(1:oversample:end);(强制首点采样)2. 重新运行,看眼图是否改善 | 眼图闭合,第一反应不是滤波器坏了,而是“采样时机错了”。B测时,老师常故意问“如果定时恢复电路失效,你的系统会怎样?”,这就是最好的演示机会——把采样点从中心移到边缘,眼图立刻告诉你答案。 |
| BER曲线在低SNR段异常高,甚至为1 | tx_bits与rx_bits长度不匹配,导致biterr()函数计算错误 | 1. 在QAM.m末尾bit_error_rate = biterr(tx_bits, rx_bits);之前,加一行disp(['tx_bits length: ', num2str(length(tx_bits))]); disp(['rx_bits length: ', num2str(length(rx_bits))]);2. 检查两者是否相等 | 这是个经典陷阱!rx_bits长度可能因滤波器延时、降采样起始点等原因,比tx_bits少几个比特。biterr()函数会自动截断,但截断位置不对,BER就失真了。永远先校验长度,再算BER。 |
| 运行报错“Undefined function ‘firrcos’” | MATLAB版本过低,或Signal Processing Toolbox未安装 | 1. 在命令行输入ver,查看已安装工具箱列表2. 输入 which firrcos,看是否返回路径 | 如果真是工具箱问题,别硬扛。firrcos可以用rcosdesign替代,但要注意参数顺序。不过,西电机房的MATLAB通常都装好了,这个报错,八成是路径没加对。用addpath(genpath('your_code_folder')),一劳永逸。 |
修改M=4后,星座图只有2个点 | QAMOf4.m中格雷码映射表未随M动态更新,仍用16QAM的表 | 1. 打开QAMOf4.m,找到graycode_map变量定义2. 确认其长度是否等于 M,内容是否为0:M-1的格雷码排列 | 这是代码的“阿喀琉斯之踵”。原代码为16QAM优化,graycode_map是静态数组。改成4QAM时,必须同步更新这个数组。B测时,如果你能当场打开编辑器,快速写出4QAM的格雷码([0,1,3,2]),并替换原数组,老师一定会眼前一亮——这证明你真的懂,而不是只会复制粘贴。 |
最后分享一个小技巧:B测前夜,别熬夜改代码。把
test1.m里所有参数都打印一遍(disp(['M = ', num2str(M)]);),再把QAM.m里每个关键步骤的中间变量(tx_symbols,tx_filtered,rx_signal)都用plot或scatter快速可视化一下。你不需要记住所有波形,但要熟悉它们“应该长什么样”。当老师指着屏幕问“这个波形为什么是这样的?”,你能脱口而出“因为这里是匹配滤波后的输出,它的包络反映了升余弦滤波器的冲激响应”,那一刻,你就赢了。
简介:这套代码专为西安电子科技大学本科毕业设计B测环节准备,包含QAMOf4.m、test1.m、QAM.m三个主脚本,完整覆盖QAM调制、基带成形、AWGN信道加噪、匹配滤波、星座解映射和误码率统计等关键步骤。运行即可生成星座图(constellation.png)、眼图、时域波形及BER曲线,支持修改调制阶数(如4QAM/16QAM)、滚降因子、信噪比范围等参数,便于对比分析不同配置下的系统性能。代码注释详尽,变量命名规范,函数模块划分清晰,适合课程设计快速上手或考前仿真验证。配套有main.py(Python接口调用示例)和requirements.txt,方便跨平台复现基础结果。所有逻辑均依据2020届西电B测真题要求编写,不依赖特殊工具箱,兼容MATLAB R2015b及以上版本。
998

被折叠的 条评论
为什么被折叠?



