简介:这份源码资源面向通信工程、信号处理方向的学习者与工程师,聚焦数字通信中ASK、FSK、PSK、QAM四种基本调制解调技术的误码率仿真,帮助理解不同调制方式在不同信噪比下的性能差异。压缩包共2个文件,包含1个m脚本文件与1张jpg测试结果图,整体约82KB,脚本可直接运行复现仿真曲线,图片则直观展示误码率随信噪比变化的对比结果。内容覆盖二进制幅度键控的幅度映射、二进制频移键控的双频表示、BPSK与QPSK的相位映射,以及16-QAM、64-QAM等多阶正交幅度调制的编码方式,并围绕误码率这一核心指标展开分析。已有294人学习,适合用于课程实验、毕业设计或通信系统参数优化的入门实践,能帮助读者快速搭建仿真框架、验证解调准确性并评估调制阶数与码率对可靠性的影响。
1. 误码率曲线不是玄学:四种调制解调的仿真到底在算什么
很多人第一次跑 ASK、FSK、PSK、QAM 的误码率仿真,看到那条随信噪比下降的曲线,心里其实没底——它到底是算出来的,还是画出来的?更反直觉的是:同一套调制方式,换一个判决门限,曲线能平移好几个 dB,而代码里往往只改了一行。这说明误码率仿真的核心不是“跑通”,而是搞清楚每个比特在收发链路里经历了什么变换、噪声从哪个口子进来、判决器凭什么把接收样点映射回 0 或 1。这份源码把四种基本数字调制放在同一套框架下做蒙特卡洛仿真,价值就在于它把“调制—信道—解调—判决—计数”这条链路拆开摆在你面前。搞懂它,你再看任何通信系统的性能评估,都不会只盯着最后那张图,而是会去追问:星座点怎么摆、噪声怎么加、判决边界画在哪。
2. ASK 与 FSK:把比特映射成波形,再让判决器猜回来
2.1 ASK 的幅度映射与相干/非相干解调差异
ASK 最朴素的理解是“有载波代表 1,无载波代表 0”,也就是 OOK。但源码里通常不会只做 OOK,而是把 M 进制 ASK 的幅度电平摆开,比如 2ASK 用 0 和 A 两个电平,4ASK 用 0、A/3、2A/3、A 四个电平。发送端做的事就是查表:把比特流按每 log2(M) 位一组,映射到对应幅度,再乘上载波 cos(2πfct)。这里有个容易忽略的点——映射方式分自然码和格雷码,格雷码能让相邻电平只差一个比特,判决出错时只错一位,误比特率会比误符号率低不少。源码里如果用了格雷映射,BER 曲线在相同 SNR 下会比自然码好看,这不是算法变强了,而是错误比特的统计口径变了。
接收端分相干和非相干两条路。相干解调需要本地恢复一个同频同相的载波,把接收信号乘回去再积分,得到基带幅度样点,然后跟门限比。非相干解调则用包络检波,取信号包络后直接判决,省掉了载波恢复,代价是性能差 1~2 dB。源码里如果两种都实现了,你会看到两条曲线在低 SNR 区明显分开,高 SNR 区逐渐靠拢。这个差异的根源在于:包络检波丢掉了相位信息,而噪声在包络上的分布是瑞利型,不是高斯型,判决门限的推导方式完全不同。
% 2ASK 相干解调核心片段(示意) rx = awgn(tx, snr, 'measured'); % 加高斯白噪声 rx_mix = rx .* cos(2*pi*fc*t); % 乘本地载波 rx_base = lowpass(rx_mix, 2*Rb); % 低通滤波取基带 sample = rx_base(end); % 抽样判决点 bit_out = sample > threshold; % 门限判决这段代码里threshold的取值直接决定误码率。理论上最佳门限在两种幅度电平的中点,但实际仿真中如果低通滤波器阶数不够、抽样时刻偏了,门限就得微调。我一般会先扫一遍门限,确认曲线在理论值附近触底,再固定下来跑完整 SNR 范围,否则你看到的“性能下降”可能只是门限没对准。
2.2 FSK 的频率间隔与正交性条件
FSK 把信息放在频率上,2FSK 用 f1 和 f2 两个频率分别代表 1 和 0。源码里生成 FSK 信号通常有两种写法:一种是直接切换振荡器频率,另一种是用两个独立载波分别调制再相加。前者相位连续,后者在切换点可能跳变,频谱展宽不一样。仿真误码率时,相位是否连续对 BER 影响不大,但对频谱效率有影响,如果源码里做了功率谱分析,你能看到旁瓣差异。
FSK 能否被正确解调,关键在频率间隔 Δf 和码元速率 Rb 的关系。当 Δf = Rb/2 时,两个频率在一个码元周期内正交,非相干解调的误码率公式最干净。如果 Δf 太小,两个频率的频谱重叠,解调器分不清;如果 Δf 太大,占用带宽浪费。源码里如果用了匹配滤波器组或者 FFT 做非相干检测,本质上是在频域找峰值,峰值位置对应哪个频率就判成哪个比特。这里有个坑:FFT 点数不够时,频率分辨率不足,两个峰值会糊在一起,BER 曲线在低 SNR 下会异常抬高,看起来像“算法不行”,其实是分辨率不够。
% 2FSK 非相干解调:双支路带通滤波 + 包络比较 bp1 = bandpass(rx, [f1-BW/2, f1+BW/2], fs); bp2 = bandpass(rx, [f2-BW/2, f2+BW/2], fs); env1 = abs(hilbert(bp1)); env2 = abs(hilbert(bp2)); bit_out = env1 > env2; % 哪路包络大就判成哪个频率BW的选取要跟 Rb 匹配,通常取 1~2 倍 Rb。太窄了信号被滤掉,太宽了噪声进来多。这段代码跑出来的 BER 在 Δf = Rb/2 时应该接近理论非相干 FSK 曲线,如果偏离超过 1 dB,优先检查带通滤波器的过渡带和希尔伯特变换的边界效应。
3. PSK 与 QAM:相位和幅度一起用,判决边界变成几何问题
3.1 BPSK/QPSK 的星座图与相干解调门限
PSK 把信息放在相位上,BPSK 用 0 和 π 两个相位,QPSK 用 π/4、3π/4、5π/4、7π/4 四个相位。星座图上,BPSK 是两个点落在实轴两端,QPSK 是四个点落在圆上。相干解调时,接收样点投影到 I/Q 平面,判决就是看它离哪个星座点最近。BPSK 的判决边界是虚轴,QPSK 的判决边界是两条对角线。源码里如果直接比较 I 路和 Q 路的符号,那就是在隐式地画这两条边界。
QPSK 有个容易混淆的地方:它每个符号带 2 比特,误符号率和误比特率的关系取决于映射方式。格雷映射下,相邻星座点只差一个比特,所以 BER ≈ SER/2(高 SNR 时)。如果源码里用了二进制自然映射,BER 会更高。仿真时如果只统计误比特率,不关心里面的映射,你可能会觉得 QPSK 比 BPSK 差很多,其实按每比特能量归一化后,QPSK 和 BPSK 的 BER 曲线几乎重合——因为 QPSK 相当于两路正交的 BPSK。
% QPSK 相干解调:I/Q 两路分别判决 i_out = real(rx_base) > 0; q_out = imag(rx_base) > 0; bit_out = [i_out; q_out]; % 按映射表还原比特对这里rx_base是去掉载波后的复基带信号。如果载波恢复有相位偏差,星座图会旋转,判决边界跟着转,BER 会恶化。源码里如果没做载波同步,而是假设理想相位,那仿真结果就是理论下界,实际系统要再打折扣。我一般会在仿真里故意加一个固定相位偏移,看看曲线恶化多少,这样心里对同步误差的容忍度就有数了。
3.2 16QAM/64QAM 的幅度相位联合判决与信噪比敏感度
QAM 把幅度和相位一起用,16QAM 是 4×4 的方格,64QAM 是 8×8。星座点不再落在圆上,而是矩形网格。判决变成二维最近邻搜索:接收样点落在哪个格子里,就判成哪个符号。源码里如果用了矩形判决区域,实现很简单——I 路和 Q 路分别做多电平判决,然后查表。但要注意,矩形星座的相邻点距离不均匀,角落的点和中心的点抗噪能力不一样,平均 BER 是所有这些点错误概率的加权。
QAM 对 SNR 的要求比 PSK 高得多。同样传 4 比特,16QAM 的星座点间距比 QPSK 小,噪声稍微大一点就越界。源码跑出来的 BER 曲线在低 SNR 区会陡峭上升,这不是 bug,是 QAM 的固有特性。仿真时如果发现 16QAM 的曲线跟理论差距很大,先检查平均符号能量有没有归一化——很多源码忘了除以 sqrt(10) 之类的因子,导致实际发射功率偏大,曲线看起来“太好”。
% 16QAM 矩形判决:I/Q 各做 4 电平判决 levels = [-3 -1 1 3]; % 归一化后的电平 [~, i_idx] = min(abs(real(rx_base) - levels)); [~, q_idx] = min(abs(imag(rx_base) - levels)); sym_out = (i_idx-1)*4 + q_idx; % 映射回符号索引levels的间距是 2,对应星座点间距。如果发射端做了能量归一化,接收端判决前也要用同样的尺度。这段代码在 SNR 高于 15 dB 时应该跟理论曲线贴合,低于 10 dB 时因为噪声导致样点乱跑,BER 会接近 0.5 的随机猜测水平。
4. 误码率仿真避坑:那些让曲线“不对劲”的常见问题
4.1 现象:BER 曲线在高 SNR 处不降反平
原因通常是仿真比特数不够。蒙特卡洛仿真里,误码率是错误数除以总比特数。当理论 BER 到 1e-5 时,你至少需要 1e6 个比特才能看到几个错误,否则统计涨落会让曲线尾部翘起来。源码里如果固定了总比特数,高 SNR 段就是不可信的。
解决:按 SNR 动态调整仿真长度,或者设一个最小错误数(比如 100 个错误)作为停止条件。我一般会在高 SNR 段把比特数拉到 1e7,虽然跑得慢,但曲线尾部干净。
4.2 现象:ASK 和 FSK 的曲线跟理论差 3 dB
原因多半是噪声功率的定义方式。awgn函数里的 SNR 是按信号功率算的,但有些源码手动加噪声时用了randn乘一个方差,没跟信号功率对齐。ASK 信号有“关断”时段,平均功率和峰值功率差一倍,如果按峰值功率算 SNR,曲线就会平移。
解决:统一用awgn或者手动计算信号平均功率,确保 SNR 定义是每比特能量与噪声功率谱密度之比 Eb/N0,而不是符号信噪比。ASK 和 FSK 的 Eb/N0 跟 SNR 差一个带宽因子,换算错了就是几 dB 的偏差。
4.3 现象:QPSK 误比特率比 BPSK 高很多
原因通常是映射方式不是格雷码,或者 I/Q 两路比特没有并行统计。QPSK 一个符号错可能导致两个比特都错,如果映射表让相邻符号的比特差异大,BER 就高。
解决:检查星座映射表,确保相邻星座点只差一个比特。如果源码里用的是自然二进制映射,可以自己改成格雷映射再跑一遍,对比曲线差异。
4.4 现象:16QAM 在低 SNR 下 BER 超过 0.5
原因可能是判决区域没有覆盖整个平面,或者归一化因子错了导致接收样点整体偏移。BER 超过 0.5 意味着判决器在“故意”犯错,比随机猜还差。
解决:画一下接收样点的散点图,看星座点是否落在判决区域中心。如果整体偏移,检查发射端和接收端的归一化是否一致;如果散点扩散太大,检查噪声方差是否加错了。
4.5 现象:FSK 非相干解调曲线在某个 SNR 点突然跳变
原因通常是带通滤波器的带宽或阶数在某个 SNR 下导致包络检波失效,或者 FFT 分辨率不够导致频率峰值检测跳变。这种跳变不是理论上的,是实现细节引入的。
解决:固定滤波器参数,扫一遍 SNR,看跳变点是否随滤波器带宽移动。如果是,加宽带宽或提高 FFT 点数,直到曲线平滑。
5. 从仿真到直觉:怎么判断一条 BER 曲线“对不对劲”
仿真跑完,图一画,怎么知道它可不可信?我的习惯是拿理论曲线当尺子。BPSK 相干解调的 BER 理论值是 Q(sqrt(2Eb/N0)),QPSK 跟它重合,2FSK 非相干是 0.5*exp(-Eb/(2N0)),16QAM 在格雷映射下有近似公式。如果仿真曲线跟理论在 1 dB 以内,基本可信;差 2~3 dB,先查噪声定义和归一化;差 5 dB 以上,多半是判决器或同步环节有结构性问题。
另一个验证方法是看曲线斜率。高 SNR 区,BER 随 Eb/N0 的下降斜率反映了分集阶数。BPSK 和 QPSK 的斜率一样,16QAM 因为星座点密,斜率更陡但起点更高。如果仿真曲线斜率跟理论不符,说明错误事件的主导因素变了——可能是噪声模型不对,也可能是某个环节引入了非线性。
这份源码把四种调制放在一起,最大的好处是你能横向对比。同样传 2 比特,QPSK 和 4FSK 的 BER 曲线差多少?同样传 4 比特,16QAM 和 16PSK 谁更抗噪?这些对比在单一调制仿真里看不出来,放在一起就一目了然。我一般会先把每个调制单独跑通,确认跟理论对得上,再改参数做对比,这样每一步都有参照,不会越跑越糊涂。
从那以后我每次拿到一个新的通信仿真代码,都强制先跑一遍理论曲线做基准,再动任何参数。希望这份源码和上面的拆解,能帮你把误码率仿真从“跑出图就行”变成“知道每个 dB 从哪来”。
本文还有配套的精品资源,点击获取