☰
SCMA MATLAB仿真全攻略:码本构造、MPA检测与BER实现
2026/10/26 23:18:10 网站建设 项目流程

简介:稀疏码分多址(SCMA)是一种面向第五代移动通信的非正交多址技术,而这份MATLAB仿真程序包恰好围绕该技术展开,适合通信方向的学生、研究者,以及想快速验证多址算法的工程师。资源提供了从稀疏码字编码、星座映射到多用户叠加传输、迭代译码的完整仿真链路,代码组织结构清楚,便于直接运行和二次修改。压缩包共包含11个文件,核心为9个MATLAB脚本,覆盖主仿真、编码以及MPA、SD-MPA、PM-MPA等不同译码算法实现,另有说明文档辅助阅读,整体仅约10KB,非常轻量。目前已有274人学习使用,说明其入门门槛较低、参考价值明确。借助这套代码,可以快速跑通误码率评估流程;仿真主程序与各译码算法模块划分明确,便于按需修改参数,也能为课程设计、论文复现或后续算法优化提供可扩展的基线版本。

1. 从 scma-simulation.rar 到能出图:SCMA 的 MATLAB 仿真到底在做什么

从网上下到一份以scma-simulation命名的 MATLAB 仿真包,解压后面对一堆*.m文件和几个码本矩阵,却不知道从哪条脚本跑起——这是很多刚接触非正交多址接入的研究生遇到的第一道坎。SCMA(稀疏码多址接入)是 5G 候选多址方案里被讨论最多的一种,它把多个用户的数据通过各自的稀疏码本叠加在同样几个资源块上,接收端再用消息传递算法(MPA)把它们分离。这套 MATLAB 程序的核心产出是误码率(BER)曲线:给定码本、信道和信噪比,衡量检测器的差错性能。这篇笔记把 SCMA 仿真拆成码本构造、MPA 实现、主循环参数三条线来讲,新手能照着把曲线跑出来,熟手能直接对参数和坑下手。

2. 发射端仿真的三块地基:码本、因子图与叠加发送

2.1 码本这个黑匣子:SCMA 为什么敢让多用户信号叠在一起

SCMA 与传统 TDMA/FDMA 的区别在于,多个用户同时占用同一段时频资源。它靠的是一件事:每个用户有一个专属码本。码本是一个 K 行 M 列的复数矩阵,K 是资源块数量,M 是码字数量(也就是每个符号能携带的比特数)。每一列是一个码字,一个 K 维复向量,代表这个比特组映射到 K 个资源上的幅度和相位。

码本的关键特征是稀疏:每个码字里只有 dv 个非零元素,其余位置是 0。这意味着每个用户只“占用”K 个资源里的 dv 个,而同一个资源上会有 df 个用户同时叠加。典型配置是 J=6 个用户、K=4 个资源、M=4 个码字、dv=2、df=3。每个用户每符号携带 log2(4)=2 比特,6 个用户用 4 个资源,频谱效率是 6×2/4=3 bit/s/Hz,这是正交方案做不到的。

参数含义常见取值影响
K资源块数4码本维度,越大频谱效率越高但检测越复杂
M码字数(星座点数)4log2(M) 决定每用户每符号比特数
J用户数6叠加用户数,决定负载率 J/K
dv每用户占用资源数2码本稀疏度,影响 MPA 复杂度和性能
df每资源叠加用户数3df 决定 MPA 的组合复杂度,约 M^df

初学者最容易忽略的是:码本决定了 SCMA 的性能上限。检测器再好,码本设计得一塌糊涂,BER 曲线照样难看。后面第 6 章专门讲怎么用距离指标快速筛码本。

2.2 因子图:把“谁占用了哪个资源”写成一张矩阵

SCMA 的用户-资源关系不用文字描述,直接用因子图矩阵 F。F 是 K 行 J 列的 0/1 矩阵,F(k,j)=1 表示用户 j 在资源 k 上有非零码字。标准 6 用户 4 资源配置的因子图长这样:

% 行:资源 1~4;列:用户 1~6 F = [1 1 1 0 0 0; 1 0 0 1 1 0; 0 1 0 1 0 1; 0 0 1 0 1 1];

这个矩阵每列正好 2 个 1(dv=2),每行正好 3 个 1(df=3)。接收端做 MPA 时,资源节点只需要看每一行里哪些用户占了资源,变量节点只需要看每一列里哪些资源被该用户使用。这个矩阵是后续所有循环的索引基础,也是码本构造时确定非零行位置的依据。工程上建议把 F 定义成全局变量或作为结构体字段,别在多个函数里手写硬编码,否则改配置时容易漏改。

