☰
西电通信原理大作业MATLAB实战:HDB3编码与2PSK调制及误码率仿真
2026/10/29 10:42:27 网站建设 项目流程

简介:这份文档是2023年西电通信原理课程大作业的完整参考材料,面向通信工程、电子信息等专业正在修读通信原理课程的高校学生,尤其适合需要完成4G网络综述类作业、梳理第四代移动通信技术知识框架的读者。压缩包内共1个doc文件,约306KB,内容围绕4G技术的概念、重要技术规定与主要特点展开,涵盖通信速度提升、网络频谱拓宽、通信灵活性增强、智能性能提高、兼容性能平滑、增值服务多样化、频率使用效率优化及通信费用降低等维度,并延伸至5G研发趋势与通信产业影响。文档结构清晰,可作为课程作业的写作范本与知识梳理笔记,帮助读者快速把握4G关键技术要点与论述逻辑,节省资料搜集与框架搭建时间。目前已有130人学习下载,适合作为通信原理大作业的参考与复习资料。

1. 西电通信原理大作业到底在考什么:从 HDB3 到 2PSK 的完整链路

如果你手上正躺着一份《2023年西电通信原理大作业.doc》,打开一看全是“试设计……”“试分析……”“画出……波形”,却不知道从哪下手,那这篇就是写给你的。通信原理这门课的大作业,本质不是让你背公式,而是逼你把“模拟信号数字化 → 基带编码 → 载波调制 → 信道加噪 → 接收判决”这条链路,用 MATLAB 从头到尾跑一遍,最后拿误码率和波形图说话。西电的版本通常会把 HDB3 编码、2PSK/2DPSK 调制、蒙特卡洛误码率统计这几块捆在一起,要求你既给出理论推导,又给出仿真波形和 BER 曲线。适合谁看?正在赶 due 的本科生、想复习通信链路但懒得翻书的考研党,以及第一次用 MATLAB 做系统级仿真、被for循环和采样率搞得头大的人。下面我按“先能跑通、再谈指标、最后避坑”的顺序,把这份大作业拆成可复现的步骤。

2. HDB3 与 2PSK 的 MATLAB 实现:从信源到已调信号

2.1 为什么大作业总拿 HDB3 开刀

通信原理大作业里,基带编码部分几乎绕不开 HDB3。原因很实际:它同时考了“连零抑制”和“极性交替”两个知识点,又不像曼彻斯特编码那样一眼看穿。HDB3 的核心规则是四连零替换:当信码中出现 4 个连续 0 时,用000V或B00V替换,其中 V 是破坏脉冲,必须与前一个非零脉冲同极性;B 是调节脉冲,用来保证相邻 V 脉冲极性交替。很多同学翻车就翻在“V 和 B 的极性判断顺序”上——先判断当前 4 零之前非零脉冲的个数是奇数还是偶数,再决定用哪种替换模式。

我一般会先把规则写成一张状态表,再落代码。下面是最小可跑的 HDB3 编码函数,输入是 0/1 序列,输出是 +1/0/-1 三电平序列。

function [hdb3_out, v_pos, b_pos] = hdb3_encode(bits) % bits: 输入二进制序列,元素为 0 或 1 % hdb3_out: 输出三电平序列,+1 / 0 / -1 % v_pos, b_pos: 记录 V 脉冲和 B 脉冲的位置,方便调试 bits = bits(:)'; n = length(bits); hdb3_out = zeros(1, n); last_pulse_pol = -1; % 上一个非零脉冲极性,初始设为 -1,保证第一个脉冲为 +1 last_v_pol = -1; % 上一个 V 脉冲极性 one_count = 0; % 自上一个 V 之后的非零脉冲计数 i = 1; v_pos = []; b_pos = []; while i <= n if bits(i) == 1 hdb3_out(i) = -last_pulse_pol; % 交替反转 last_pulse_pol = hdb3_out(i); one_count = one_count + 1; i = i + 1; else % 检查是否连续 4 个 0 if i + 3 <= n && all(bits(i:i+3) == 0) if mod(one_count, 2) == 1 % 奇数个 1,用 000V 替换 hdb3_out(i:i+3) = [0 0 0 last_pulse_pol]; % V 与上一个非零同极性 v_pos = [v_pos, i+3]; last_pulse_pol = last_pulse_pol; % V 不改变交替基准?注意:V 之后基准要翻转 last_pulse_pol = -last_pulse_pol; % 实际实现中 V 后极性基准翻转 one_count = 0; else % 偶数个 1,用 B00V 替换 b_pol = -last_pulse_pol; hdb3_out(i) = b_pol; hdb3_out(i+1:i+2) = [0 0]; hdb3_out(i+3) = last_pulse_pol; % V 与上一个非零同极性 b_pos = [b_pos, i]; v_pos = [v_pos, i+3]; last_pulse_pol = -last_pulse_pol; one_count = 0; end i = i + 4; else hdb3_out(i) = 0; i = i + 1; end end end end

