公司动态
MATLAB实现64QAM软解调链路仿真:从原理到误码率分析
简介本资源是一套面向通信工程专业本科生及MATLAB初学者的64QAM软解调链路仿真教学包聚焦数字调制系统误码率性能分析这一核心实验任务。资源包含5个文件2个主程序脚本.m、2个运行日志.log、1个操作指引.txt总大小仅5KB轻量易用其中main1.m与main2.m实现64QAM调制、AWGN信道建模、软判决解调及BER计算全流程全部代码配有详尽中文注释逻辑清晰、模块分明配套操作视频已通过txt文件提供观看地址可直观掌握MATLAB当前路径设置、脚本运行与结果可视化关键步骤。已有193人学习下载特别适合课程设计、通信原理实验复现或毕业设计前期验证使用开箱即用无需额外依赖库有效降低软解调算法理解与仿真实践门槛。1. 项目概述从理论到实践的64QAM链路仿真如果你正在学习数字通信或者工作中需要评估一个通信系统的性能那么“误码率仿真”这个词你一定不陌生。它就像是通信工程师的“试金石”在真正把硬件做出来之前先用软件跑一遍看看这个设计在理论上能有多“抗造”。今天要聊的就是一个非常经典且实用的仿真案例64QAM调制结合软解调的完整通信链路误码率仿真。我会用MATLAB作为工具带你从零开始手把手搭建这条链路并解释清楚每一个模块背后的“为什么”。64QAM全称64进制正交幅度调制是当前4G/5G乃至Wi-Fi等高速通信系统的核心技术之一。简单来说它就像在一个坐标平面上精心布置了64个不同的点我们称之为“星座点”每个点代表一个6比特的二进制组合。通过改变发射信号的幅度和相位让它落到对应的星座点上从而在一个符号周期内传输6个比特效率远高于传统的BPSK1比特/符号或QPSK2比特/符号。但高收益伴随着高风险64个点挨得很近对噪声和干扰极其敏感这就对解调技术提出了更高要求。“软解调”正是应对这一挑战的利器。传统的“硬判决”解调接收端看到信号后会直接“猜”它离哪个星座点最近然后输出对应的比特0或1。这个过程是“非黑即白”的丢失了“这个猜测有多可靠”这一宝贵信息。而软解调不同它不急于做决定而是为每一个比特计算一个“似然比”或“软信息”这个值反映了该比特是0还是1的“置信度”。这个软信息可以交给后续的信道译码器如Viterbi或LDPC译码器进行更智能的纠错从而大幅提升系统在恶劣信道下的性能。可以说没有软解调高阶QAM的实用价值将大打折扣。这个仿真项目的核心价值就在于将“64QAM调制”和“软解调”这两个关键环节串联起来构建一个包含完整发端、信道、收端的基带仿真模型。通过它你可以直观地看到信号是如何从比特流变成复杂的调制信号经过噪声“污染”后又如何被接收机尽力恢复出来并最终以“误码率”这个硬指标来量化系统性能。无论你是通信专业的学生想深化理解还是工程师需要验证算法或教学这个仿真都能提供一个清晰、可操作、可修改的模板。接下来我们就深入链路内部看看每一个模块究竟是如何工作的。2. 64QAM调制原理与MATLAB实现细节要仿真首先得把信号正确地产生出来。64QAM调制器是发射机的核心它的任务是把一串二进制比特流映射到我们前面提到的那个有64个点的星座图上。2.1 星座图映射比特到符号的“翻译官”64QAM的星座图通常采用矩形网格状分布这也是最常用、能量分布最均匀的一种。具体来说在复平面的实部I路和虚部Q路方向上各取8个等间隔的电平值。例如我们可以将电平归一化到[-7, -5, -3, -1, 1, 3, 5, 7]这8个值上这样任意一个星座点都可以表示为a b*j其中a和b都来自这个集合。那么如何将6个比特(b5b4b3b2b1b0)映射到一个具体的(I, Q)坐标呢这里采用格雷码映射是关键。格雷码的特点是相邻星座点所对应的二进制组合之间只有1个比特不同。这样做的好处是当噪声导致接收信号错判到相邻星座点时只会产生1个比特的错误而不是多个这能显著降低误比特率。一种常见的映射规则是将6个比特分成高3位(b5b4b3)和低3位(b2b1b0)分别用于决定I路和Q路的电平。3个比特有8种状态正好对应8个电平。通过一个查找表将3位格雷码映射到前述的8个电平值上。在MATLAB中我们无需手动计算每个映射可以利用qammod函数。但为了透彻理解我们可以先自己实现一遍% 参数定义 M 64; % 调制阶数 k log2(M); % 每符号比特数 6 % 生成随机比特流 numBits 10000; dataIn randi([0 1], numBits, 1); % 将比特流分组每6比特一组 dataInMatrix reshape(dataIn, k, length(dataIn)/k).; % 将二进制转换为十进制范围0-63 dataSymbolsIn bi2de(dataInMatrix, left-msb); % 定义归一化的64QAM星座矩形格雷码映射 % 使用comm.RectangularQAMModulator对象或自定义映射 % 方法1使用通信工具箱函数最简单 if exist(qammod, file) % 注意默认的qammod可能使用非格雷码建议指定gray映射 modSignal qammod(dataSymbolsIn, M, gray, InputType, integer, UnitAveragePower, true); else % 方法2自定义格雷码映射教学目的 % 1. 生成格雷码序列 graySeq 0:M-1; graySeq bitxor(graySeq, floor(graySeq/2)); % 十进制转格雷码 % 2. 定义归一化星座点坐标平均功率为1 constellation qammod(0:M-1, M, UnitAveragePower, true); % 先用默认方式生成坐标 % 3. 根据格雷码序列重新排序星座点 [~, idx] sort(graySeq); constellation constellation(idx); % 4. 映射输入的十进制符号索引0-63对应到constellation中的值 modSignal constellation(dataSymbolsIn 1); % 1因为MATLAB索引从1开始 end注意UnitAveragePower参数设置为true至关重要。这会将星座点的平均功率归一化为1瓦特。这样我们在后面添加噪声时信噪比Eb/N0或Es/N0的定义才是清晰且一致的。如果忘记归一化计算出的噪声功率将是错误的导致仿真结果完全不可信。2.2 脉冲成形与过采样让信号适应连续时间信道直接生成的调制符号modSignal是一个一个的离散点。但在实际信道中传输的是连续时间波形。脉冲成形滤波器的作用就是把这些离散的符号点“连接”成平滑的波形同时将信号的频谱限制在一定的带宽内避免干扰相邻信道。最常用的脉冲是平方根升余弦滚降滤波器。这里有个关键概念过采样。我们的符号速率假设是1 Baud每秒1个符号。为了用离散序列较好地表示连续波形我们需要用更高的采样率比如每个符号采样spsSamples Per Symbol次。sps通常为4或8。% 脉冲成形参数 sps 8; % 每个符号的采样点数 span 10; % 滤波器的符号长度通常两边各span/2个符号 rolloff 0.25; % 滚降因子典型值0.2~0.5 % 设计平方根升余弦滤波器 rrcFilter rcosdesign(rolloff, span, sps, sqrt); % 对调制信号进行上采样和滤波 % 上采样在每个符号之间插入 sps-1 个零 upSampledSignal upsample(modSignal, sps); % 滤波 txSignal filter(rrcFilter, 1, upSampledSignal); % 注意滤波会引入群延迟长度为 (length(rrcFilter)-1)/2 个采样点。 % 在接收端进行匹配滤波后需要去除这个延迟才能正确对齐符号进行判决。 filterDelay (length(rrcFilter) - 1) / 2;经过脉冲成形后txSignal就是一个准备好了的基带发射信号可以送入信道模型了。这里生成的信号是复信号包含了同相I和正交Q两路。3. 信道模型模拟现实世界的噪声与衰落一个理想的仿真环境没有意义我们需要引入信道损伤来检验系统的鲁棒性。最基本的也是最重要的损伤就是加性高斯白噪声。3.1 加性高斯白噪声的精确添加AWGN信道是几乎所有通信系统性能分析的起点。添加噪声的关键在于根据设定的信噪比Eb/N0精确计算噪声功率。首先明确几个功率关系Eb每比特能量。Es每符号能量。对于64QAMEs Eb * log2(64) Eb * 6。信号平均功率我们已经通过UnitAveragePower将调制符号的平均功率归一化为1。但经过脉冲成形滤波器后信号功率可能会发生变化。实际上一个设计良好的RRC滤波器是能量保持的输入输出功率基本不变。但为了绝对精确我们可以在滤波后重新测量信号功率。噪声功率谱密度N0N0 2 * sigma^2其中sigma^2是复噪声每个维度I或Q的方差。添加噪声的步骤如下% 设定仿真信噪比范围以dB为单位 EbN0_dB 0:2:16; % 例如从0dB到16dB步进2dB numSNR length(EbN0_dB); % 初始化误码率结果存储 ber_soft zeros(1, numSNR); ber_hard zeros(1, numSNR); % 用于和硬判决对比 for snrIdx 1:numSNR current_EbN0_dB EbN0_dB(snrIdx); % 1. 将dB值转换为线性值 current_EbN0 10^(current_EbN0_dB / 10); % 2. 计算每符号信噪比 Es/N0 EsN0 current_EbN0 * k; % k log2(64) 6 % 3. 计算信号功率测量滤波后信号的平均功率更准确 signalPower mean(abs(txSignal).^2); % 4. 计算所需的噪声功率谱密度 N0 % 根据 Es/N0 signalPower / (N0 * 采样率因子?) 需要小心。 % 在离散时间仿真中我们处理的是采样后的信号。 % 更通用的方法是根据 Es/N0 计算每个采样点的噪声方差。 % 对于复基带信号噪声方差 sigma^2 N0 / (2 * 过采样率?) 这里容易混淆。 % 推荐的标准方法 % 我们的符号能量 Es signalPower * 符号周期Ts。 % 在离散仿真中采样间隔为 Ts/sps。信号序列的功率是 signalPower。 % 那么一个符号周期内的信号能量对应于 sps 个采样点。 % 因此平均到每个采样点上的信号“能量”是 signalPower * (Ts/sps) * sps? 这很乱。 % 最清晰、不易错的方法从比特级别推导。 % 已知Eb/N0 (线性值) % 总比特数 numBits % 信号总能量 信号功率 * 信号持续时间。 % 信号持续时间 符号数 * 符号周期 (numBits/k) * Ts。 % 在采样点层面信号总能量 sum(|txSignal|.^2) * (Ts/sps)。 % 令采样间隔 T Ts/sps则总能量 sum(|txSignal|.^2) * T。 % 而总比特能量 Eb * numBits。 % 所以 sum(|txSignal|.^2) * T Eb * numBits。 % 又因为 Eb/N0 已知所以 N0 Eb / (Eb/N0)。 % 那么噪声功率谱密度 N0 已知。 % 对于离散复高斯噪声每个维度的方差 sigma^2 N0 / (2 * T) % 实际上对于采样率为 fs 1/T 的系统离散噪声序列的方差 sigma_n^2 N0 * fs / 2 N0 / (2T)。 % 为了避免混乱通信工具箱提供了最直接的函数awgn。 % 但为了理解原理我们手动计算一次 % 方法A使用 awgn 函数确保信号功率已测量 rxSignal awgn(txSignal, current_EbN0_dB 10*log10(k) - 10*log10(sps), measured); % 解释awgn函数的第二个参数是信噪比SNR(dB)。 % 我们需要的是 Es/N0 (dB)。因为信号是过采样的其采样点功率不等于符号功率。 % measured 模式会根据输入信号 txSignal 的功率计算信号功率然后添加相应功率的噪声。 % 所以我们需要告诉它目标 Es/N0。 % Es/N0 (dB) Eb/N0 (dB) 10*log10(k) % 但 awgn 默认认为输入参数是信号采样点的 SNR (dB)。 % 对于过采样信号采样点 SNR 与 Es/N0 的关系是采样点 SNR (dB) Es/N0 (dB) - 10*log10(sps) % 因此awgn 的目标 SNR (dB) Eb/N0_dB 10*log10(k) - 10*log10(sps) % 方法B手动添加噪声加深理解 % 测量信号功率 sigPower mean(abs(txSignal).^2); % 计算每个采样点的信噪比 SNR_linear (线性值) % 目标 Es/N0 (Eb/N0)*k EsN0_linear current_EbN0 * k; % 采样点 SNR 信号功率 / 噪声功率 (Es/Ts) / (N0 * fs) ? 需要统一。 % 更简单噪声功率 信号功率 / (采样点 SNR) % 而 采样点 SNR (线性值) EsN0_linear / sps % 因为 Es 是符号能量分散在 sps 个采样点上每个采样点能量为 Es/sps。 % 噪声功率谱密度为 N0带宽内的噪声功率为 N0 * (1/Ts)不对。 % 对于采样率 fs sps/Ts噪声带宽为 fs/2 基带信号是复的正频率部分带宽为 1/(2Ts) 太复杂。 % 结论对于复基带仿真最稳妥且通用的公式是 % 噪声方差 sigma^2 (信号功率) / (Es/N0_linear) * (1/sps) % 但根据能量守恒符号能量 Es 信号功率 * Ts。 % 采样点功率 Ps 信号功率。 % 采样点噪声方差 N0 / (2 * T_sample) N0 * fs / 2。 % 而 N0 Es / EsN0_linear。 % 所以 sigma^2 (Es / EsN0_linear) * (sps/Ts) / 2 (Ps * Ts / EsN0_linear) * (sps/Ts) / 2 Ps / (2 * EsN0_linear / sps) % 令 SNR_sample_linear EsN0_linear / sps % 则 sigma^2 Ps / (2 * SNR_sample_linear) SNR_sample_linear EsN0_linear / sps; noiseVar sigPower / (2 * SNR_sample_linear); % 复噪声每个维度的方差 noise sqrt(noiseVar/2) * (randn(size(txSignal)) 1i*randn(size(txSignal))); % 生成复高斯噪声 rxSignal_manual txSignal noise; % 通常使用方法Aawgn函数更简单且不易出错。这里为了演示我们使用 rxSignal_manual 继续。 rxSignal rxSignal_manual; end这段代码包含了信道添加噪声的核心。其中最关键的是信噪比换算这是通信仿真中最容易出错的地方之一。务必理解Eb/N0、Es/N0以及过采样系统采样点信噪比之间的关系。3.2 可选的信道损伤扩展除了AWGN一个更完整的仿真可能还需要考虑多径衰落、相位噪声、频偏等。例如添加一个简单的多径信道% 定义一个两径瑞利衰落信道 channel [0.8, 0, 0, 0, 0.3]; % 主径增益0.8延迟4个采样点的多径增益0.3 rxSignalMultipath filter(channel, 1, txSignal); % 注意这会引入码间串扰 % 然后再添加噪声 rxSignal awgn(rxSignalMultipath, ...);在初步的误码率仿真中通常从最简单的AWGN信道开始因为它给出了系统性能的理论下界在无码间串扰、无衰落的情况下。有了这个基准再引入其他损伤就能看出系统性能的下降程度。4. 接收机处理匹配滤波与定时同步信号经过信道带着噪声到达接收机。接收机的首要任务是从连续的、被污染的信号波形中最佳地恢复出发送的符号序列。这第一步就是匹配滤波和符号定时同步。4.1 匹配滤波最大化信噪比匹配滤波器的冲激响应是发射脉冲成形滤波器的共轭反转。对于实系数的平方根升余弦滤波器匹配滤波器就是它本身。匹配滤波有两个作用1. 使采样时刻的信噪比最大化2. 与发射滤波器共同构成一个升余弦滚降滤波器从而满足奈奎斯特第一准则在理想同步下消除码间串扰。% 接收端匹配滤波 rxFiltered filter(rrcFilter, 1, rxSignal); % 匹配滤波同样会引入延迟 % 总延迟是发射滤波和接收滤波延迟之和 totalDelay 2 * filterDelay; % 因为发射和接收用了同一个滤波器rrcFilter4.2 符号定时同步找到最佳采样点经过匹配滤波后我们得到了一个波形需要在每个符号周期的特定时刻通常是最佳采样点即波形眼图张开最大的时刻进行采样才能得到用于判决的符号值。在仿真中我们通常知道精确的符号定时因为是我们自己生成的所以可以理想采样。但在实际中或更高级的仿真里需要定时同步算法。% 理想定时同步已知延迟和过采样率 % 1. 去除滤波器引入的延迟 rxFilteredAlign rxFiltered(totalDelay1 : end); % 确保长度是sps的整数倍方便下采样 effectiveLen floor(length(rxFilteredAlign) / sps) * sps; rxFilteredAlign rxFilteredAlign(1:effectiveLen); % 2. 下采样在每个符号周期的中心点采样假设理想同步 % 我们通常选择在滤波后波形的稳定区中心采样。对于RRC最佳采样点就是符号间隔的中心。 % 由于我们上采样时在符号前补零滤波后波形峰值会出现在符号周期中间。 % 因此下采样索引可以从 (sps/2 1) 开始每隔 sps 个点取一个。 startIdx ceil(sps/2); % 例如 sps8, startIdx4 sampledSignal rxFilteredAlign(startIdx : sps : end);现在sampledSignal的长度应该等于发送的符号数(numBits/k)。这些点就是受到噪声干扰后散布在64QAM星座图各个理想点周围的接收符号。接下来就要对这些点进行解调恢复出比特信息。5. 软解调算法详解与MATLAB实现这是本仿真的核心与难点。硬判决解调很简单计算接收符号到64个理想星座点的欧氏距离选择距离最小的点然后根据映射规则反解出6个比特。但软解调需要为每一个比特输出一个软信息通常是该比特为0的对数似然比。5.1 对数似然比计算原理对于加性高斯白噪声信道接收符号y在发送符号为x条件下的概率密度函数是复高斯分布。比特b_i的对数似然比定义为LLR(b_i) log( P(b_i0 | y) / P(b_i1 | y) )根据贝叶斯公式和等概发送的假设可以推导出近似公式LLR(b_i) ≈ (1/(2*sigma^2)) * [ min_{x in S_i^1} |y - x|^2 - min_{x in S_i^0} |y - x|^2 ]其中S_i^0表示所有使第i个比特为0的星座点集合S_i^1表示所有使第i个比特为1的星座点集合。sigma^2是噪声方差每个维度。这个公式的直观意义是对于第i个比特分别找到离接收点y最近的、该比特为0的星座点和最近的、该比特为1的星座点。计算y到这两个点的距离平方。如果离“0点”更近差值为负LLR为负值倾向于判0反之LLR为正值倾向于判1。LLR的绝对值大小反映了判决的置信度。5.2 高效LLR计算的MATLAB实现直接按照定义计算需要遍历集合对64QAM来说每个比特需要对64个点计算距离并比较计算量较大。对于矩形格雷码映射的QAM可以利用其星座图的对称性推导出基于接收信号I、Q分量的近似LLR计算公式这能极大简化运算。这里我们展示通用但稍慢的“最小距离”法以及更高效的分段线性近似法。方法一最小距离法通用易于理解function llr qam64_soft_demod_min_distance(y, M, sigma2) % y: 接收符号复数标量或向量 % M: 调制阶数 64 % sigma2: 噪声方差每个维度的即上面的 sigma^2 k log2(M); % 生成所有理想星座点格雷码映射归一化平均功率为1 constellation qammod(0:M-1, M, gray, UnitAveragePower, true); % 为每个比特预分配LLR llr zeros(length(y), k); % 对于每个接收符号 for idx 1:length(y) y_scalar y(idx); % 计算到所有星座点的距离平方 dist2 abs(y_scalar - constellation).^2; % 1x64向量 % 对于每个比特位 for bitIdx 0:k-1 % 找出该比特为0和1的星座点索引 % 需要知道格雷码映射下每个星座点对应的比特图案 % 我们可以反解对于 constellation 中的第m个点其对应的比特图案是 % 因为 constellation 是按格雷码顺序排列的所以第m个点对应的整数符号就是 m-1 (0-63) % 将 m-1 转换为 k 位二进制格雷码顺序需要先将整数转为格雷码再转二进制 % 实际上我们生成 constellation 时用了 gray 选项那么 qammod 的输入整数 0:63 就对应格雷码索引。 % 所以符号索引 symIdx 0:63 直接对应格雷码。 % 我们需要知道对于给定的 symIdx它的第 bitIdx 位是0还是1。 % 生成所有符号的比特矩阵 allSymbols (0:M-1).; % 格雷码转二进制因为我们的符号索引是格雷码 % 格雷码转二进制二进制最高位等于格雷码最高位此后每一位等于格雷码当前位与前一位二进制异或 graySeq allSymbols; binSeq zeros(size(graySeq)); for i 1:k binSeq(:, i) bitget(graySeq, k-i1); % 先获取格雷码的各个位 end % 格雷码转二进制算法 bin zeros(size(graySeq)); bin(:,1) binSeq(:,1); % 最高位相同 for i 2:k bin(:,i) xor(binSeq(:,i), bin(:,i-1)); end % 现在 bin 是一个 M x k 的矩阵bin(m, bitIdx1) 就是符号索引 m-1 的第 bitIdx 个比特值最高位在前取决于bitget顺序 % 注意bitget 默认是低位在前LSB而我们在映射时可能约定高位在前。这里需要与调制映射保持一致。 % 为了避免混乱一个更清晰但计算量大的方法是直接遍历 % 初始化最小距离 min_dist_0 inf; min_dist_1 inf; for m 1:M sym constellation(m); dist abs(y_scalar - sym)^2; % 判断这个星座点对应的第 bitIdx 个比特是0还是1 % 我们需要一个函数给定星座点索引 m-1返回其比特图案按照调制时的映射规则 bits get_bits_from_symbol_index(m-1, k); % 假设有这个函数 if bits(bitIdx1) 0 if dist min_dist_0 min_dist_0 dist; end else if dist min_dist_1 min_dist_1 dist; end end end % 计算LLR llr(idx, bitIdx1) (min_dist_1 - min_dist_0) / (2*sigma2); end end end % 辅助函数根据符号索引和格雷码映射规则返回比特数组 function bits get_bits_from_symbol_index(symIdx, k) % symIdx: 0~63 % 假设调制时使用了标准的格雷码映射矩形星座。 % 对于矩形格雷码映射I路和Q路独立进行格雷码映射。 % 将 symIdx 分解为 I路索引 (0-7) 和 Q路索引 (0-7) i_index floor(symIdx / 8); % 0~7 q_index mod(symIdx, 8); % 0~7 % 将十进制索引转换为3位格雷码二进制 % 注意这里的映射需要与调制器完全一致。我们假设使用自然二进制转格雷码。 i_gray bitxor(i_index, floor(i_index/2)); q_gray bitxor(q_index, floor(q_index/2)); % 将两个3位格雷码合并成6位比特高3位是I路低3位是Q路或反之需与调制器对应 bits [de2bi(i_gray, 3, left-msb), de2bi(q_gray, 3, left-msb)]; end这个方法逻辑清晰但计算复杂度是O(符号数 * 64 * 6)当仿真大量符号时非常慢。方法二分段线性近似法高效适用于矩形格雷码QAM对于矩形格雷码映射的QAMLLR可以近似为接收信号I、Q分量经过一个非线性函数的结果。这个函数通常可以用分段线性函数或查表来近似速度极快。MATLAB的通信工具箱函数qamdemod在指定OutputType为llr或approxllr时就采用了这种近似算法。% 使用通信工具箱进行软解调推荐 % 首先需要知道噪声方差 sigma2 % sigma2 的计算方法见前面信道部分 noiseVar ...; % 计算得到的噪声方差每个维度 % 计算LLR llr qamdemod(sampledSignal, M, gray, OutputType, approxllr, ... UnitAveragePower, true, NoiseVariance, noiseVar); % 或者使用 llr后者是更精确但计算量稍大的方法。 % approxllr 使用近似公式速度更快在中等及以上信噪比下精度足够。实操心得在实际仿真中强烈建议使用qamdemod函数进行软解调。它不仅速度快而且经过充分优化和测试结果可靠。自己编写最小距离法代码主要用于教学和理解原理。在使用qamdemod时务必确保UnitAveragePower和NoiseVariance参数与调制端和信道模型完全匹配这是结果正确的关键。5.3 硬判决解调对比为了凸显软解调的优势我们同时实现硬判决作为对比% 硬判决解调 hardDecisionSymbols qamdemod(sampledSignal, M, gray, OutputType, integer, UnitAveragePower, true); % 将符号解映射为比特流 dataOutHard de2bi(hardDecisionSymbols, k, left-msb).; dataOutHard dataOutHard(:); % 转换为列向量 % 软解调输出已经是LLR可以用于后续信道译码。 % 如果直接对比误码率我们需要将LLR转换为硬比特判决LLR0判为0LLR0判为1。 dataOutSoftBits llr 0; % 注意LLR的定义 log(P(0)/P(1))0 倾向于00 倾向于1。 dataOutSoftBits dataOutSoftBits(:);6. 误码率计算与仿真结果分析有了发射比特流dataIn和接收端恢复的比特流dataOutHard、dataOutSoftBits就可以计算误码率了。误码率是错误比特数与总比特数之比。6.1 计算与绘图我们需要对每一个仿真信噪比EbN0_dB点进行多次蒙特卡洛仿真或者发送足够多的比特使得误码率统计结果可靠例如错误比特数至少几十个。% 续接前面的主循环 for snrIdx 1:numSNR % ... [前面的调制、信道、接收、解调代码] ... % 解调完成后计算误码率 % 确保比较的比特流长度一致去除可能因延迟处理导致的头尾不对齐 minLen min(length(dataIn), length(dataOutHard)); [~, ber_hard(snrIdx)] biterr(dataIn(1:minLen), dataOutHard(1:minLen)); minLenSoft min(length(dataIn), length(dataOutSoftBits)); [~, ber_soft(snrIdx)] biterr(dataIn(1:minLenSoft), dataOutSoftBits(1:minLenSoft)); % 如果需要还可以计算符号错误率 % ... end % 绘制误码率曲线 figure; semilogy(EbN0_dB, ber_hard, b-o, LineWidth, 1.5, DisplayName, 硬判决); hold on; semilogy(EbN0_dB, ber_soft, r-s, LineWidth, 1.5, DisplayName, 软判决直接判决LLR); grid on; xlabel(Eb/N0 (dB)); ylabel(误比特率 (BER)); title(64QAM在AWGN信道下的误码率性能); legend(Location, best);6.2 结果分析与理论对比运行完整的仿真后你会得到两条曲线。软判决的性能应该明显优于硬判决尤其是在中高信噪比区域。为了验证仿真代码的正确性一个重要的步骤是与理论值进行对比。对于AWGN信道下的矩形64QAM其理论误符号率有闭式表达式而误比特率在格雷码映射下可以近似为BER ≈ (1/k) * SER。我们可以将理论曲线画在同一张图上。% 计算64QAM的理论误符号率AWGN相干解调 % 参考公式SER 2*(1-1/sqrt(M))*Qfunc( sqrt(3*k*EbN0_lin/(M-1)) ) * ... % (1 - (1-1/sqrt(M))*Qfunc( sqrt(3*k*EbN0_lin/(M-1)) ) ); % 更常用的近似公式 M 64; k log2(M); EbN0_lin 10.^(EbN0_dB/10); % 平均符号能量 Es k * Eb % 对于单位平均功率的星座最近邻距离 d_min sqrt(2/(M-1)*3) 需要查标准公式。 % 使用通信工具箱函数 ser_theory berawgn(EbN0_dB, qam, M); % 注意berawgn返回的是理论误比特率近似值 % berawgn 给出的就是格雷码映射下的理论BER近似。 % 因此我们可以直接对比。 % 绘制理论曲线 semilogy(EbN0_dB, ser_theory, k--, LineWidth, 1.5, DisplayName, 理论 (格雷码映射));如果仿真曲线特别是硬判决曲线与理论曲线在高信噪比时基本重合说明你的仿真链路搭建正确信道噪声添加、功率归一化等环节没有错误。软判决曲线应该位于理论曲线下方展现出编码增益尽管这里我们没有加信道编码但软信息本身提供了“内在”的增益。6.3 常见问题与调试技巧曲线不重合或形状怪异首先检查功率归一化。确保调制时UnitAveragePower设置为true。检查awgn函数中信噪比参数的换算是否正确。最可靠的调试方法是在极高信噪比如30dB下仿真此时误码率应趋近于0。如果还有错误说明是系统性的映射错误或同步问题。软解调性能反而比硬判决差检查LLR的符号定义。qamdemod输出的LLR正负值分别对应比特0和1的置信度。在直接判决时llr 0判为1这个规则是否与你的比特映射一致可以用一个简单例子验证发送全零序列在极高信噪比下接收到的LLR应该全部是很大的正数判决结果应为全0。仿真速度太慢如果自己实现了最小距离软解调速度会非常慢。对于大规模仿真务必使用内置的qamdemod函数或提前计算好查找表。另外蒙特卡洛仿真中低误码率点需要仿真大量比特非常耗时。可以采用“错误计数达到一定数目就停止”的策略来加速。星座图可视化在调试阶段绘制发射和接收的星座图非常有帮助。figure; subplot(1,2,1); plot(real(modSignal), imag(modSignal), b.); title(发射星座图); axis square; grid on; subplot(1,2,2); plot(real(sampledSignal), imag(sampledSignal), r.); title(接收星座图加噪声后); axis square; grid on;通过观察接收星座图可以直观感受噪声大小以及是否存在明显的相位旋转或幅度失真如果信道模型包含了这些效应。通过这个完整的64QAM软解调链路仿真你不仅得到了误码率曲线这个最终结果更重要的是你走通了从比特到波形再到噪声信道最后恢复出软硬判决信息的全流程。这个模型是一个强大的基础你可以在此基础上轻松地修改参数如滚降因子、过采样率、替换信道模型如瑞利衰落、或者接入真正的信道译码器如Viterbi译码器来评估级联系统的性能。把程序模块化写好注释它就是你通信算法工具箱里一件非常趁手的兵器。本文还有配套的精品资源点击获取