2.3 发射端最小实现:从比特到叠加信号的 MATLAB 代码

构造码本的最简可靠方案是“母星座 + 旋转”:先选一个 QPSK 星座作为基底,再给每个用户在每个非零资源上配不同的旋转角。性能普通,但能把流程跑通,后续可以换更好的码本。

% SCMA发射端最小实现:参数、码本、叠加 K = 4; M = 4; J = 6; dv = 2; F = [1 1 1 0 0 0; 1 0 0 1 1 0; 0 1 0 1 0 1; 0 0 1 0 1 1]; % 母星座:QPSK,平均能量归一化为1 qpsk = [1+1j; 1-1j; -1+1j; -1-1j] / sqrt(2); % 每用户在每个非零资源上的旋转角,共 J*dv 个 rot = [0, pi/2; 0, pi/3; pi/4, pi/6; pi/6, pi/4; pi/3, 0; pi/2, 0]; % 逐用户构造码本:非零位置由因子图决定 cbs = cell(1, J); for j = 1:J cb = zeros(K, M); % 先全填0,保证稀疏 res = find(F(:, j)).'; % 该用户占用的资源编号 for d = 1:dv cb(res(d), :) = qpsk * exp(1j * rot(j, d)); end % 码字能量归一化:每个码字平均能量 = 1 Eavg = mean(sum(abs(cb).^2, 1)); cbs{j} = cb / sqrt(Eavg); end % 随机生成一帧:每用户 600 个符号,每符号2比特 frameLen = 600; bits = randi([0 1], J, frameLen * 2); sym = zeros(J, frameLen); for j = 1:J sym(j, :) = bi2de(reshape(bits(j, :), 2, []).') + 1; end % 叠加发送:第t个符号时刻,6个用户的码字求和 X = zeros(K, frameLen, J); for j = 1:J X(:, :, j) = cbs{j}(:, sym(j, :)); end s = sum(X, 3); % K x frameLen 叠加信号 % AWGN信道:实部虚部各加一半噪声功率 N0 = 0.1; n = sqrt(N0/2) * (randn(K, frameLen) + 1j * randn(K, frameLen)); y = s + n;

这段代码的逻辑:先由因子图确定每个用户在哪些资源上有值,把旋转后的 QPSK 星座填进码本的对应行,其余行保持 0。归一化这步很重要,很多仿真包坑就在这里——码本不归一化,不同用户的发射功率就不同,BER 曲线会带着错误前提。sym是每用户每个符号的码字索引,取值 1 到 4,发送端直接用它索引码本矩阵的列。最后叠加求和得到s,加噪声时注意复噪声的方差要拆成实部虚部各N0/2,只乘一个sqrt(N0)会让噪声功率翻倍。

3. MPA 检测器:接收端仿真的核心循环与参数调优

3.1 消息传递到底在传什么:变量节点和资源节点的“对话”

MPA 的工作方式是在因子图上迭代交换消息。对每个用户 j,它和相邻的资源节点之间来回传递“我认为我的码字是 m”的置信度。消息分两类:变量节点到资源节点(Mv2f(j,k,m),用户 j 告诉资源 k 自己有多大概率取码字 m),以及资源节点到变量节点(Mf2v(k,j,m),资源 k 根据叠加信号和所有相邻用户的消息,反馈给用户 j 一个概率)。

每一轮迭代分两步。资源节点更新:资源 k 上叠加了 df 个用户,对目标用户 j 的每个可能码字 m,遍历其他用户的所有码字组合,计算组合信号与真实接收信号的欧氏距离,距离越小、其他用户当前消息越大,则这条组合对目标消息的贡献越大。变量节点更新:用户 j 把自己收到的来自不同资源节点的消息相乘,再做归一化,得到新一轮传给资源节点的消息。

这个过程本质上是在把“多用户联合检测”拆成若干个局部的小型枚举,复杂度是每资源M^df,也就是 4^3=64 个组合枚举。这是 SCMA 接收机复杂度远低于最大似然检测的根本原因。

3.2 一份能直接放进主循环的概率域 MPA 函数

下面是一个完整的概率域 MPA 实现,输入接收向量、信道、码本和因子图,输出每个用户两比特的 LLR。为了可读性,组合枚举写成了显式循环,跑通后再优化。

