简介这份资源是面向通信工程、电子信息类专业学生及扩频通信初学者的MATLAB仿真设计文档围绕直接序列扩频DSSS通信系统展开帮助读者理解扩频、解扩与抗干扰性能评估的完整流程。文档系统讲解了直扩系统模型、BPSK调制方式、m序列与GOLD码等伪随机码类型以及扩频通信在抗同频干扰、抗衰落、抗多径干扰方面的优势并给出信源速率2kbps、扩频因子64、高斯信道下的仿真参数设置与误码率随信噪比变化的分析思路。资源包内仅含1个doc文件大小约320KB内容涵盖实验原理、系统组成框图说明、部分程序代码与仿真结果展示结构紧凑便于直接查阅与参考。目前已有142人学习适合作为课程设计、实验报告或扩频通信入门仿真的参考资料读者可据此快速搭建MATLAB仿真框架并进一步调整参数研究不同条件下的系统性能。1. 直接序列扩频通信仿真到底在仿什么很多人第一次看到「基于 MATLAB 的直接序列扩频通信系统仿真设计」这个标题第一反应是去翻通信原理教材里那一堆 PN 码、扩频增益、解扩的公式然后打开 Simulink 拖几个模块跑出一条误码率曲线就交差。但真正做过一轮完整仿真的人会告诉你这个题目的核心不是「搭出一个能跑的模型」而是搞清楚扩频和解扩这一对操作在时域、频域上到底把信号变成了什么样噪声和干扰又是怎么被摊薄的。直接序列扩频DSSS的本质是用一个高速率的伪随机码去乘以低速率的窄带信息把信号能量摊到很宽的频带上接收端再用同一个码把它收回来。这个过程里扩频增益、码同步、解扩后的信噪比改善才是仿真真正要验证的东西。这篇文章面向的是通信、电子相关方向的学生和刚入行的工程师目标是把一套可复现的 MATLAB 仿真流程讲清楚从参数怎么定、码怎么生成、每一步为什么这么写到跑出来结果不对时该往哪里查。2. 把 DSSS 的数学模型翻译成可执行的 MATLAB 参数2.1 先定死五个参数不然后面全是玄学直接序列扩频仿真翻车十有八九是参数没定清楚就开始写代码。我一般会先把下面这五个量固定下来后面所有模块都围绕它们展开。参数符号典型取值说明信息比特率Rb1 kbps单个用户原始数据速率扩频码速率Rc31 kbps一个比特对应多少个码片扩频增益Gp10log10(Rc/Rb)本例约 14.9 dB载波频率fc10 kHz相对码速率要留够带宽采样率fs200 kHz至少是码速率的 6 倍以上扩频增益 Gp 是整个仿真的灵魂。它决定了你解扩之后信噪比能改善多少也决定了误码率曲线能压到多低。如果 Rc/Rb 只取 4 或者 8那扩频增益只有 6 到 9 dB在强噪声下曲线会很难看你会误以为是代码写错了其实是参数本身就没给够余量。常见做法是让一个信息比特对应 31 或 63 个码片这样增益在 15 到 18 dB仿真出来的效果比较有说服力。采样率 fs 的选取也有讲究。它必须远大于码速率否则码片边沿会糊掉解扩时相关峰展宽同步判决就会飘。我一般取 fs 8×Rc 到 10×Rc本例中 Rc 是 31 kbpsfs 取 200 kHz 左右每个码片大约 6 到 7 个采样点够用且不至于让仿真慢得离谱。2.2 用 m 序列生成扩频码别用 rand 糊弄扩频码必须是确定性的伪随机序列接收端要能复现出完全一样的码否则解扩就是空谈。MATLAB 里没有现成的 m 序列函数得自己写移位寄存器。下面这段代码生成一个周期为 31 的 m 序列对应 5 级移位寄存器。% 生成 5 级 m 序列周期 2^5-1 31 % 本原多项式 f(x) x^5 x^2 1对应抽头 [5 2] n 5; % 移位寄存器级数 N 2^n - 1; % 序列周期 reg [1 0 0 0 0]; % 初始状态不能全零 pn zeros(1, N); % 预分配扩频码 for k 1:N pn(k) reg(n); % 输出最高位 fb xor(reg(5), reg(2)); % 反馈抽头异或 reg [fb reg(1:n-1)]; % 右移并注入反馈 end pn 2*pn - 1; % 把 0/1 映射成 -1/1这段代码的逻辑是标准的线性反馈移位寄存器。reg 数组代表 5 个寄存器每次循环把最高位输出作为码片同时把第 5 位和第 2 位异或后反馈到最低位。抽头位置 [5 2] 对应本原多项式 x^5 x^2 1这个多项式保证序列周期达到最大值 31。最后一步把 0/1 映射成 -1/1 是为了后续做双极性相关运算比单极性方便得多。参数说明n 决定周期长度n 取 5 到 10 都常见n 越大码越长、扩频增益越高但同步搜索时间也越长。初始状态 reg 不能全零否则序列会锁死在零状态出不来。抽头位置不是随便选的必须查本原多项式表选错了周期会缩短扩频性能直接打折。2.3 扩频、加噪、解扩三步走通一条链路有了信息比特和扩频码接下来就是把整条链路串起来。下面这段代码完成一次完整的扩频调制、信道加噪、解扩判决。Rb 1000; % 信息比特率 Rc 31000; % 码片速率 fs 200000; % 采样率 sps_info fs / Rb; % 每比特采样点数 sps_chip fs / Rc; % 每码片采样点数 num_bits 1000; % 仿真比特数 data randi([0 1], 1, num_bits); % 随机信息比特 data_bip 2*data - 1; % 双极性映射 % 生成与比特数匹配的扩频码 pn_full repmat(pn, 1, ceil(num_bits*Rc/Rb/length(pn))); pn_full pn_full(1:num_bits*Rc/Rb); % 扩频每个信息比特乘以 31 个码片 spread zeros(1, num_bits*Rc/Rb); for k 1:num_bits idx (k-1)*Rc/Rb 1 : k*Rc/Rb; spread(idx) data_bip(k) * pn_full(idx); end % 上采样到采样率 spread_upsample rectpulse(spread, sps_chip); % 加高斯白噪声 snr_db 0; % 信噪比 spread_noisy awgn(spread_upsample, snr_db, measured); % 解扩与同步的扩频码逐段相关 despread zeros(1, num_bits); for k 1:num_bits idx (k-1)*Rc/Rb*sps_chip 1 : k*Rc/Rb*sps_chip; seg spread_noisy(idx); pn_seg rectpulse(pn_full((k-1)*Rc/Rb1 : k*Rc/Rb), sps_chip); despread(k) sum(seg .* pn_seg); end % 判决 data_out despread 0; ber sum(data_out ~ data) / num_bits;逻辑上分四步。第一步把信息比特做双极性映射0 变 -1、1 变 1这样乘法就等价于扩频。第二步把扩频码重复铺开到和信息比特等长每个比特对应 31 个码片。第三步逐比特做扩频再用 rectpulse 把码片序列上采样到采样率模拟实际波形的持续时长。第四步加噪后用同一段扩频码做相关累加相关值大于零判为 1否则判为 0。参数说明snr_db 是信道信噪比可以先从 0 dB 开始跑再扫到 -10 dB 看扩频增益的效果。rectpulse 的第二个参数 sps_chip 是每个码片的采样点数它决定了相关运算的精度。解扩时的 idx 必须和扩频时的索引严格对齐差一个采样点相关峰就会掉误码率会莫名其妙地高——这是新手最容易踩的坑之一。3. 误码率曲线怎么扫、怎么画才说明问题3.1 用循环扫 SNR别只跑一个点单跑一个信噪比点看不出扩频到底有没有用。正确的做法是让信噪比从 -20 dB 扫到 5 dB每个点跑足够多的比特统计误码率然后画半对数曲线。snr_range -20:1:5; % 信噪比扫描范围 ber_curve zeros(size(snr_range)); num_bits 5000; % 每个 SNR 点跑 5000 比特 for si 1:length(snr_range) snr_db snr_range(si); err_cnt 0; for trial 1:10 % 每个点重复 10 次取平均 % ... 此处复用上一节的扩频解扩流程 ... err_cnt err_cnt sum(data_out ~ data); end ber_curve(si) err_cnt / (num_bits * 10); end semilogy(snr_range, ber_curve, b-o, LineWidth, 1.5); xlabel(SNR (dB)); ylabel(BER); grid on;这里的关键是每个信噪比点要跑足够多的比特。5000 比特乘以 10 次重复总共 5 万个比特在误码率 10^-3 量级时能统计到几十个错误曲线不会太毛糙。如果只跑 1000 个比特误码率低于 10^-2 之后基本就是零错误曲线会断掉看起来像是「性能无限好」其实是统计样本不够。参数说明snr_range 的下限取决于你的扩频增益。如果 Gp 是 15 dB那信噪比扫到 -15 dB 左右应该还能看到误码率明显低于不扩频的情况。trial 次数越多曲线越平滑但仿真时间线性增长一般 10 到 20 次够用。3.2 把扩频和不扩频画在一张图里对比才有说服力单独一条误码率曲线说明不了扩频的价值。我一般会把「扩频后解扩」和「不扩频直接判决」两条曲线画在同一张图上横轴是信噪比纵轴是误码率。% 不扩频的参考曲线直接对信息比特加噪判决 ber_ref zeros(size(snr_range)); for si 1:length(snr_range) snr_db snr_range(si); data_bip 2*randi([0 1],1,num_bits) - 1; rx awgn(data_bip, snr_db, measured); ber_ref(si) sum((rx0) ~ (data_bip0)) / num_bits; end semilogy(snr_range, ber_curve, b-o, snr_range, ber_ref, r-s); legend(DSSS 扩频解扩, 不扩频直接判决);两条曲线的水平间距就是扩频增益带来的信噪比改善。理论上这个间距应该接近 10log10(Rc/Rb)实际因为采样、相关运算的离散化误差会略有偏差但趋势必须对。如果两条曲线几乎重合那说明扩频环节没起作用大概率是扩频码没有正确对齐或者解扩时的相关运算写成了简单的求和而没有乘码。3.3 用眼图和频谱验证中间过程误码率曲线是最终结果但中间过程对不对得靠眼图和频谱来查。扩频后的信号频谱应该明显展宽功率谱密度下降解扩后的信号应该恢复出窄带特征。% 扩频前后频谱对比 Nfft 1024; f (-Nfft/2:Nfft/2-1) * fs / Nfft; S_spread fftshift(abs(fft(spread_upsample(1:Nfft), Nfft))); S_despread fftshift(abs(fft(despread(1:Nfft), Nfft))); figure; subplot(2,1,1); plot(f/1000, 20*log10(S_spreadeps)); title(扩频后频谱); xlabel(频率 (kHz)); ylabel(幅度 (dB)); subplot(2,1,2); plot(f/1000, 20*log10(S_despreadeps)); title(解扩后频谱); xlabel(频率 (kHz)); ylabel(幅度 (dB));扩频后的频谱应该比信息带宽宽出大约 Rc/Rb 倍解扩后能量重新集中到信息带宽内。如果扩频后频谱没展宽检查扩频码是不是真的乘进去了如果解扩后频谱还是一团散检查相关运算的索引对齐。4. 仿真跑不通时先查这五个地方4.1 误码率始终在 0.5 附近码没对齐现象不管信噪比多高误码率都在 0.5 左右等于瞎猜。 原因解扩时用的扩频码和扩频时的码没有对齐相关运算结果接近零判决完全随机。 解决在解扩循环里打印第一段的相关值确认它明显偏离零。检查 pn_full 的索引是否从 1 开始逐段取以及 rectpulse 后的长度是否和信号段长度一致。4.2 误码率比理论值高一大截采样率不够现象曲线趋势对但整体比理论值高两三个数量级。 原因每个码片的采样点数太少相关运算的离散化误差大等效于信噪比损失。 解决把 fs 提高到 Rc 的 8 到 10 倍重新跑。如果曲线明显下移说明之前是采样精度不够。4.3 扩频后频谱没变化乘法写成了加法现象扩频前后频谱几乎一样看不出展宽。 原因扩频操作写成了 spread data pn 而不是 data .* pn或者双极性映射没做。 解决确认 data_bip 是 -1/1 而不是 0/1确认扩频用的是逐元素乘法。4.4 仿真跑得极慢循环里反复分配大数组现象跑一次误码率曲线要几十分钟。 原因在 SNR 循环内部反复生成大矩阵或者用未预分配的数组不断增长。 解决把扩频码、上采样后的码型提前算好存在变量里循环内只做乘法和相关。预分配所有结果数组。4.5 高信噪比下误码率不为零判决门限偏了现象信噪比很高时误码率应该趋近于零但始终有个小尾巴。 原因相关值的判决门限设成了固定值而不是零或者直流偏置没去掉。 解决判决直接用 despread 0不要设额外门限。检查信号里有没有意外的直流分量。5. 把仿真从「能跑」推到「可信」的两个进阶习惯5.1 用理论误码率公式做标尺仿真跑出来的曲线不能只看趋势得和理论值对得上。直接序列扩频在加性高斯白噪声信道下解扩后的等效信噪比是 Eb/N0 乘以扩频增益。BPSK 的理论误码率是 Q(sqrt(2*Eb/N0))MATLAB 里可以用 berawgn 或者 qfunc 算。EbN0_dB snr_range 10*log10(Rc/Rb); % 折算到解扩后 EbN0_lin 10.^(EbN0_dB/10); ber_theory qfunc(sqrt(2*EbN0_lin)); semilogy(snr_range, ber_curve, b-o, snr_range, ber_theory, k--); legend(仿真, 理论);如果仿真曲线和理论曲线在低信噪比段贴合、高信噪比段仿真略高那是正常的离散化损失。如果两条曲线平行但差了好几个 dB说明仿真链路里有额外的信噪比损失得回去查采样率、滤波器或者相关运算的长度。5.2 把关键中间变量存下来别每次都重跑调试阶段最耗时的不是写代码是反复跑仿真等结果。我的习惯是在第一次跑通之后把扩频后的信号、解扩前的相关值、每个 SNR 点的误码数全部 save 成 mat 文件。后面改判决逻辑或者画图时直接 load不用重新跑链路。save(dsss_debug.mat, spread_upsample, despread, ... ber_curve, snr_range, pn);这个习惯在参数扫描时特别有用。比如你想比较不同扩频码长度对误码率的影响只需要改 n 重新跑一次链路把结果追加到同一个 mat 文件里画图时一起 load 出来对比。省下来的时间够你多试好几组参数。说到底直接序列扩频仿真这个题目代码量不大但每个参数、每个索引、每次对齐都有讲究。我自己的血泪经验是先把参数表定死再把 m 序列生成和验证单独跑通最后才串整条链路。中间任何一步结果不对都不要急着往下走把那个环节的波形画出来看一眼比盯着代码猜快得多。希望帮到你。本文还有配套的精品资源点击获取