
简介SCMA-ML-master 是一份面向无线通信与机器学习交叉方向研究者的开源代码资源聚焦 SCMA稀疏码多址系统的算法实现与性能优化。SCMA 作为码域非正交多用户接入技术可提升频谱效率与抗干扰能力而该资源尝试引入机器学习方法辅助信号检测、编解码与参数调优适合具备通信原理与 Python 编程基础的学习者研读。压缩包共 9 个文件以 m 文件为主辅以 license、s 与 md 文档整体约 6KB体量轻巧但结构完整涵盖码本设计、SCMA 编解码、ML 检测及四进制与二进制转换等核心模块README 与许可证文件便于快速了解项目背景与使用约束。目前已有 227 人学习下载读者可借此理解 SCMA 与机器学习结合的基本流程包括数据预处理、模型训练、误码率等指标评估并参考其目录组织方式搭建自己的仿真实验框架对通信工程与机器学习方向的研究具有较高参考价值。1. SCMA-ML-master 到底在做什么从稀疏码多址到机器学习接收机如果你手里只有一份名为SCMA-ML-master的代码包打开后看到morehsq、SCMA、ML这些目录名第一反应大概率是这是一个把机器学习塞进稀疏码多址Sparse Code Multiple Access, SCMA系统里的仿真工程。SCMA 本身是 5G 非正交多址接入NOMA家族里被讨论最多的一种方案核心思路是让多个用户在相同的时频资源上叠加发送靠码本的稀疏性在接收端做多用户检测。而ML通常指 Maximum Likelihood 检测也可能是 Machine Learning 的缩写——在这个项目名里两者其实都说得通因为 SCMA 的接收机设计正好处在传统最大似然检测和深度学习检测的交汇点上。这个方向适合谁如果你在做通信物理层仿真、想复现 SCMA 的码本设计和消息传递算法MPA或者想对比 ML 检测和深度学习方法在 SCMA 上的误码率表现这份代码包就是一个能跑的起点。它解决的核心问题是在用户数超过资源数、码本又稀疏的情况下接收端怎么把叠加的信号拆开。传统 MPA 复杂度随用户数指数增长ML 检测虽然最优但穷举量太大而机器学习方法试图在两者之间找平衡。接下来我会按「先跑通、再调参、最后避坑」的顺序把这条路径拆开讲清楚。2. 把 SCMA-ML-master 在本地跑起来环境、入口与最小验证2.1 先看清目录结构再动手拿到一个通信仿真包最忌讳的就是直接python main.py。SCMA-ML-master 这类工程通常包含码本生成、信道建模、检测算法、误码率统计几个模块。我一般会先花五分钟把目录树扫一遍确认入口脚本、配置文件和数据输出路径。常见结构是SCMA/放码本和因子图ML/放检测器实现morehsq/可能是作者自己的实验脚本或参数扫描目录。如果目录名带master说明这是主分支快照不一定有完整的依赖声明文件。# 先看目录层级不要急着运行 find . -maxdepth 2 -type d | sort # 再看有没有 requirements.txt 或 environment.yml ls -la | grep -E requirements|environment|setup # 确认 Python 版本和关键依赖 python --version pip list | grep -E numpy|scipy|matplotlib|torch|tensorflow上面这段命令的逻辑是先摸清目录边界再确认依赖是否齐全。参数上-maxdepth 2避免输出太深grep -E用来快速过滤关键词。如果发现没有依赖文件就需要根据 import 语句反推。常见依赖是numpy做矩阵运算、scipy做特殊函数、matplotlib画 BER 曲线如果ML指深度学习还会出现torch或tensorflow。2.2 最小可运行入口与参数含义跑通的第一步不是复现论文而是让程序输出一个非零的 BER 结果。我通常会在入口脚本里找if __name__ __main__或者config字典把用户数、资源数、码本大小、信噪比范围这几个参数先固定成小值。# 典型的 SCMA 仿真参数配置片段 config { K: 4, # 资源元素数即 RE 数量 J: 6, # 用户数J K 体现过载 M: 4, # 每个用户的码本码字数量 N: 2, # 每个码字占用的非零资源数稀疏度 N/K snr_db: list(range(0, 16, 2)), # 信噪比扫描范围 channel: rayleigh, # 信道类型 detector: ml # 检测器选择ml / mpa / dnn }这段配置里K4, J6表示过载率 150%这是 SCMA 的典型场景。N2决定码本稀疏度N 越小检测越容易但性能会降。snr_db从 0 到 14 步进 2是为了画 BER 曲线。detector字段是切换算法的关键如果代码里同时实现了 ML 和 MPA改这个值就能对比。运行后先看输出目录有没有ber.npy或ber.csv如果有说明主流程通了。2.3 验证码本和因子图是否对得上SCMA 的码本不是随便生成的它和因子图矩阵一一对应。因子图矩阵F是 K 行 J 列F(k,j)1表示第 j 个用户在第 k 个资源上发送非零符号。如果代码包里码本维度和因子图不匹配后面检测全是错的。import numpy as np # 假设从文件加载因子图矩阵 F np.load(SCMA/factor_graph.npy) print(因子图维度:, F.shape) # 应为 (K, J) print(每列非零数:, np.sum(F, axis0)) # 应等于 N print(每行非零数:, np.sum(F, axis1)) # 通常大于 1 # 检查码本维度每个用户一个码本形状 (M, N) codebook np.load(SCMA/codebook.npy) print(码本维度:, codebook.shape) # 应为 (J, M, N)这里的关键是确认F的每列非零数等于N每行非零数大于 1。如果对不上要么是加载错了文件要么是码本生成脚本没跑完。我见过有人直接拿论文里的因子图矩阵硬编码结果和代码里的码本维度差一位BER 曲线直接变成一条水平线这就是典型的“翻车”现场。3. ML 检测在 SCMA 里怎么落地从穷举到可跑通的实现3.1 最大似然检测的数学形式与复杂度边界SCMA 的接收信号可以写成y Hx n其中x是所有用户码字的叠加。ML 检测就是在所有可能的用户码字组合里找一组使||y - Hx||^2最小。对于J个用户、每个用户M个码字穷举量是M^J。当J6, M4时4^64096种组合还能接受但如果J12, M4就是 1600 万种单机跑一次 BER 点要很久。所以 ML 检测在 SCMA 里的定位是“小规模最优基准”用来验证 MPA 或神经网络检测器是否接近最优。def ml_detect(y, H, codebooks): y: 接收信号形状 (K,) H: 信道矩阵形状 (K, J) codebooks: 所有用户码本形状 (J, M, N) 返回: 最优用户码字组合索引 J, M, N codebooks.shape K y.shape[0] best_idx None min_dist np.inf # 穷举所有组合 for combo in np.ndindex(*([M] * J)): x np.zeros(K, dtypecomplex) for j in range(J): # 把第 j 个用户的第 combo[j] 个码字映射到非零资源上 x map_to_resources(codebooks[j, combo[j]], j) dist np.linalg.norm(y - H x) ** 2 if dist min_dist: min_dist dist best_idx combo return best_idx这段代码的逻辑很直白用np.ndindex生成所有码字组合逐个计算欧氏距离。参数上codebooks的维度必须是(J, M, N)map_to_resources负责把N维码字放到K维资源上。实际跑的时候如果J超过 8建议先加剪枝或者改用 MPA否则一个 SNR 点就能跑十几分钟。3.2 用向量化把 ML 检测速度提上来纯 Python 循环穷举在J6时还能忍但做参数扫描就太慢。我一般会用 NumPy 做向量化把所有候选组合预先展开成矩阵一次性算距离。def ml_detect_vectorized(y, H, codebooks): J, M, N codebooks.shape K y.shape[0] # 生成所有组合的索引形状 (M^J, J) combos np.array(np.unravel_index( np.arange(M**J), [M]*J)).T # 构造所有候选叠加信号形状 (M^J, K) X_candidates np.zeros((M**J, K), dtypecomplex) for j in range(J): for n_idx in range(N): # 找到第 j 个用户第 n_idx 个非零资源的位置 res_idx np.where(factor_graph[:, j] 1)[0][n_idx] X_candidates[:, res_idx] codebooks[j, combos[:, j], n_idx] # 向量化计算距离 diff y[None, :] - X_candidates H.T dists np.sum(np.abs(diff)**2, axis1) return combos[np.argmin(dists)]向量化之后M^J个候选一次性算完速度能快一个数量级。注意factor_graph的列索引要和码本的非零位置对应否则叠加信号会错位。这个函数在J6, M4时大概几毫秒出结果适合做 BER 扫描。3.3 和 MPA 检测的对比什么时候该用 MLML 检测是性能上界但复杂度也最高。实际做对比实验时我一般会固定K4, J6, M4分别跑 ML、MPA 和 DNN 三种检测器看 BER 曲线在哪个 SNR 点分叉。MPA 的迭代次数通常设 5 到 10 次次数越多越接近 ML但时延也越大。如果代码包里morehsq目录有现成的对比脚本直接改detector字段就行如果没有就自己写一个循环把三种检测器的 BER 存到同一个.npz里再用matplotlib画图。这一步的坑在于不同检测器的输出格式可能不一样有的返回比特有的返回符号索引对齐的时候要特别小心。4. 参数怎么调、结果怎么看SCMA-ML 仿真的调参与验证4.1 过载率和稀疏度的取舍SCMA 的核心卖点是过载J/K越大接入用户越多但检测难度也越大。常见配置是K4, J6过载 150%或K4, J8过载 200%。N一般取 2因为N1就退化成正交多址N3又太稠密MPA 的因子图会变复杂。调参的时候我习惯先固定N2然后逐步增加J看 BER 在什么用户数下开始急剧恶化。这个拐点就是这套码本和检测器的实际容量边界。参数典型值影响K4资源数越小过载越高J6用户数越大检测越难M4码本大小越大频谱效率越高N2稀疏度越小检测越简单迭代次数5~10MPA 专用越大越接近 ML4.2 BER 曲线的正确读法BER 曲线不是越陡越好要看在目标误码率比如1e-3下的 SNR 门限。ML 检测的曲线通常最靠左MPA 会右移 1 到 2 dBDNN 检测器如果训练充分可以逼近 ML。但如果 DNN 曲线在低 SNR 反而比 MPA 差说明训练集覆盖不够或者网络过拟合。我一般会跑snr_db 0:2:14每个点至少1e5个比特否则高 SNR 段的 BER 抖动很大看起来像“玄学”。# 简单的 BER 统计循环 ber [] for snr in config[snr_db]: errors 0 total 0 for _ in range(1000): # 每个 SNR 跑 1000 帧 y, bits_true simulate_frame(snr, config) bits_est detector(y, config) errors np.sum(bits_true ! bits_est) total len(bits_true) ber.append(errors / total)这段代码里simulate_frame负责生成信道和叠加信号detector是前面实现的 ML 或 MPA。1000帧是经验值如果 BER 低于1e-4需要加到1e5帧才能看到稳定结果。4.3 用星座图辅助排查映射错误如果 BER 曲线明显偏离预期比如 ML 检测和 MPA 几乎重合那大概率是码本映射或者信道模型出了问题。我一般会画接收信号的星座图看叠加后的符号是否落在预期的码字组合上。如果星座点散乱说明H矩阵或者码本归一化有问题。这一步不需要改代码用matplotlib的scatter就能看出来。5. 避坑与排查SCMA-ML 仿真里最容易翻车的 4 个点5.1 现象BER 曲线是一条水平线原因检测器输出和真实比特没有对齐或者码本维度加载错误。常见于codebook.npy的(J, M, N)被误读成(M, J, N)。解决打印codebook.shape和factor_graph.shape确认J和K的对应关系。再用一个已知码字手动叠加看ml_detect能否返回正确索引。5.2 现象ML 检测跑得极慢一个 SNR 点要半小时原因用了纯 Python 循环穷举没有向量化或者J设得太大。解决换成ml_detect_vectorized或者先把J降到 4 验证流程。如果必须跑J8以上考虑用 MPA 做基准ML 只跑一个 SNR 点做上界参考。5.3 现象DNN 检测器训练 loss 不下降原因输入特征没有归一化或者训练集和测试集的信道模型不一致。解决把接收信号y按功率归一化标签用 one-hot 码字索引。检查morehsq目录里的数据生成脚本确保训练和测试用的是同一套H分布。5.4 现象MPA 迭代次数增加但 BER 不变原因因子图存在环消息传递不收敛或者阻尼因子设得不对。解决检查因子图矩阵是否有短环适当增加阻尼因子比如 0.5 到 0.7。如果还是不降说明码本设计本身有问题换一组论文里的标准码本再试。6. 进阶技巧把 SCMA-ML 的检测器换成可训练模块如果你已经跑通了 ML 和 MPA下一步大概率是想试试深度学习检测器。我的习惯是不动原有仿真框架只在检测器接口上做替换。具体做法是把ml_detect的输入输出固定成(y, H) - 码字索引然后写一个 PyTorch 模块用全连接网络或者 CNN 拟合这个映射。训练数据就用仿真循环生成标签是真实码字组合。关键技巧是网络最后一层用softmax输出M^J维概率但M^J可能很大所以实际会用因子图结构做分组检测把M^J拆成J个M分类问题。验证的时候先看训练集准确率能不能到 95% 以上再看 BER 曲线是否逼近 ML。如果 DNN 在低 SNR 比 MPA 还差别急着调网络先检查训练集里低 SNR 样本是不是太少。这个方向我踩过最大的坑是仿真生成的H矩阵在训练和测试时用了不同的随机种子导致网络学到的映射完全对不上BER 直接爆表。后来养成习惯所有随机种子固定数据生成和检测器评估分开跑才稳定下来。希望帮到你。本文还有配套的精品资源点击获取