function LLR = mpa_prob(y, Hh, cbs, F, M, N0, iters) % y : K x 1 接收信号 % Hh : K x J 信道矩阵,AWGN时全1,瑞利时给随机信道 % cbs : 1 x J cell,cbs{j}是K x M码本 % F : K x J 因子图 % M : 码字数(星座点数) % N0 : 噪声单边功率谱密度 % iters : 迭代次数 K = size(F,1); J = size(F,2); % 消息初始化:概率域消息全1,表示无先验 Mv2f = ones(J, K, M); % 用户j -> 资源k,关于码字m Mf2v = ones(K, J, M); % 资源k -> 用户j,关于码字m % 预生成每个资源的码字组合索引表:M^df x df combos_cell = cell(1, K); for k = 1:K df = sum(F(k,:)); grids = cell(1, df); [grids{:}] = ndgrid(1:M); combos = zeros(M^df, df); for d = 1:df combos(:, d) = reshape(grids{d}, [], 1); end combos_cell{k} = combos; end for it = 1:iters % ---- 资源节点更新 ---- for k = 1:K users = find(F(k,:)); % 占用资源k的用户 df = length(users); combos = combos_cell{k}; % 取出这些用户码本在资源k上的行,组成 df x M 矩阵 cbk = cellfun(@(cb) cb(k,:), cbs(users), 'UniformOutput', false); Xbk = reshape([cbk{:}], M, df).'; for jj = 1:df % 遍历资源k上的每个用户 uj = users(jj); for m = 1:M acc = 0; for c = 1:size(combos,1) if combos(c, jj) ~= m, continue; end % 目标用户码字必须=m u_idx = combos(c, :); % 本组合下各用户码字索引 % 其他用户消息乘积 lik = 1; for uu = 1:df lik = lik * Mv2f(users(uu), k, u_idx(uu)); end % 本组合对应的无噪接收值 r_k = 0; for uu = 1:df r_k = r_k + Hh(k, users(uu)) * Xbk(uu, u_idx(uu)); end acc = acc + lik * exp(-abs(y(k) - r_k).^2 / N0); end Mf2v(k, uj, m) = acc; end end end % ---- 变量节点更新 ---- for j = 1:J res = find(F(:, j)).'; % 用户j占用的资源 for k = res for m = 1:M p = 1; for kk = res if kk == k, continue; end % 排除自身 p = p * Mf2v(kk, j, m); end Mv2f(j, k, m) = p; end % 归一化,防止概率累计值过大 s = sum(Mv2f(j, k, :)); Mv2f(j, k, :) = Mv2f(j, k, :) / (s + eps); end end end % ---- 最终判决:计算每个用户两比特的LLR ---- LLR = zeros(J, log2(M)); for j = 1:J post = ones(1, M); for k = find(F(:, j)).' post = post .* squeeze(Mf2v(k, j, :)).'; end % 码字索引1~4对应比特组 [0 0] [0 1] [1 0] [1 1] % 这里按bi2de低位在前的顺序 LLR(j, 1) = log(sum(post([3 4])) + eps) - log(sum(post([1 2])) + eps); LLR(j, 2) = log(sum(post([2 4])) + eps) - log(sum(post([1 3])) + eps); end end

这段代码有四个要点。第一,combos_cell必须提前生成并缓存,如果在每次迭代里重复构建组合索引表,仿真速度会慢很多倍。第二,资源节点更新的核心是exp(-abs(y(k)-r_k)^2/N0),这里的N0必须和发射端加噪声用的一致,否则整个 MPA 的置信度都错位。第三,变量节点归一化用eps兜底,避免除零。第四,LLR 的比特顺序由发射端bi2de决定,如果 BER 统计对不上,把两个 LLR 的顺序交换即可,这是最常见的低级错误。

3.3 三个必调参数:迭代次数、噪声方差、组合枚举顺序

迭代次数是最直观的参数。SCMA 的因子图没有环,消息在 5 到 8 次迭代后基本收敛。设 3 次以下性能差得明显,设 15 次以上纯属浪费时间。我一般默认 6 次,先跑通再根据 BER 曲线是否还有上升空间决定要不要加到 8。

噪声方差N0的换算有个高频翻车点。发射端做了码字能量归一化后,每个码字平均能量 Es=1,每个用户每符号携带 bits_per_sym=log2(M) 个比特。画 BER 曲线用 EbN0 口径时:

N0 = Es / bits_per_sym * 10^(-EbN0dB / 10);

