
简介面向通信工程、电子信息类课程学习者与扩频通信初学者的MATLAB直接序列扩频通信系统仿真设计文档围绕DSSS的扩频、解扩与抗干扰性能评估展开适合课程设计、实验复现和原理梳理。压缩包内仅含1个doc文档约320KB内容从发送端信息与PN码模二加、接收端相关解扩的基本流程讲起覆盖直扩系统模型、BPSK调制、m序列与GOLD码等伪随机码类型以及信源速率2kbps、扩频因子64和高斯信道下的误码率仿真。文档还结合部分程序代码与仿真结果说明抗同频干扰、抗衰落和抗多径干扰的实现思路读者可据此搭建仿真框架、调整参数并观察系统性能变化结构清晰便于按实验模块查阅与复现。已有143人学习下载适合需要把扩频通信原理落到MATLAB实现的中初级读者参考。1. 一条过于漂亮的误码率曲线直接序列扩频在 MATLAB 里到底仿真什么第一次把直接序列扩频的误码率曲线跑出来不少人会怀疑自己代码写错了横轴才 4 dBBER 已经掉到 10⁻³ 以下比不扩频的 BPSK 好看一大截。等把横轴从比特信噪比换成码片信噪比两条曲线立刻贴在一起——扩频并没有凭空造出信噪比它只是把能量摊到更宽的带宽上再在解扩时把有用信号相干地收回来。MATLAB 上的直接序列扩频通信系统仿真做的就是把这笔「摊开再收回」的账算清楚m 序列怎么生成、码片怎么对齐、Eb/N0 怎么换算、解扩后的软判决值受什么影响。这篇写给已经学过通信原理、但一动手就发现曲线对不上的人从一条能跑通的最小链路开始把参数、代码和翻车点一个个落到具体数字上。2. 扩频增益从哪来把 DSSS 拆成四个能单独验证的环节一条完整的直接序列扩频链路拆开看只有四件事产生伪随机码、把比特乘上码片、过信道、用同一段码把信号收回来。任何一环的顺序或长度搞错最后画出来的 BER 曲线都会以「玄学」的方式偏离理论值。这一章先把四件事的数学关系摆清楚后面写代码时才知道每一行在算什么。2.1 一个比特摊成 N 个码片能量没变但判决前的信噪比变了设比特率为 $R_b$每个比特用长度为 $N$ 的伪随机码扩频码片速率就是 $R_c N R_b$。发送端把 BPSK 符号 $s_k \in {1,-1}$ 与码序列 $c[n]\in{1,-1}$ 逐码片相乘得到$$x[n] s_k \cdot c[n],\quad n 0,\dots,N-1$$每个码片的能量是 $E_c$每个比特的能量 $E_b N E_c$。扩频前后总能量一点没变只是把它从 $T_b$ 的时间里摊到了 $N$ 个码片上占用带宽相应扩了 $N$ 倍。接收端做相干解扩就是把收到的 $N$ 个码片再乘一遍本地码并求和$$y_k \sum_{n0}^{N-1} r[n],c[n] N s_k \sum_{n0}^{N-1} w[n],c[n]$$有用信号相干累加幅度变成 $N$ 倍功率变成 $N^2$ 倍噪声是非相干的$N$ 个独立样本相加功率只涨 $N$ 倍。一进一出解扩后的信噪比改善了 $N$ 倍这就是处理增益$$G_p 10\log_{10} N \ \text{dB}$$$N31$ 时约 14.9 dB$N127$ 时约 21 dB。这个数字是整篇仿真的基准后面任何一条曲线只要和理论 BPSK 差了大约 $G_p$先别怀疑信道模型先怀疑自己把信噪比定义在哪一级。处理增益还有一个常被忽略的用法——干扰容限。系统能忍受的干扰功率大致是 $G_p$ 减去解调所需信噪比再减去实现损耗。窄带干扰在解扩时被本地码「再扩」一次带宽被摊开 $N$ 倍落到判决带宽内的功率只剩 $1/N$而有用信号被收窄回比特带宽。这个不对称就是直接序列扩频抗窄带干扰的全部原理。仿真里要验证它只需要在信道里加一个单频正弦然后看解扩前后的频谱。2.2 码序列选 m 序列还是 Gold 序列自相关旁瓣决定了解扩干不干净伪随机码不是随便一串 ±1 就行它的自相关函数决定了解扩能不能把能量干净地收回来。理想的码零时延自相关为 1其余时延为 0。实际能拿到的只有准正交序列。m 序列是最常用的选择$m$ 级线性反馈移位寄存器周期 $N2^m-1$双极性归一化自相关满足$$R(\tau)\begin{cases}1, \tau 0\ -1/N, \tau \ne 0\end{cases}$$$N31$ 时旁瓣只有 $-0.032$几乎可以忽略。这意味着只要码片定时对齐解扩输出里由其他比特、其他用户泄漏过来的能量极小判决门限稳稳压在零上。选 m 序列的三个实际理由一是生成只要一个移位寄存器加几个异或MATLAB 里十几行就够不需要查表二是周期 $2^m-1$ 覆盖了绝大多数扩频因子的取值习惯31、63、127、255三是自相关特性有闭式表达仿真结果不对时可以拿它当标尺反查。Gold 序列的优势在不同用户之间两个 m 序列优选对模 2 相加得到的序列族互相关是三值的适合多址场景。单用户点对点仿真用不上但如果你打算把链路扩成两用户直接换成 Gold 序列会比手动错开 m 序列初态更省事。有一条边界要记住m 序列的旁瓣是 $-1/N$不是 0。当扩频因子只有 7 或 15 的时候旁瓣已经到 $-0.14$ 和 $-0.067$多径或定时偏差稍微大一点解扩输出就会出现肉眼可见的偏置。$N$ 太小时不要指望曲线能贴着理论值走。2.3 基带等效仿真还是带通仿真采样率和计算量的两笔账同一套扩频链路可以在基带做也可以在带通做两者的计算量差一个数量级。带通仿真需要把信号搬到载频 $f_c$ 上采样率至少 $2(f_cB_{ss})$。假设码片速率 1 MHz、扩频因子 31、载频 10 MHz采样率要到 22 MHz 以上仿真 2 万个比特就是 6.8 亿个采样点普通机器上跑一轮扫描要几十分钟。基带等效仿真只保留复包络采样率由码片速率决定$f_s \text{sps}\times R_c$sps 是每码片采样点数取 4 到 16 就足够。同样是 2 万个比特、31 倍扩频、sps8总采样点只有 496 万秒级出结果。载波的相位旋转在基带里体现为一个复指数因子如果想验证载波相位偏差对解扩的影响乘一个 $e^{j\theta}$ 就等价于带通里的相位误差不需要真的产生高频载波。我的习惯是算法验证阶段一律用基带实信号±1 码片不加复载波只保留「扩频—加噪—解扩」三个环节等要验证频偏、相位噪声、I/Q 失衡这类射频损伤时再升级到复基带把损伤作为乘性因子加进去。真要出带通波形给外部工具或者硬件再单独写一段上变频脚本不要让载波拖慢整个参数扫描。3. 最小可跑链路m 序列、BPSK 扩频与相干解扩的 MATLAB 实现原理清楚之后剩下的全是顺序问题。这一章给一条能直接跑出 BER 曲线的链路从码序列生成到理论值对比每一步都标清楚为什么这么写。3.1 三十行写出 m 序列发生器并用自相关自检先写码序列。核心是一个 $m$ 级移位寄存器每个时钟把抽头位置的比特模 2 相加反馈进最高位最低位输出。function pn gen_mseq(m, taps, seed) % GEN_MSEQ 生成周期为 2^m-1 的双极性 m 序列 % m : 移位寄存器级数周期 N 2^m - 1 % taps : 反馈抽头下标1 表示最高级对应本原多项式的非零项 % seed : 1 x m 初态不能全 0否则输出恒为 0 reg seed(:).; if numel(reg) ~ m || all(reg 0) error(初态长度必须等于 m且不能全 0); end N 2^m - 1; pn zeros(1, N); for k 1:N pn(k) reg(end); % 最低级输出一个码片 fb mod(sum(reg(taps)), 2); % 抽头模 2 和作为反馈 reg [fb, reg(1:end-1)]; % 右移一位反馈注入最高级 end pn 1 - 2*pn; % 0/1 映射成 1/-1 end这段的关键在taps。m5配taps[1 4]对应本原多项式 $x^5x^21$抽头从最高级 $x^5$ 数起分别是第 1 级和第 4 级。抽头选错不会报错只是周期变短输出看起来仍然像噪声——这是最阴的一类 bug。生成之后必须自检用自相关验证周期和旁瓣pn gen_mseq(5, [1 4], [1 0 0 0 0]); R xcorr(pn, biased); N numel(pn); fprintf(周期%d 零时延%.3f 旁瓣均值%.4f\n, ... N, R(N), mean(R([1:N-1, N1:end])));biased选项让自相关按 $1/N$ 归一化正确输出是「周期31 零时延1.000 旁瓣均值-0.0323」。旁瓣均值跑到 $-0.1$ 以上基本就是抽头错了或者初态退化。这一步花十秒钟能省掉后面两小时的排查。参数说明m决定周期也决定扩频因子的候选值seed只影响序列的相位偏移不影响周期但如果多个用户共用同一组抽头初态必须错开否则两个用户的码完全一样多址仿真直接失效。3.2 扩频调制与 AWGN 信道kron 与 repelem 的顺序不能反有了码主链路就是把比特铺成码片、加噪、再收回来。这里有两个展开操作顺序和维度必须一次写对。clear; clc; rng(2024); m 5; % 寄存器级数 sf 2^m - 1; % 扩频因子31 nBits 20000; % 每帧比特数 sps 8; % 每码片采样点数 ebn0dB 0:2:10; % 比特信噪比扫描点 pn gen_mseq(m, [1 4], [1 0 0 0 0]); % 1 x 31取值 ±1 pnw repelem(pn, sps); % 每码片展开成 sps 个采样点 ber zeros(size(ebn0dB)); for ii 1:numel(ebn0dB) data randi([0 1], 1, nBits); sym 1 - 2*data; % BPSK0 - 11 - -1 tx kron(sym, pn); % 逐比特扩频长度 nBits*sf txw repelem(tx, sps); % 矩形码片成形 ebn0 10^(ebn0dB(ii)/10); sigma sqrt(sf * sps / (2 * ebn0)); % 每个采样点的噪声标准差 rxw txw sigma * randn(size(txw)); rx reshape(rxw, sf*sps, nBits); % 每列对应一个比特 y sum(rx .* pnw(:), 1); % 相干解扩本地码加权求和 hat y 0; % 软判决值取符号 ber(ii) mean(hat ~ data); end三行核心操作各管一件事。kron(sym, pn)把第 $k$ 个比特乘上整段码输出顺序是「比特1的31个码片、比特2的31个码片……」长度为nBits*sf。repelem(tx, sps)再把每个码片复制成 sps 个采样点模拟矩形脉冲成形长度变成nBits*sf*sps。reshape(rxw, sf*sps, nBits)按列切分第 $j$ 列恰好是第 $j$ 个比特对应的全部采样点与pnw(:)的长度和顺序完全对齐。噪声标准差那一行是整段代码里最容易写错的地方。sf*sps是每个比特占用的采样点数信号幅度为 1 时每个采样点的能量是 1所以 $E_b \text{sf}\cdot\text{sps}$。高斯白噪声的双边功率谱密度 $N_0/2$ 对应每个采样点的方差 $\sigma^2$于是$$\frac{E_b}{N_0} \frac{\text{sf}\cdot\text{sps}}{2\sigma^2}\ \Longrightarrow\ \sigma \sqrt{\frac{\text{sf}\cdot\text{sps}}{2,E_b/N_0}}$$漏掉sps因子曲线会整体平移 $10\log_{10}(\text{sps})$ dB看起来像「仿真比理论好 9 dB」实际只是噪声加少了。3.3 相干解扩与误码统计把 BER 曲线和理论值画在同一张图上跑完扫描把结果和相干 BPSK 的理论值画在一起是判断链路是否正确的唯一硬标准ber_th qfunc(sqrt(2 * 10.^(ebn0dB/10))); % 相干 BPSK 理论误码率 semilogy(ebn0dB, ber, o-, ebn0dB, ber_th, k--, LineWidth, 1.2); grid on; xlabel(E_b/N_0 (dB)); ylabel(BER); legend(DSSS 仿真, BPSK 理论); ylim([1e-5 1]);如果解扩、判决、噪声换算三处都写对了两条曲线应该在高信噪比段几乎重合。注意「几乎」扩频因子只有 31 时码序列的自相关旁瓣是 $-1/N$会给解扩输出带来一点残余偏置低信噪比段仿真值可能略高于理论值这属于正常误差。qfunc是 MATLAB 自带的 Q 函数等价于0.5*erfc(x/sqrt(2))。如果你的版本里没有这个函数直接换成0.5*erfc(sqrt(2*10.^(ebn0dB/10))/sqrt(2))结果一样。误码统计有一个隐藏的精度问题nBits20000时BER 低于 $5\times10^{-5}$ 就统计不到错误了曲线末端会出现断点或者突然掉到 0。想让曲线画到 $10^{-5}$比特数至少要 10 万量级这一点在设定仿真规模时就要算进去不要等画图时才发现最后一个点不可信。4. 参数怎么定扩频因子、每码片采样点与信噪比换算代码跑通只是起点参数选得不合适曲线照样不可信。这一章把三个必调量的边界讲清楚。4.1 扩频因子 SF 的三个约束码长、带宽和仿真时长扩频因子直接等于处理增益但它不是越大越好受三方面约束。第一是码长约束。用 m 序列时 SF 只能取 $2^m-1$可选值是 7、15、31、63、127、255、511。想取 32 或 100要么换 Gold 序列要么接受周期不整带来的截断误差。第二是带宽约束。扩频后占用带宽是 $B_{ss} \text{SF}\times R_b$如果码片速率被射频前端或采样率卡住SF 就顶到头了。仿真里虽然不受硬件限制但 sps 与 SF 的乘积决定了每比特的采样点数SF255、sps16 时每比特 4080 个采样点10 万比特就是 4 亿个 double内存先撑不住。第三是仿真时长约束。误码率统计需要足够多的错误样本粗略估计是「想测到 $10^{-k}$至少需要 $10^{k1}$ 个比特」。SF31 时 2 万比特足够画到 $10^{-4}$SF511 时同样的比特数只能画到 $10^{-3}$ 出头还得把仿真规模翻几倍。我的取值习惯算法验证用 SF31规模适中、旁瓣可忽略需要展示处理增益随 SF 变化的趋势时扫 7/31/127 三档画三条曲线对比做多址或干扰抑制时再上 255。扩频因子 SF处理增益每比特码片数建议仿真比特数适用场景78.5 dB75 万快速验证链路连通性3114.9 dB312 万单用户误码率曲线12721.0 dB1275 万处理增益对比、窄带干扰25524.1 dB25520 万多址、低信噪比捕获4.2 每码片采样点数 sps低于 4 就开始出现玄学误差sps 是每码片展开的采样点数。它不影响扩频增益的数学关系但影响仿真对定时偏差和码片成形的敏感度。sps1 等价于理想码片定时解扩时的积分就是简单的码片求和结果干净但掩盖了实际问题——真实接收机永远有定时误差sps1 的仿真给不出任何关于同步精度的信息。sps 取 4 到 8 是常规做法既能体现码片波形计算量也可控。低于 4 的时候如果后面要加半个码片的定时偏差采样点根本表达不出来误差会被量化成「要么对齐要么差一整片」曲线会莫名其妙地跳。矩形码片成形下sps 只改变采样密度不改变解扩后的信噪比判决结果应当完全一致。可以用这一点做自检把 sps 从 4 改到 16BER 曲线应该几乎重合。如果不一样说明解扩时的对齐用错了长度而不是 sps 本身有问题。如果想看升余弦成形的效果把repelem换成rcosdesign生成的成形滤波器做卷积注意滤波器会引入延迟解扩前要把接收端和发送端对齐否则那点群时延足以让所有比特判错。4.3 Eb/N0 与 SNR 的换算awgn 函数最容易埋的坑这是实测里翻车最多的一处。MATLAB 的awgn(x, snr)加的是「信号功率与噪声功率之比」单位 dB而误码率曲线的横轴通常是 $E_b/N_0$。两者差了一个「每比特几个采样点」的因子$$\text{SNR} \frac{E_b}{N_0}\cdot\frac{R_b}{f_s} \frac{E_b}{N_0}\cdot\frac{1}{\text{sps}\cdot\text{SF}}$$反过来说$\text{SNR(dB)} E_b/N_0\text{(dB)} - 10\log_{10}(\text{sps}\cdot\text{SF})$。SF31、sps8 时这个差值是 24 dB。直接把ebn0dB喂给awgn等于把噪声加少了 24 dB曲线会漂亮得完全不真实。量定义与 Eb/N0 的关系常见误用Eb/N0每比特能量与噪声功率谱密度之比基准量直接当成 SNR 传给 awgnSNR采样级采样点信号功率与噪声功率之比Eb/N0 − 10log10(sps·SF)忘了 sps 或 SF 中任一项Ec/N0每码片能量与噪声功率谱密度之比Eb/N0 − 10log10(SF)和 Eb/N0 混用于解扩后判决Es/N0每符号能量与噪声功率谱密度之比与本链路 Eb/N0 相同BPSK多进制时未按比特数换算稳妥的做法是绕开awgn函数直接手算噪声标准差再加也就是 3.2 节里那行sigma sqrt(sf*sps/(2*ebn0))。这样公式摆在明面上参数改动能一眼看出影响。真要用awgn就先写一行snr ebn0dB - 10*log10(sps*sf);让换算过程可见别把它藏进函数调用里。5. 避坑与排查解扩后误码率不降反升的 5 个现场记录下面这些都不是理论问题全是写代码时会真实撞上的。现象一BER 曲线比理论 BPSK 好了二十多 dB几乎贴着坐标轴下沿。原因把 $E_b/N_0$ 当成采样级 SNR 直接用了噪声功率少加了一个sps*SF的因子等价于信噪比虚高。解决按 4.3 节的公式重算 $\sigma$或者打印10*log10(sf*sps)和曲线平移量对比两个数对得上就说明是这个错。现象二低信噪比段 BER 在 0.5 附近高信噪比段突然掉到 0中间没有过渡。原因reshape的维度或顺序写反了解扩时本地码和接收样本错位相当于每个比特乘了随机码判决完全靠运气。解决先取nBits10、ebn0dB20跑一遍打印第 1 个比特的rx(:,1)与pnw(:)逐点乘积如果乘积的符号随机跳变就是对齐错了。检查kron与repelem的先后顺序以及reshape的行数是否等于sf*sps。现象三m 序列看起来正常但自相关旁瓣在 -0.15 左右处理增益比理论差 2 dB。原因本原多项式的抽头写错了生成的序列周期变短实际上是一段短序列在循环。解决用 3.1 节的自检脚本打印周期和旁瓣均值周期不等于 $2^m-1$ 就换抽头。查本原多项式表时注意抽头是从最高级还是最低级数起两种约定差一个镜像。现象四加入单频窄带干扰后误码率完全没有变化看不出扩频的作用。原因干扰频率落在了解扩后的带宽之外或者干扰功率定义得太大直接把接收机压死又或者干扰是加在解扩之后而不是信道里。解决干扰必须加在kron之后、reshape之前的时域波形上单频正弦的频率要落在扩频带宽之内、比特带宽之外才能真正体现「解扩时被摊开」的效果干扰功率从 −10 dB 相对信号功率开始扫不要一上来就加 20 dB。现象五sps 从 4 改到 16 之后BER 曲线整体平移了 6 dB。原因噪声方差公式里的 sps 和波形展开用的 sps 不是同一个值改参数时只改了一处。另一种可能是升余弦成形后没有做功率归一化滤波器增益被算进了信号功率。解决把 sps 作为唯一变量让sigma和repelem都从它派生不要在两处各写一个常数用成形滤波器时先sum(h.^2)检查归一化让滤波前后平均功率一致。6. 从「能跑」到「敢用」用理论曲线和干扰场景给仿真做交叉验证曲线和理论重合只证明链路在理想条件下算对了。真要用这套仿真去支撑设计决策还得补两个验证。第一个是处理增益的实测标定。把同一个 $E_b/N_0$ 下的三种情况画在一起不扩频的 BPSK、扩频但解扩前统计的 BER、扩频解扩后统计的 BER。第二种应该明显差于第一种因为每个比特被摊成 31 个码片单看码片信噪比更低第三种应该和第一种几乎重合。这三条线的相对位置比任何推导都能说明扩频到底做了什么。第二个是窄带干扰下的表现。在信道里叠一个单频正弦频率取码片速率的 0.3 倍落在扩频带宽内、比特带宽外功率从 −20 dB 扫到 0 dB记录 BER 恶化的拐点。理论上拐点应该出现在干扰功率接近处理增益的位置SF31 时大约在 15 dB 附近。如果拐点提前很多先查干扰是不是加错了位置如果根本不出现拐点查干扰频率是不是落在了解扩后的带宽内。验证项判据不通过时先查什么无干扰 BER 与理论重合度高信噪比段偏差 0.5 dB噪声方差里的 sps、SF 因子处理增益实测值与 10log10(SF) 相差 1 dBm 序列自相关旁瓣、码片对齐窄带干扰拐点与处理增益同量级干扰注入位置、干扰频率定时偏差敏感度偏移 0.25 码片内 BER 恶化可接受sps 是否足够表达亚码片偏移最后说一个省时间的习惯每次改完参数先只跑ebn0dB 8这一个点看 BER 是不是落在 $10^{-3}$ 到 $10^{-4}$ 之间。这个单点检查十秒钟出结果比扫完一整条曲线再回头找问题快得多。仿真这件事血泪经验往往就藏在这种「先跑一个点」的小动作里。希望帮到你。本文还有配套的精品资源点击获取