这段代码里最容易写错的是last_pulse_pol在 V 脉冲之后的更新。注意看注释:V 脉冲本身要满足“与上一个非零脉冲同极性”,但 V 之后,极性交替的基准要翻转,否则下一个 1 的极性会错。参数one_count统计的是自上一个 V 之后的非零脉冲个数,用来决定用000V还是B00V。如果你跑出来的波形在四连零处出现连续两个同极性 V,八成就是这里没翻转。

2.2 2PSK 调制:把基带信号搬上载波

HDB3 输出的是三电平基带信号,但大作业通常要求继续做 2PSK。2PSK 的表达式是s(t) = A cos(2πf_c t + φ_n),其中φ_n由二进制符号决定,通常 0 对应 0 相位,1 对应 π 相位。实现时有两种写法:一种是直接生成两个不同相位的余弦波再拼接,另一种是用cos(2πf_c t + π * bit)。我推荐第二种,代码短且不容易错。

fc = 2000; % 载波频率 2kHz fs = 20000; % 采样率 20kHz,满足 fs >> fc Tb = 1/1000; % 码元宽度 1ms sps = fs * Tb; % 每个码元的采样点数 t = 0:1/fs:(length(bits)*Tb - 1/fs); % 将 HDB3 三电平映射为二进制:非零 -> 1,零 -> 0(仅用于 2PSK 演示) bits_for_psk = (hdb3_out ~= 0); baseband = repelem(bits_for_psk, sps); % 每个码元扩展 sps 个点 carrier = cos(2*pi*fc*t); psk_signal = cos(2*pi*fc*t + pi*baseband); % 0 相位 / π 相位

这里repelem是关键,它把每个符号扩展成sps个采样点,保证基带和载波长度一致。sps一般取 20 以上,否则波形看起来像三角形,频谱混叠严重。如果你用rectpulse也可以,但repelem更直观。注意t的长度要和baseband严格对齐,否则cos会报维度错误——这是新手最常见的翻车点之一。

2.3 加噪与误码率统计:蒙特卡洛不是随便跑跑

大作业最后通常要求画 BER 曲线。理论公式是Pe = Q(sqrt(2*Eb/N0)),但仿真时你要自己生成高斯白噪声、做相干解调、抽样判决。我一般用蒙特卡洛循环,每个 SNR 点跑 10^5 个码元,保证曲线平滑。

EbN0_dB = 0:1:10; ber_sim = zeros(size(EbN0_dB)); num_bits = 1e5; for k = 1:length(EbN0_dB) EbN0 = 10^(EbN0_dB(k)/10); noise_var = 1/(2*EbN0); % 实信号噪声方差 bits_tx = randi([0 1], 1, num_bits); % 2PSK 映射:0 -> +1, 1 -> -1 symbols = 1 - 2*bits_tx; % 加高斯白噪声 noise = sqrt(noise_var) * randn(1, num_bits); rx = symbols + noise; % 判决 bits_rx = rx < 0; ber_sim(k) = sum(bits_rx ~= bits_tx) / num_bits; end semilogy(EbN0_dB, ber_sim, 'o-'); hold on; EbN0_lin = 10.^(EbN0_dB/10); ber_theory = qfunc(sqrt(2*EbN0_lin)); semilogy(EbN0_dB, ber_theory, 'r--'); grid on; xlabel('Eb/N0 (dB)'); ylabel('BER'); legend('仿真', '理论');

参数说明:noise_var = 1/(2*EbN0)是因为实信号下噪声功率谱密度双边为 N0/2,而 Eb 归一化为 1。如果你用复信号,方差要改成1/EbN0。qfunc是 MATLAB 自带的 Q 函数,不用自己写。跑完如果仿真曲线和理论曲线在低 SNR 处偏离,先检查噪声方差是否算错,再检查判决门限是不是 0。

3. 采样率、滤波器与同步:大作业里最容易忽略的三个参数

3.1 采样率不是越高越好

很多同学觉得fs设得越大越精确,结果跑一次仿真要等十分钟。实际上,对于 2PSK,只要fs ≥ 4*fc就能画出像样的波形,fs = 10*fc已经足够。我一般取fs = 20*fc,兼顾波形平滑和速度。如果你还要做频谱分析,fs至少是信号最高频率的 2.5 倍,否则fft出来的谱会混叠。大作业里常见的要求是“画出已调信号波形和功率谱”,这时候fs取 20kHz、fc取 2kHz 是稳妥的。

3.2 带通滤波器:不是必须,但加了更像“通信系统”

理论上的 2PSK 误码率推导假设接收端有理想带通滤波器。仿真时如果你直接加噪声再判决,得到的 BER 会和理论值有偏差,尤其是在低 SNR 下。我一般会在接收端加一个巴特沃斯带通滤波器,中心频率fc,带宽2*Rb。用butter设计,filtfilt零相位滤波。