也就是N0 = 0.5 * 10^(-EbN0dB/10)。如果你在仿真包里看到别人直接用N0 = 10^(-EbN0dB/10),那他的曲线横坐标其实是 EsN0,两张图的横轴相差 3dB。搞清楚自己用的是哪种口径,否则拿你的曲线跟论文对比时,永远差出 3 个 dB。

第三个参数是组合枚举顺序。资源节点更新里M^df个组合,对每个目标用户 m 都要遍历一遍。典型实现是用continue跳过不满足的组合,这在df=3时问题不大,但如果你想扩展到大码本或更高负载,要改成“按目标用户的 m 预先分组索引”,也就是提前算好combos_by_m{jj}{m},直接取子集,能省掉一大半无效循环。

4. 跑通完整仿真:BER 主循环、码本导入与信道配置

4.1 主循环骨架:从 EbN0 扫描到 BER 统计

把发射、MPA、误码统计串起来的 BER 仿真主循环大致如下。这个骨架遵循一个原则:外圈扫信噪比,内圈多帧取平均,帧内逐符号做 MPA。

% SCMA BER仿真主循环骨架 EbN0dB = 0:2:12; % 横轴:每比特信噪比 nFrame = 200; % 每个SNR点的帧数 frameLen = 600; % 每帧每用户符号数 maxIter = 6; % MPA迭代次数 Es = 1; bitsPerSym = 2; ber = zeros(size(EbN0dB)); % 码本与因子图先准备好,见第2章代码 % cbs为1xJ cell,F为KxJ矩阵 for ei = 1:length(EbN0dB) N0 = Es / bitsPerSym * 10^(-EbN0dB(ei) / 10); errCnt = 0; bitCnt = 0; for f = 1:nFrame % 随机比特与符号映射 bits = randi([0 1], J, frameLen * bitsPerSym); sym = zeros(J, frameLen); for j = 1:J sym(j, :) = bi2de(reshape(bits(j, :), bitsPerSym, []).') + 1; end % 码本映射与叠加发送 X = zeros(K, frameLen, J); for j = 1:J X(:, :, j) = cbs{j}(:, sym(j, :)); end s = sum(X, 3); % AWGN信道(瑞利信道改这里,见4.3) Hh = ones(K, J); n = sqrt(N0/2) * (randn(K, frameLen) + 1j * randn(K, frameLen)); y = s + n; % 逐符号MPA检测 for t = 1:frameLen LLR = mpa_prob(y(:, t), Hh, cbs, F, size(cbs{1},2), N0, maxIter); dec = double(LLR < 0); % 负数判为1 % 与原始比特比对,注意列顺序 for j = 1:J b0 = bits(j, 2*(t-1)+1); b1 = bits(j, 2*(t-1)+2); errCnt = errCnt + (b0 ~= dec(j,1)) + (b1 ~= dec(j,2)); bitCnt = bitCnt + 2; end end end ber(ei) = errCnt / bitCnt; fprintf('EbN0=%.1fdB, BER=%.3e\n', EbN0dB(ei), ber(ei)); end % 画图 semilogy(EbN0dB, ber, 'o-'); grid on; xlabel('EbN0 (dB)'); ylabel('BER');

主循环的编排逻辑是:将 SNR 扫描和帧统计分开,每一帧重新生成比特和信道,这是为了让误码统计覆盖足够多的随机事件。bits是 J 行、每行frameLen*2列,sym(j,:)把一个符号的两个比特转成 1~4 的码字索引,发送端按索引取码本列。接收端逐符号调用 MPA,得到 LLR 后做硬判决。BER 统计必须把比特列和符号对齐,这是新手最容易写错的地方:dec是当前符号的 2 比特,对应bits的第2*(t-1)+1和第2*(t-1)+2列。

这个骨架跑 200 帧、每帧 600 符号、6 次迭代,在普通笔记本上大概需要十几分钟。如果你想快速验证正确性,先把nFrame降到 20,frameLen降到 100,BER 曲线会毛糙一点,但能立刻看出趋势。

4.2 码本导入与随机种子:两个影响可复现性的小细节

很多下载到的仿真包把码本放在独立的.mat文件里,命名类似codebook.mat。导入时务必做三件事:检查维度、检查非零位置、检查归一化。

% 码本导入与健壮性检查 S = load('codebook.mat', 'cbs'); cbs = S.cbs; % 维度检查:每个码本必须是 K x M assert(isequal(size(cbs{1}), [K, M]), '码本维度不是KxM'); % 非零位置检查:必须与因子图一致 for j = 1:J nz_rows = find(any(cbs{j} ~= 0, 2)).'; assert(isequal(nz_rows, find(F(:, j)).'), '码本非零行与因子图不一致'); end % 归一化检查:码字平均能量应为1 for j = 1:J Eavg = mean(sum(abs(cbs{j}).^2, 1)); if abs(Eavg - 1) > 1e-6 cbs{j} = cbs{j} / sqrt(Eavg); % 强行拉回,避免功率偏置 end end

