ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于Matlab的扩频通信系统仿真:从m序列到码相位同步

基于Matlab的扩频通信系统仿真:从m序列到码相位同步 简介一份基于Matlab的扩频通信系统仿真源码包面向通信工程专业学生、科研人员及对直接序列扩频DSSS感兴趣的开发者用于理解扩频通信原理、验证同步性能并开展参数优化研究。包内共9个M文件涵盖扩频码生成、沃尔什码构造、发送接收模块、高斯白噪声模拟及信噪比计算等功能模块整体仅4KB结构紧凑、便于逐模块阅读和二次修改。已有2298人学习参考。通过运行这些脚本读者可直观查看信号扩频、传输、解扩及SNR评估的完整流程也能在此基础上调整扩频码长度、扩频比和信道条件深入分析不同因素对系统误码与同步性能的影响为课程设计或实际系统预研提供可复现的仿真基础。1. 基于 Matlab 的扩频通信系统仿真为什么同步比解扩更值得关注写这个源码包时我遇到的反直觉结论是基于 Matlab 的扩频通信系统仿真里真正决定误码率上限的不是扩频码本身而是接收端的码相位同步。只要本地伪码与发送端错开一个码片解扩结果直接变成噪声误码率掉到 0.5 附近。这套扩频通信系统仿真包正是围绕这个问题设计的提供 send_moudle.m、receive_module.m、SNR.m 等独立脚本覆盖直接序列扩频DSSS从伪码生成、扩频调制、信道加噪到同步解扩的完整链路同时把同步误差对相关峰和误码的影响变成可量化的曲线。对想理解 m 序列、沃尔什码、扩频增益如何落到代码里的人它是没有 Simulink 包装的裸版本每个环节都是一个函数能看清信号在每个阶段的形态。适合通信课程设计、DSSS 算法验证以及不想拖动模块、想直接用脚本控制每个采样点的工程师。2. 扩频链路框架与 m 序列发生器先让伪随机码可用2.1 直接序列扩频的信号模型与处理增益DSSS 的本质是信息序列与高速率伪随机序列相乘。设信息比特为 d(k) ∈ {1, -1}伪随机码片序列为 c(n) ∈ {1, -1}扩频后的基带信号为 x(n) d(k) * c(n)其中每个信息比特持续 L 个码片L 就是扩频因子。接收端解扩时再次乘以同步伪码 c(n)由于 c²(n)1信号被还原成 d(k)窄带干扰则被伪码的谱扩展特性摊平到整个带宽从而在解扩后被低通滤波器滤除。处理增益 G 10log10(L) dB 直接决定系统对干扰的抑制能力在后续的 SNR.m 和同步性能分析中会反复出现。实际仿真时如果 L31G 约为 14.9 dB意味着解扩前信噪比很低时解扩后信噪比依然可以支撑可靠判决。理解这一点才知道为什么扩频通信能工作在噪声电平以下也才知道 SNR.m 测出来的数值应该落在哪个区间。2.2 从源码包映射到链路各环节拿到这套源码我建议先按功能给文件归类而不是直接追 main.m 的执行顺序。一个比较实用的映射关系是下表m 文件链路角色关键输出m_sequence.m / m_seq.m伪码生成m 序列单极性或双极性walsh.m正交码生成沃尔什函数矩阵send_moudle.m发送端扩频后的基带信号yongwuAwumlvjisuan.m扩频运算信息与码片相乘后的序列gngauss.m信道噪声高斯白噪声样本receive_module.m接收端解扩结果与同步偏移SNR.m性能测量信噪比估计值main.m顶层调度误码率、同步性能曲线这里容易混淆的是 m_sequence.m 与 m_seq.m 的关系前者输出移位寄存器产生的 0/1 逻辑序列后者做极性映射把 0 变成 -1、1 变成 1。后续所有扩频相乘都要求双极性所以真正参与运算的是 m_seq.m 的输出。这样拆分调试也清晰想单测伪码性质时用 m_sequence想跑链路时用 m_seq。2.3 复现 m 序列生成逻辑m 序列是最大长度线性反馈移位寄存器序列周期是 2^n - 1。工程上最常用查本原多项式表确定抽头位置例如 n4 时抽头是 [4 3]n5 时是 [5 3]。复现包的 m_sequence.m 时我一般写成function seq m_sequence(n, taps) % n : 移位寄存器阶数 % taps : 反馈抽头下标从1开始 % seq : 0/1序列长度 2^n - 1 if nargin 2 switch n case 4 taps [4 3]; case 5 taps [5 3]; otherwise error(需要显式指定抽头位置); end end reg ones(1, n); seq zeros(1, 2^n - 1); for i 1:(2^n - 1) seq(i) reg(n); % 输出最高位 fb mod(sum(reg(taps)), 2); % 抽头异或等价于模2加法 reg [fb reg(1:end-1)]; % 右移并反馈 end end参数说明n决定伪码周期周期越长自相关性越好但接收端捕获时间随之变长。taps里的下标对应本原多项式中非零项的幂次选错会退化为短周期序列造成相关峰旁瓣升高。实现里mod(sum(...), 2)等价于对抽头位做异或是移位寄存器最直接的数学表达。拿到真实文件后可以用sum(m_sequence(5, [5 3]))验证序列中 1 的个数为 16与理论值 2^(n-1) 一致。3. 沃尔什码与扩频调制用正交性分离用户与信号3.1 沃尔什码的构造逻辑沃尔什码由 Hadamard 矩阵按行提取。2 阶 Hadamard 矩阵是 [[1 1]; [1 -1]]更高阶按 Kronecker 积递归扩展H(2m) [H(m) H(m); H(m) -H(m)]。walsh.m 在 Matlab 里最简单的实现是用hadamard(N)但更贴近链路建模习惯的是自己迭代矩阵便于控制码长和行索引。沃尔什码的核心价值是任意两行正交相关值为 0在多用户场景中不同用户的扩频码不互相干扰接收端解扩时能把目标用户信号完整恢复出来。代码可以这样复现function walsh_codes walsh(N) % N 必须是2的幂 w 1; while size(w, 1) N w [w w; w -w]; end walsh_codes w; end调用walsh_codes walsh(4)会得到四行码每行对应一个用户的扩频码。使用时要把 0/1 逻辑映射成双极性即 0→1、1→-1正交关系在双极性下依然严格成立。N越大处理增益越高可支持的用户数越多但码片速率被抬高同步要求也越苛刻。码长选择可以参考下表码长 N处理增益 dB正交码数量适用场景46.04教学演示89.08简单多用户1612.016小规模接入3215.132同步性能研究实战中做误码率仿真用 N31 或 63 的 m 序列更普遍因为沃尔什码的自相关旁瓣不一定低但研究多址干扰时沃尔什码不可替代。3.2 send_moudle 的扩频与极性映射发送模块完成三件事信息比特极性映射、码片复制、扩频相乘。下面的 send_moudle 结构能复现源码包的行为function [tx, pn] send_moudle(data, code, code_index) % data : 0/1 信息比特行向量 % code : 扩频码矩阵或行向量 % code_index : 选第几个码作为扩频码默认1 if nargin 3 code_index 1; end info 2*data - 1; % 0/1 - -1/1 pn code(code_index, :); % 取一行双极性码 info_up reshape(repmat(info, length(pn), 1), 1, []); tx info_up .* repmat(pn, 1, length(info)); end这里repmat将每个比特扩展成length(pn)个码片扩频倍数等于码长。info_up是扩展后的信息序列repmat(pn, 1, length(info))把伪码重复到与扩展序列等长两者逐点相乘完成扩频。双极性表示下没有真正的“乘”硬件实现工程里对应 FPGA 的异或门操作Matlab 里用点乘结果更直观。如果 data 是 0/1 序列而忘了转极性会出现扩频后各码片之间缺少对应的抑制作用误码率曲线整体异常。3.3 yongwuAwumlvjisuan.m 的运算本质yongwuAwumlvjisuan.m 承担扩频运算输入两个双极性序列输出乘积序列。实际包里可能还有额外的边界处理但核心逻辑可以抽象成function out yongwuAwumlvjisuan(info_seq, pn_seq) info_rep kron(info_seq, ones(1, length(pn_seq))); out info_rep .* pn_seq; endkron的语义是先将每个信息比特重复length(pn_seq)次形成串行码片流再与伪码逐点相乘。这段代码与 send_moudle 里的展开方式等价区别在于它是底层算子send_moudle 负责把用户参数准备好。参数上要强制输入已经是双极性序列否则点乘结果失去正负号信息。在仿真链路里yongwuAwumlvjisuan.m 可以同时被发送端和同步测试复用避免写两份重复的扩频代码。4. 高斯噪声、接收解扩与 SNR 估计把仿真做到可信4.1 gngauss.m 的噪声模型信道噪声建模为加性高斯白噪声时gngauss.m 用于生成指定方差的高斯样本。它通常采用 Box-Muller 变换将两个均匀分布随机数转成标准正态分布样本再乘标准差。代码可以写成function n gngauss(sigma) % sigma : 噪声标准差 u1 rand; u2 rand; z sqrt(-2*log(u1)) * cos(2*pi*u2); n sigma * z; end这个函数每次只返回一个样本因此在实际链路中需要循环调用。几千个码片规模下开销可接受如果要仿真 10^6 个码片更推荐向量化写法noise sigma * randn(1, N)。标准差sigma与噪声功率直接相关噪声功率为sigma^2。在 5.3 节会看到从 Eb/N0 换算 sigma 是一个容易出错的点必须把扩频码长考虑进去否则生成的信道噪声与理论曲线对不上。4.2 receive_module 的滑动相关同步策略接收端的首要任务是找到本地伪码和接收信号的相对延迟工程上最简单可靠的策略是滑动相关把本地码循环移位 k 个码片与接收信号相乘累加相关值最大的位置就是码相位估计。receive_module.m 可以按下面的方式理解function [data_hat, offset, peak, corr] receive_module(rx, pn) % rx : 接收基带信号长度必须为 length(pn) 的整数倍 % pn : 双极性扩频码 chip_len length(pn); mat reshape(rx, chip_len, []); % 每行对应一个信息比特的码片块 corr zeros(1, chip_len); for shift 1:chip_len pn_shift circshift(pn, [0, shift-1]); corr(shift) abs(mean(mat * pn_shift)); end [peak, offset] max(corr); pn_sync circshift(pn, [0, offset-1]); despread mat * pn_sync; data_hat despread 0; end这里circshift完成伪码循环移位reshape(rx, chip_len, [])把连续码片流分割成每个信息比特一个块。相关值最大的offset就是同步位置估计。注意循环移位适用于周期性的 m 序列对非周期性的突发帧需要用前导码做线性移位相关否则边缘效应会引入误差。如果每码片有多个采样点需要先把接收信号按码片抽取成单样本序列或把搜索步长改为采样点间隔两种做法对应不同的代码路径。4.3 SNR.m 估计的信噪比口径SNR.m 负责计算接收信号信噪比输入一般是一段含噪信号和一段噪声样本输出 dB 值function s SNR(signal, noise) Ps mean(signal.^2); % 含噪信号总功率 Pn mean(noise.^2); % 噪声功率 s 10*log10((Ps - Pn) / Pn); % 扣除噪声功率得到信号功率 endPs是含噪信号的总功率减去Pn得到信号自身功率再除以Pn就是线性信噪比。这个测量口径与理论上的 Eb/N0 之间有固定换算关系解扩前 SNR 比解扩后低处理增益 dB。码长 31 的 m 序列处理增益约 14.9 dB接收端若测得解扩前 SNR-10 dB解扩后应接近 4.9 dB。如果 SNR.m 输出的解扩增益小于这个值说明伪码没有同步或相关峰搜索失败。调参时可以参考下面的配置表参数含义推荐值sigma噪声标准差由 Eb/N0 换算samps_per_chip每码片采样点2 ~ 4search_step同步搜索步长1/samps_per_chippn_len扩频码长度31 / 63其中search_step必须与内插后的采样率匹配否则会出现相邻搜索位置都找不到峰值的情况。5. 同步性能仿真主程序参数与误码率曲线5.1 main.m 里的关键参数main.m 是整个仿真程序的调度入口。在跑通之前必须把参数确定下来信息比特数、扩频码类型、码长、每码片采样点、信噪比扫描范围。每码片采样点对同步性能的影响最明显取 1 时只能检测整数码片偏移取 2 时能分辨半码片误差取 4 可以做到 0.25 码片。参数建议如下参数值说明num_bits1000统计 BER 需要足够样本code_len31m 序列周期处理增益约 14.9 dBsamps_per_chip2同步分析时使用BER 主流程跑码片级SNR_dB-10:2:10常规 AWGN 扫描范围code_typem_seq可选 walsh用于多址对比这组参数下单条 SNR 点产生 31000 个码片普通笔记本跑完 11 个信噪比点约一分钟方便反复调参。5.2 码相位偏差对相关峰的影响同步性能仿真的核心观察对象是相关峰峰值与码相位误差的关系。m 序列自相关函数在零偏移处等于码长 L其他整数偏移为 -1/L。当接收端本地码与发送端的相对偏差超过一个码片时相关峰几乎消失判决输出趋于随机。为了量化这个效应我在链路中加入可控延迟并做上采样samps_per_chip 2; tx_up reshape(repmat(tx, samps_per_chip, 1), 1, []); % 2倍上采样 tau 0.3 * samps_per_chip; % 0.3码片延迟的采样点数 delayed_tx [zeros(1, round(tau)), tx_up]; corr_peak zeros(1, 50); for shift 1:50 seg delayed_tx(shift:shift length(tx_up) - 1); chip_seg seg(1:samps_per_chip:end); % 抽取到码片级 [~, ~, corr_peak(shift)] receive_module(chip_seg, pn); end plot(1:50, corr_peak); xlabel(搜索起始位置); ylabel(相关峰);这里的tau是定时偏移模拟值corr_peak展示不同初相下相关峰的衰减。实际绘制后会看到偏移 0.5 码片时相关峰已明显下降1 码片时降至旁瓣水平此时 BER 必然接近 0.5。这个曲线是判断接收端同步算法是否有效的直接证据。源码包里的 main.m 一般会用类似手段扫描不同偏移得到同步性能随相位误差变化的曲线。5.3 跑通全链路并绘制 BER 曲线完整链路把发送、噪声、同步和误码统计串起来。5.3 的 BER 主流程在码片级仿真每个码片一个样本避免噪声功率换算歧义。代码可以写成EbN0_dB -10:2:10; code_len 31; pn 2*m_sequence(5, [5 3]) - 1; for idx 1:length(EbN0_dB) data randi([0 1], 1, 1000); tx send_moudle(data, pn, 1); EbN0_lin 10^(EbN0_dB(idx)/10); sigma sqrt(1 / (2 * EbN0_lin * code_len)); noise zeros(size(tx)); for m 1:length(tx) noise(m) gngauss(sigma); end rx tx noise; data_hat receive_module(rx, pn); ber(idx) mean(data ~ data_hat); end semilogy(EbN0_dB, ber, o-); hold on; semilogy(EbN0_dB, qfunc(sqrt(2*10.^(EbN0_dB/10))), --); xlabel(Eb/N0 (dB)); ylabel(BER); legend(仿真,理论);这里sigma的换算是关键BPSK 的每比特能量 Eb 在扩频后等于码长code_len所以噪声方差要除以code_len否则噪声功率被高估。qfunc(sqrt(2*EbN0_lin))是 BPSK 理论误码率扩频不改变 AWGN 下的误码性能两条曲线应该基本重合。若仿真曲线在高信噪比区域出现平台优先怀疑同步搜索步长过粗或相关峰判决门限问题而不是噪声生成问题。6. 调参技巧让仿真结果更接近理论值6.1 扩频码平衡性检查m 序列每个周期有 2^(n-1) 个 1 和 2^(n-1)-1 个 0转换为双极性后正负样本数量差 1直流分量约为 1/L。这个不平衡会在频谱上留下离散谱线导致 SNR.m 计算信号功率时把直流分量也算进去使信噪比估计偏高。调试第一步是检查平衡性pn_bipolar 2*m_sequence(5, [5 3]) - 1; balance sum(pn_bipolar); % 期望为 -1如果 balance 明显不是 ±1说明反馈抽头不是本原多项式必须重新查表确定 taps。这个检查在跑 main.m 之前做成本几乎为零却能避免后面所有结果被污染。6.2 同步搜索步长的选择当 BER 曲线在低信噪比区域比理论值差最常见原因是同步搜索步长太大。步长为 1 码片时同步误差最大可达 0.5 码片相关峰损失约 3 dB步长减小到 0.5 码片损失降到约 0.9 dB。但步长减小会线性增加运算量。实用做法是先按 1 码片步长跑通链路确认各模块没有错误再提高samps_per_chip到 2 或 4观察同步误差分布是否收敛。main.m 中的相关峰搜索循环会随步长细化而变慢因此只对重点信噪比点做细扫全范围扫描保持粗步长。6.3 用峰均比自动判定同步失败同步模块最怕的是把旁瓣当主瓣静默地解出随机数据。调试时把 receive_module 的corr数组拿出来算峰均比[~, ~, ~, corr] receive_module(rx, pn); peak_to_avg max(corr) / (mean(abs(corr)) eps);m 序列同步成功时peak_to_avg通常大于 5未同步时接近 1。在 main.m 中加一个阈值判断凡是peak_to_avg 2的帧标记为同步失败并排除在误码统计之外。这样能快速定位是信道噪声过大还是伪码本身出了问题。最后建议在 main.m 开头固定随机种子rng(2024);。伪码序列、噪声样本和误码位置完全可复现尤其在低 SNR 区域误码数量少时随机波动会让 BER 曲线出现毛刺影响判断固定种子后同一组参数每次运行结果一致不同参数之间的差异才能真实反映到曲线上。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进