Rb = 1000; % 码元速率 bw = 2*Rb; % 带宽 [b, a] = butter(4, [(fc-bw/2) (fc+bw/2)]/(fs/2), 'bandpass'); rx_filtered = filtfilt(b, a, rx_signal);

注意filtfilt会引入瞬态,前几个码元可能失真,统计 BER 时要把前 100 个点丢掉。如果你用filter,会有相位延迟,判决前要补偿。大作业里如果没要求滤波器,可以不加,但加了之后曲线更贴近理论,答辩时也好解释。

3.3 同步:为什么你的 BER 曲线总是比理论高一点

仿真里最容易忽略的是定时同步。蒙特卡洛循环里我直接在每个码元中心抽样,这是“理想同步”假设。实际系统中如果抽样点偏移,BER 会急剧恶化。大作业通常不要求做同步算法,但你要在报告里说明“本仿真假设理想定时同步”。如果你非要加一点真实感,可以在抽样时随机偏移 ±5% 的码元宽度,看看 BER 恶化多少——这个对比实验写在报告里很加分。

4. 避坑与排查:HDB3 和 2PSK 仿真中的 5 个血泪教训

4.1 现象:HDB3 输出在四连零处出现连续同极性 V

原因:last_pulse_pol在 V 脉冲之后没有翻转,导致下一个 V 的极性判断错误。解决:在替换000V或B00V之后,强制last_pulse_pol = -last_pulse_pol,并重置one_count = 0。用v_pos数组打印所有 V 的位置,检查相邻 V 的极性是否交替。

4.2 现象:2PSK 已调信号波形看起来像调幅,包络不为常数

原因:基带信号没有扩展成sps个采样点,或者t的长度和baseband不一致,导致cos的相位跳变点错位。解决:用repelem扩展后,检查length(baseband) == length(t)。如果不等,用t = t(1:length(baseband))截断。另外,cos(2*pi*fc*t + pi*baseband)里baseband必须是 0/1 逻辑值,不能是 +1/-1。

4.3 现象:BER 仿真曲线在高 SNR 处不再下降,出现“地板”

原因:蒙特卡洛点数不够,或者噪声方差计算错误。当 BER 低于 1e-4 时,10^5 个点只能统计到几个错误,曲线会抖动。解决:高 SNR 段把num_bits提高到 10^6,或者用“错误数达到 100 就停止”的自适应策略。同时检查noise_var是否用了1/(2*EbN0),复信号要用1/EbN0。

4.4 现象:加了带通滤波器后 BER 反而变差

原因:滤波器阶数太高导致群延迟过大,filtfilt虽然零相位,但瞬态响应影响了前几个码元;或者带宽设得太窄,把信号边带滤掉了。解决:带宽至少取2*Rb,阶数降到 2 或 3。统计 BER 时跳过前 200 个采样点。如果还不行,先不加滤波器跑一遍,确认基础链路没问题再逐步加。

4.5 现象:MATLAB 报错“向量长度必须相同”或“索引超出矩阵维度”

原因:bits是行向量,hdb3_out初始化成列向量,后面repelem又要求行向量;或者i+3越界。解决:在函数开头统一bits = bits(:)',所有数组用行向量。循环里判断i+3 <= n再访问。调试时用dbstop if error让 MATLAB 停在出错行,看i和n的值。

5. 进阶技巧:用 comm 工具箱加速仿真与验证

如果你已经跑通了上面的基础版,想在大作业里做出点区分度,我建议用 MATLAB 的 Communications Toolbox 里的comm.HDB3Encoder和comm.PSKModulator做交叉验证。自己写的函数和工具箱结果对比,能快速定位逻辑错误。比如:

hdb3_std = comm.HDB3Encoder; psk_mod = comm.PSKModulator(2, 'PhaseOffset', 0, 'BitInput', true); hdb3_ref = hdb3_std(bits_tx'); psk_ref = psk_mod(bits_tx');

注意工具箱的 HDB3 编码器输入输出都是二进制,不是三电平,它内部做了映射。对比时要把你的三电平输出转成二进制再比。另外,comm.PSKModulator默认是二进制输入,PhaseOffset设 0 对应 0 相位,设 π/2 对应 QPSK 的偏移。用工具箱跑一遍 BER,和你手写的蒙特卡洛曲线叠在一起,如果两条线重合,说明你的噪声方差和判决门限都对了。

还有一个省时间的习惯:把num_bits和EbN0_dB做成脚本参数,用parfor并行跑 SNR 循环。MATLAB 的并行工具箱在 2023 版之后对parfor支持很好,10^6 个点跑 11 个 SNR 点,普通笔记本也就几十秒。但注意parfor里不能用semilogy,要把结果存成数组,循环结束后统一画图。

最后说个我自己的教训:大作业报告里一定要写清楚“仿真参数表”,包括fc、fs、Rb、num_bits、滤波器阶数。答辩时老师第一个问的就是“你这个采样率怎么选的”。我当年第一次做的时候没写,被追问了五分钟,后来每次都在报告开头放一张参数表,省事又显专业。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询