这三个检查能挡掉大部分坏码本。因子图与码本非零位置不一致时,MPA 里find(F(k,:))取出的用户和实际码本结构对不上,检测结果会全面崩溃且报错不明显——只有 BER 曲线异常差,很难排查。随机种子方面,主脚本开头加一行rng(2024),保证每次跑出的 BER 曲线可复现。做调试时这行代码是你的后悔药:跑出奇怪结果后同一套随机数还能再跑一遍,定位问题方便得多。

4.3 从 AWGN 到瑞利信道:MPA 里信道矩阵的改动方式

AWGN 信道下Hh = ones(K,J)是因为信号没有经过衰落。瑞利信道下每个用户到接收端的信道系数不同,接收信号变为:

% 每帧重新生成瑞利信道:实部虚部各一半方差 Hh = (randn(K, J) + 1j * randn(K, J)) / sqrt(2); % 接收信号:每个用户的码字乘各自信道系数后叠加 y = zeros(K, frameLen); for t = 1:frameLen y(:, t) = sum(Hh .* X(:, t, :), 3) + n(:, t); end

mpa_prob函数里已经在计算r_k时乘了Hh(k, users(uu)),所以 AWGN 下传ones(K,J)、瑞利下传每帧生成的随机Hh即可,检测器主体不用改。需要留意两点:一是瑞利信道下每个用户的等效功率是随机的,BER 波动比 AWGN 大得多,需要更多帧数才能平滑;二是Hh每帧重新生成,不要放在 SNR 循环外面共用一组信道,否则那条 BER 曲线只是某个固定信道下的特例,不具备统计意义。

验证仿真结果靠三件事:低 SNR 段 BER 是否随 SNR 上升而明显下降,曲线是否单调光滑,以及对比同一码本在 AWGN 和瑞利下的性能差异是否在合理范围。

检查项方法期望结果
低 SNR 表现看 BER 是否接近 0.5 并随 SNR 下降SNR 升高 2dB,BER 应明显改善
曲线平滑度各点 BER 波动是否在半个数量级内帧数不足时波动大,需加帧
码本有效性对比 AWGN 与瑞利 BER瑞利比 AWGN 差几个 dB,差距过小或过大都要查

5. SCMA 仿真避坑:四个让 MATLAB 程序翻车的典型问题

5.1 现象:MPA 迭代中出现 NaN,BER 直接变成 0 或空

概率域 MPA 跑几步后,Mf2v或Mv2f里出现 NaN,判决结果全是 0,误码率统计出来反而变成“完美”。原因很直接:概率相乘连续发生,某一轮迭代后某条消息下溢为 0,下一轮 0 被乘进所有后续计算,0/0就产生 NaN。

解决方式按优先级来。第一选择是切到 Log-MPA,所有乘法变成加法,数值范围从 1e-300 量级抬升到几百量级。第二选择是给概率域消息加下界,归一化时用max(p, 1e-12)兜底。第三选择是在变量节点归一化后立即检查是否全零,全零则回退为均匀分布。实际工程里 Log-MPA 几乎是标配,概率域只用来教学演示。

5.2 现象:BER 曲线在高 SNR 段出现地板(error floor)

高信噪比下 BER 降不下去,维持在 1e-3 到 1e-4 左右。最先怀疑的是噪声方差换算错误:MPA 里的N0比真实值偏大,导致检测器在高 SNR 段仍然认为噪声很强,置信度不增长。检查方法很简单,在某个 SNR 点手动算一次N0,和发射端sqrt(N0/2)的赋值对一下。

如果N0没问题,第二个原因是码本能量归一化不一致。某些码本构造代码里,不同用户的码字平均能量差 2~3 倍,这等于给部分用户加了额外功率,而统计 BER 时又把所有用户混在一起平均。解决方式是统一每个码本的平均能量为 1,再重新跑一遍对比。

5.3 现象:跑出来的 BER 还不如 4G 的正交多址方案

