多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

QPSK调制解调MATLAB仿真:从星座图到误码率曲线

QPSK调制解调MATLAB仿真:从星座图到误码率曲线 简介这份MATLAB仿真资源面向通信原理学习者与数字调制入门者围绕QPSK调制解调全流程展开帮助读者打通从理论公式到代码实现的认知断层。压缩包共5个文件以4个m脚本和1个txt说明为主整体约6KB其中主函数负责调制解调主流程其余脚本分别承担低通滤波、升余弦滚降成型滤波以及双边与单边频谱绘制结构清晰、便于分模块阅读。代码覆盖二进制随机序列生成、双极性变换、串并转换、上采样、成型滤波、载波调制、高斯白噪声、相干解调、匹配滤波、抽样判决与并串转换等环节并输出时域波形、功率谱、频谱图、星座图、眼图及理论与仿真误码率曲线每步均附详细注释。已有3800余人学习作者确认代码在2018与2023版MATLAB均可无报错运行适合边调试边理解成型滤波限带、匹配滤波消除码间干扰等关键机制。1. 从一次“星座图糊成一团”说起这份 QPSK 调制解调仿真到底能帮你什么刚入行做通信基带那会儿我最怕的不是写不出代码而是仿真跑出来了、波形却不对——星座图四个点糊成一团误码率曲线平得像条死鱼。后来才发现问题根本不在 QPSK 映射本身而是成型滤波器的滚降系数和匹配滤波器的群时延没对齐。这类“玄学”问题光看教科书上的公式根本救不了你必须有一份能跑通、能改参数、能对着波形一步步排查的 MATLAB 代码。这份 QPSK 调制和解调仿真代码干的就是这件事。它把 QPSK 从比特流到星座映射、根升余弦成型滤波、AWGN 信道、匹配滤波、抽样判决、误码率统计的完整链路串了起来而且注释给得足够细参数都是显式写出来的不是那种“一行黑箱函数调用完事”的代码。适合谁通信工程方向的学生做课程设计、刚转基带方向的工程师搭链路验证、以及需要快速验证某个滤波器参数对 BER 影响的人。你不需要从零推导公式但得知道每个模块在干什么否则改错一个参数星座图照样糊给你看。2. QPSK 链路拆解从比特到星座点每一步在算什么2.1 为什么 QPSK 要用两路正交载波QPSK 的本质是把二进制比特流每两个一组映射到四个相位状态上。这四个状态在复平面上就是四个星座点通常取 ((\pm1 \pm j)/\sqrt{2}) 这种归一化形式。之所以用 I/Q 两路正交载波是因为同一频带内正交分量互不干扰频谱效率直接翻倍——BPSK 一个符号带 1 bitQPSK 一个符号带 2 bit。代码里第一步就是串并转换。假设输入比特流是[1 0 1 1 0 0 ...]每两个比特分成一组10映射到某个星座点11映射到另一个。这里有个容易翻车的地方映射规则必须和接收端判决规则严格对应否则解调出来的比特全是反的。常见做法是用格雷码映射让相邻星座点只差一个比特这样即使判决到隔壁点也只错 1 bitBER 不会爆炸。% 串并转换与 QPSK 星座映射格雷码 dataBits randi([0 1], 1, N_bits); % 生成随机比特流 I_bits dataBits(1:2:end); % 奇数位给 I 路 Q_bits dataBits(2:2:end); % 偶数位给 Q 路 % 格雷码映射00--1-1j, 01--11j, 11-11j, 10-1-1j symbols (1 - 2*I_bits) 1j*(1 - 2*Q_bits); symbols symbols / sqrt(2); % 归一化平均功率为 1这段代码里1 - 2*I_bits把 0/1 映射成 1/-1再组合成复数符号。归一化那一步很关键不归一化的话后面加噪声时信噪比定义会乱算出来的 BER 对不上理论值。参数N_bits控制仿真总比特数一般至少取 (10^5) 量级不然 BER 统计抖动大得没法看。2.2 成型滤波与匹配滤波一对必须配套的 FIR星座映射完符号还是冲激形式直接发出去频谱是无限宽的。所以发射端要过成型滤波器接收端要过匹配滤波器。理论上成型滤波器和匹配滤波器合起来构成一个根升余弦RRC滚降系统总响应是升余弦。代码里通常用rcosdesign生成 RRC 系数滚降系数beta一般取 0.35 或 0.5。这里有个血泪经验成型滤波器和匹配滤波器的系数必须完全一样而且群时延要对齐。很多人只在一端加了 RRC另一端直接抽样结果就是星座点拖尾严重、ISI 大到没法看。正确做法是两端各用一个 RRC卷积后自然形成升余弦。% 根升余弦滤波器设计 sps 8; % 每符号采样数至少 48 更稳 beta 0.35; % 滚降系数常用 0.35 或 0.5 span 6; % 滤波器跨度符号数影响截断精度 rrcFilter rcosdesign(beta, span, sps, sqrt); % 发射端成型滤波 txSignal upfirdn(symbols, rrcFilter, sps); % 接收端匹配滤波系数相同 rxFiltered upfirdn(rxSignal, rrcFilter, 1);sps是每符号采样数取 8 意味着一个符号周期内有 8 个采样点。span决定滤波器截断长度取 6 表示前后各拖 6 个符号。upfirdn先上采样再滤波一步到位。注意匹配滤波后信号长度会变长后面抽样判决时要算准最佳采样时刻通常取滤波器群时延补偿后的中点。2.3 AWGN 信道与信噪比定义加噪声这一步很多人直接用awgn函数但信噪比到底是符号信噪比 (E_s/N_0) 还是比特信噪比 (E_b/N_0)必须搞清楚。QPSK 一个符号带 2 bit所以 (E_s/N_0 E_b/N_0 3) dB。代码里如果按 (E_b/N_0) 扫描 BER 曲线加噪声时要换算。EbN0_dB 0:2:10; % 比特信噪比扫描范围 EbN0_lin 10.^(EbN0_dB/10); EsN0_lin EbN0_lin * 2; % QPSK: Es 2*Eb noiseVar 1 ./ (2 * EsN0_lin); % 复噪声方差 noise sqrt(noiseVar/2) * (randn(size(rxFiltered)) 1j*randn(size(rxFiltered))); rxNoisy rxFiltered noise;复高斯噪声的实部和虚部各占一半方差所以sqrt(noiseVar/2)这个系数不能漏。漏了的话 BER 曲线整体偏移 3 dB你会以为自己代码写错了其实是噪声功率算错了。3. 接收端解调抽样判决、星座图与误码率统计3.1 最佳抽样时刻怎么定匹配滤波后每个符号周期内有一个采样点信噪比最高就是最佳抽样时刻。由于 RRC 滤波器有群时延upfirdn输出后信号起点会偏移。常见做法是算出滤波器延迟(span*sps)/2然后从那个位置开始每隔sps个点抽一个。% 计算滤波延迟并抽样 filterDelay span * sps / 2; sampleIdx filterDelay 1 : sps : length(rxNoisy) - filterDelay; rxSymbols rxNoisy(sampleIdx); % 判决看实部和虚部符号 decI real(rxSymbols) 0; decQ imag(rxSymbols) 0; decBits zeros(1, 2*length(decI)); decBits(1:2:end) decI; decBits(2:2:end) decQ;抽样位置差一个点星座图就会从四个清晰点变成四团云。调试时先把rxSymbols画出来确认四个簇分得开再往下算 BER。3.2 星座图与 BER 曲线怎么画才说明问题星座图用scatterplot或直接plot(real, imag, .)。BER 曲线要和理论值对比QPSK 理论 BER 是 (Q(\sqrt{2E_b/N_0}))MATLAB 里用qfunc算。% 星座图 figure; plot(real(rxSymbols), imag(rxSymbols), .); axis equal; grid on; title(接收端星座图); % BER 统计 numErr sum(decBits ~ dataBits(1:length(decBits))); ber numErr / length(decBits); % 理论 BER berTheory qfunc(sqrt(2*EbN0_lin)); semilogy(EbN0_dB, ber, o-, EbN0_dB, berTheory, r--);仿真 BER 在低信噪比时应该贴着理论线高信噪比时如果仿真点数不够会掉不下去这是正常的统计波动不是代码错。3.3 参数扫描滚降系数和采样数对 BER 的影响把beta从 0.2 扫到 0.8你会发现 beta 越小频谱越紧凑但时域拖尾越长对定时误差越敏感。sps从 4 降到 2ISI 会明显恶化。这些扫描不用改主逻辑把参数提到循环外层就行。参数常用值影响beta0.35越小频谱效率越高但定时敏感sps8越大波形越平滑计算量越大span6越大截断误差越小滤波器越长N_bits1e5越大 BER 统计越稳4. 避坑与排查那些让星座图糊掉的常见问题4.1 星座图四个点糊成一团现象接收端星座图不是四个清晰簇而是四团云甚至一个圆。 原因最常见是匹配滤波器系数和成型滤波器不一致或者根本没加匹配滤波其次是抽样时刻没对准抽到了过渡带。 解决先确认两端rcosFilter是同一个变量再检查sampleIdx是否从filterDelay1开始。把rxFiltered直接画出来看眼图眼睛张开最大处就是最佳抽样点。4.2 BER 曲线整体偏移 3 dB现象仿真 BER 比理论值差 3 dB 左右形状是对的。 原因(E_b/N_0) 和 (E_s/N_0) 换算漏了 QPSK 的 2 bit/符号因子或者噪声方差算错。 解决检查EsN0_lin EbN0_lin * 2这行有没有以及noiseVar 1./(2*EsN0_lin)里的 2 有没有漏。复噪声实虚部各一半方差这个系数错一点曲线就偏。4.3 高信噪比时 BER 降不下去现象(E_b/N_0) 超过 8 dB 后 BER 卡在 (10^{-4}) 不动。 原因仿真比特数不够错误数太少统计不准或者滤波器截断太狠引入残余 ISI。 解决把N_bits加到 (10^6)span从 4 加到 6 或 8。如果还降不下去检查是不是没归一化符号功率。4.4 解调比特全是反的现象BER 恒等于 1 或 0.5星座图看着正常。 原因映射规则和判决规则不匹配比如发端用格雷码收端用自然码。 解决把发端symbols和收端decBits的映射表对一遍确保00--1-1j这类对应关系一致。4.5 滤波器设计报错或系数异常现象rcosdesign返回全零或报错。 原因sps和span必须满足sps*span为偶数否则rcosdesign会告警。 解决sps取 8、span取 6乘积 48 是偶数没问题。如果取span5、sps8乘积 40 也行但span取奇数时注意延迟计算。5. 进阶玩法把仿真改成可配置脚本与自动化验证把上面所有参数提到脚本开头做成一个config结构体换参数不用翻代码。我一般会这么干cfg.N_bits 1e5; cfg.sps 8; cfg.beta 0.35; cfg.span 6; cfg.EbN0_dB 0:2:10; % 主循环 for k 1:length(cfg.EbN0_dB) ber(k) run_qpsk_sim(cfg, cfg.EbN0_dB(k)); endrun_qpsk_sim封装完整链路输入配置和信噪比输出 BER。这样扫参数、画曲线、对比不同 beta 都是一行循环的事。验证方法上除了对比理论 BER还可以做两件事一是把发端符号和收端判决前的符号对比确认只有噪声引起的偏差二是把成型滤波器和匹配滤波器卷积后的总响应画出来确认是升余弦而不是别的形状。总响应不对后面全白搭。验证项合格标准检查方式总响应升余弦过零点等间隔卷积后画冲激响应星座图四个簇清晰可分scatter 或 plotBER低 SNR 贴理论线semilogy 对比频谱带外衰减符合 betapwelch 看功率谱从那以后我每次搭 QPSK 链路都强制先跑一遍无噪声回环确认星座图四个点干干净净再加噪声扫 BER。这个习惯帮我省了无数个对着糊图发呆的下午。希望帮到你。本文还有配套的精品资源点击获取
返回列表