这是新手最容易心理崩溃的一幕:SCMA 作为“先进方案”,曲线比 QPSK 正交接入还差一大截。多数时候不是检测器写错了,而是码本本身太差。随机生成的复矩阵放在稀疏位置里,星座点之间的最小欧氏距离小得可怜,高 SNR 下就是天花板。

解决方式分两步。先用第 6 章的距离指标筛码本,把明显不合格的码本挡在 BER 仿真之前;再用论文常用的“母星座 + 旋转 + 置换”构造法替换随机码本。经验上,母星座选 QPSK、每用户每资源配不同旋转角、旋转角经过优化,性能就能达到可接受的 baseline。不要一上来就追求复杂优化,先把距离指标跑起来。

5.4 现象:一个 SNR 点跑半小时,整条曲线要过夜

计算量集中在三处:帧内逐符号调用 MPA、MPA 内组合枚举、以及每次枚举里的内层循环。最有效的优化是按帧向量化 MPA——把y从 K×1 变成 K×L(L 为一帧符号数),消息矩阵变成 J×K×M×L,虽然内存占用变大,但 MATLAB 对这类多维数组的隐式扩展非常快,性能提升通常超过十倍。

第二个优化是预计算所有组合的欧氏距离系数。给定信道和码本,Hh(k, users(uu)) * Xbk(uu, u_idx(uu))在不同帧之间会变,但在同一帧内部可以复用。把组合表和码字局部值提前展开成矩阵,用矩阵乘法代替内层循环。第三个优化是把 MPA 函数改成mex,这个属于压箱底功夫,前期用不着。我一般先用nFrame=20调通逻辑,确认 BER 曲线形态正确后,再加大帧数跑正式曲线。

6. 码本优化第一课:用星座距离快速筛掉差码本

SCMA 的码本构造是个复杂命题,但对于绝大多数仿真验证工作,你不需要从头设计多维星座,只需要做一件事:用距离指标把“肉眼不可见但性能很差”的码本筛掉。SCMA 的误码率直接和叠加后星座点的最小欧氏距离相关,距离越小,在同样噪声下越容易判错。

我给一个实用做法:构造 20 组候选码本,每组用不同的旋转角组合,计算它们的两两叠加最小距离,选距离最大的一组进 BER 仿真。

% 码本粗筛:用用户间叠加最小距离打分,避免直接跑几小时BER function score = codebook_score(cbs, F, M) J = length(cbs); score = inf; for j1 = 1:J-1 for j2 = j1+1:J % 找两个用户共同占用的资源 same_res = find(F(:, j1) & F(:, j2)); if isempty(same_res), continue; end dmin2 = inf; for m1 = 1:M for m2 = 1:M for n1 = 1:M for n2 = 1:M % 用户j1自己从m1换到n1,用户j2从m2换到n2 diffv = cbs{j1}(same_res, m1) - cbs{j1}(same_res, n1) ... + cbs{j2}(same_res, m2) - cbs{j2}(same_res, n2); dmin2 = min(dmin2, sum(abs(diffv).^2)); end end end end score = min(score, dmin2); end end end

主脚本里生成候选旋转角,批量打分:

% 候选码本粗筛选:20组旋转角,各构造码本并打分 rng(7); best_score = 0; for trial = 1:20 rot_trial = 2 * pi * rand(J, dv); % 每用户每资源随机旋转 cbs_trial = build_codebook(F, rot_trial); % 内部做母星座填充+归一化 sc = codebook_score(cbs_trial, F, M); if sc > best_score best_score = sc; cbs = cbs_trial; end end fprintf('best score = %.4f\n', best_score); % 用筛选出的cbs进入第4章的BER主循环

这组代码用几百次简单矩阵计算代替几小时的 BER 仿真,是典型的“先距离筛选、后仿真验证”思路。注意它只是一个粗筛指标,最终以 BER 曲线为准,但能帮你筛掉 80% 的差码本。旋转角随机搜索的维数是 J×dv=12,20 次采样在这么小的维度空间里已经能覆盖到可用的区域。

筛完码本再回头看 BER,你会发现同样一套 MPA 代码,曲线可能好 2~3dB。SCMA 仿真的水有多深,很大程度在码本而不在检测器。我最初直接用randn生成复数矩阵当码本,BER 曲线比正交方案还难看,后来先把距离指标跑起来,才真正理解这个领域里“码本决定上限、MPA 逼近上限”这句话的分量。先筛码本、再调 MPA、最后加帧数拉平滑曲线,这套顺序能帮你少走一大半弯路,希望帮到你。

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

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

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

立即咨询