简介这份资源是一套基于MATLAB的扩频通信DSSS仿真代码聚焦直序扩频系统对抗窄带干扰的设计与验证面向无线通信、信号处理方向的学生与研究人员帮助理解扩频调制、干扰建模与抗干扰策略的实现思路。压缩包共3个文件包含2个m脚本与1个md说明文档体积约3KB其中脚本分别承担主流程仿真与误码率性能评估说明文档用于交代项目结构与运行方式。资源围绕伪随机码生成、信息信号扩频调制、窄带干扰模型、解扩与匹配滤波、BER与SNR性能分析等环节展开可帮助读者直观观察窄带干扰对通信链路的影响并对比不同抗干扰方法的误码表现。目前已有467人学习适合作为扩频通信课程实验或相关课题的入门参考便于在此基础上修改参数、扩展干扰类型并优化系统设计。1. 直扩通信里那根“窄带刺”为什么 DSSS 抗干扰仿真值得你亲手跑一遍做无线通信仿真的同行大多有过这种体验链路在纯高斯信道下误码率曲线漂亮得像教科书一旦在频谱里塞进一个窄带干扰源接收端星座图立刻散成一团。直接序列扩频DSSS被反复提及的核心价值就是拿一条伪随机码把窄带信号的能量摊到宽频带上让落在某个频点的窄带干扰只污染一小部分频谱解扩时再把这部分损伤摊薄。这套逻辑听起来顺理成章但真正动手在 MATLAB 里搭一遍你会发现扩频增益、处理增益、干扰容限这几个词之间的关系和论文里写的并不完全是一回事。这篇笔记面向的是已经懂一点通信原理、想在 MATLAB 里把 DSSS 抗窄带干扰这条链路跑通的人。我会从信号模型讲起把扩频、加窄带干扰、解扩、判决这条链路一步步搭出来给出可复现的代码和参数再重点讲几个我踩过的坑——尤其是窄带干扰的频率位置、带宽、功率怎么设以及为什么你的误码率曲线有时候会“玄学”地不降反升。目标很明确读完你能自己搭一套能出图的仿真并且知道每个参数动了之后曲线会往哪走。2. 把 DSSS 抗窄带干扰的信号模型拆开从扩频到解扩的完整链路2.1 为什么窄带干扰在解扩后会被“摊薄”先把这个反直觉的结论说清楚。假设发送端每个信息比特用长度为 N 的伪随机序列PN 码扩展码片速率是比特速率的 N 倍。一个窄带干扰如果带宽远小于扩频带宽它在时域上近似是一个单频正弦或窄带调制信号。接收端做解扩本质是把接收信号再乘一遍本地同步的 PN 码然后在一个比特周期内积分。关键在这里有用信号乘上本地 PN 码后重新变回窄带积分时能量相干累加而窄带干扰乘上 PN 码后被“二次扩频”能量被摊到整个扩频带宽上积分时只有落在信息带宽内的那一小部分能量被累加。这就是处理增益的来源数值上等于扩频带宽与信息带宽之比用码长表示就是 10·log10(N) dB。N 越大干扰被摊得越薄但代价是占用带宽和同步复杂度上升。需要提醒的是这个“摊薄”只在干扰带宽确实远小于扩频带宽时成立。如果干扰带宽接近甚至超过信息带宽处理增益带来的好处会迅速缩水这也是后面避坑章节要重点讲的。2.2 最小可复现链路的模块划分我一般把这条链路拆成五个模块每个模块对应一段独立可测的代码方便单独调模块作用关键参数信源生成随机比特比特数、帧长扩频比特与 PN 码相乘码长 N、码片速率信道叠加窄带干扰与噪声干扰频率、带宽、干信比解扩本地码相乘并积分同步位置、积分区间判决抽样判决算误码率判决门限这样拆的好处是当误码率曲线不对时你可以逐模块打印中间信号的频谱快速定位是扩频没做对、干扰加错了位置还是解扩同步偏了。2.3 用 MATLAB 搭出扩频与解扩的最小代码下面这段是核心链路我把它写成函数形式方便改参数反复跑。注意 PN 码用 m 序列生成保证自相关特性。function [ber, tx_sig, rx_sig] dsss_link(N, num_bits, JSR, f_int, fs, snr_db) % N : 扩频码长处理增益 10*log10(N) dB % num_bits : 信息比特数 % JSR : 干信比 (dB)窄带干扰功率 / 信号功率 % f_int : 窄带干扰中心频率 (Hz) % fs : 采样率 (Hz) % snr_db : 信噪比 (dB) % ---- 1. 信源双极性比特 ---- bits randi([0 1], 1, num_bits); symbols 2*bits - 1; % 映射到 1 / -1 % ---- 2. 生成 m 序列作为 PN 码 ---- pn m_sequence(N); % 长度 N 的 1/-1 序列 pn pn(:).; % ---- 3. 扩频每个比特重复整段 PN 码 ---- tx_sig zeros(1, num_bits * N); for k 1:num_bits tx_sig((k-1)*N1 : k*N) symbols(k) * pn; end % ---- 4. 上采样到采样率模拟连续波形 ---- sps fs / N; % 每码片采样点数 tx_up rectpulse(tx_sig, sps); % ---- 5. 信道加窄带干扰 高斯白噪声 ---- t (0:length(tx_up)-1) / fs; sig_power mean(tx_up.^2); % 窄带干扰用单频正弦近似带宽极窄 jam_power sig_power * 10^(JSR/10); jam sqrt(2*jam_power) * cos(2*pi*f_int*t); % 高斯噪声按 SNR 加 noise_power sig_power / 10^(snr_db/10); noise sqrt(noise_power) * randn(size(tx_up)); rx_up tx_up jam noise; % ---- 6. 解扩下采样回码片率乘本地码按比特积分 ---- rx_chip downsample(rx_up, sps); rx_sig zeros(1, num_bits); for k 1:num_bits seg rx_chip((k-1)*N1 : k*N); rx_sig(k) sum(seg .* pn); % 相干积分 end % ---- 7. 判决与误码率 ---- decided rx_sig 0; ber sum(decided ~ bits) / num_bits; end function pn m_sequence(N) % 生成长度 N 的 m 序列N 取 2^m - 1 m log2(N1); regs [1 zeros(1, m-1)]; taps [m 1]; % 本原多项式抽头按需替换 pn zeros(1, N); for i 1:N pn(i) regs(end); fb mod(sum(regs(taps)), 2); regs [fb regs(1:end-1)]; end pn 2*pn - 1; % 映射到 1/-1 end逻辑说明信源用双极性映射是为了让扩频乘法直接对应 BPSK 调制省掉额外的载波搬移。扩频段把每个比特乘以整段 PN 码这是最直观的时域扩频写法。信道段把窄带干扰建模成单频正弦这是最“毒”的一种干扰——能量全部集中在一个频点对扩频系统是最坏情况之一。解扩段先下采样回码片率再乘本地码积分等价于匹配滤波。参数说明N决定处理增益常用 31、63、127JSR是干信比仿真里从 0 dB 一路加到 20 dB 看曲线变化f_int是干扰频率建议先取 0直流附近和取扩频带宽中心两个位置对比fs要满足采样定理一般取码片速率的 8 到 16 倍。2.4 跑出第一条误码率曲线把上面的函数包一层循环扫 JSR就能得到抗干扰性能曲线N 63; num_bits 1e5; fs 1e6; snr_db 10; jsr_list 0:2:20; ber_list zeros(size(jsr_list)); for i 1:length(jsr_list) ber_list(i) dsss_link(N, num_bits, jsr_list(i), 0, fs, snr_db); end semilogy(jsr_list, ber_list, -o); xlabel(干信比 JSR (dB)); ylabel(误码率 BER); grid on;跑完你会看到一条随 JSR 上升而缓慢抬升的曲线而不是像无扩频系统那样迅速崩掉。这条曲线的斜率就是处理增益在起作用。如果曲线在某个 JSR 之后突然陡升多半是干扰功率已经大到让积分器输出饱和或判决门限失效这时候要检查你的信号功率归一化是不是做对了。3. 窄带干扰的参数怎么设频率、带宽、功率三个旋钮3.1 干扰频率落在哪结果差别很大很多人第一次做这个仿真随手把干扰频率设成 0发现误码率几乎不涨于是得出结论“DSSS 抗干扰很强”。这个结论是片面的。干扰频率落在直流附近时解扩后乘 PN 码低频分量被搬到高频积分时被抑制得最狠。真正麻烦的是干扰频率落在扩频信号频谱的某个旁瓣或主瓣边缘这时候部分能量会落在积分带宽内。我一般会扫一遍干扰频率画出“干扰频率—误码率”的二维图找到最坏干扰频点。做法是把f_int从 0 扫到码片速率步进取码片速率的 1/50 左右N 63; fs 1e6; chip_rate fs / 8; % 假设每码片 8 个采样点 f_int_list 0 : chip_rate/50 : chip_rate; ber_freq zeros(size(f_int_list)); for i 1:length(f_int_list) ber_freq(i) dsss_link(N, 2e4, 15, f_int_list(i), fs, 10); end plot(f_int_list/chip_rate, ber_freq); xlabel(归一化干扰频率 f_{int}/R_c); ylabel(误码率 BER); grid on;这张图能帮你判断你的系统对哪个频段的窄带干扰最敏感。工程上做抗干扰设计时这个最坏频点就是你要重点防护的位置。3.2 干扰带宽从“单频”放宽后会怎样单频正弦是最理想的窄带干扰实际干扰往往有一定带宽。把干扰从单频改成带限噪声只需要把正弦换成带通滤波后的高斯噪声% 带限窄带干扰中心 f_int带宽 B_jam B_jam chip_rate / 20; % 干扰带宽远小于扩频带宽 [b, a] butter(4, [f_int - B_jam/2, f_int B_jam/2]/(fs/2), bandpass); jam filter(b, a, randn(size(tx_up))); jam jam / std(jam) * sqrt(jam_power); % 归一化到目标功率这里有个容易翻车的点butter的归一化频率必须除以fs/2而且当f_int - B_jam/2接近 0 或f_int B_jam/2接近fs/2时滤波器设计会不稳定。我一般会把干扰中心频率限制在扩频带宽的 20% 到 80% 之间避开边界。带宽放宽后你会发现误码率对干扰频率的敏感度下降了但整体误码率抬升了。原因是带限干扰的能量分布更宽解扩后落在积分带宽内的比例更高。这解释了为什么实际对抗中宽带噪声干扰比单频干扰更难对付。3.3 干信比与处理增益的换算关系处理增益 Gp 10·log10(N) dB这个值决定了系统能容忍多大的干信比。理论上当 JSR 小于 Gp 时解扩后干扰功率被压到信号功率以下误码率接近无干扰情况当 JSR 超过 Gp误码率开始明显恶化。但仿真里你会发现这个“拐点”并不锐利原因是噪声也在起作用而且积分器的有限字长和采样率都会影响实际抑制效果。我一般会同时画三条曲线无干扰、JSR Gp - 5 dB、JSR Gp 5 dB对比看拐点位置是否符合预期。如果 JSR Gp - 5 dB 时误码率还很高说明你的解扩同步或功率归一化有问题。提示干信比的定义要和信号功率的统计方式一致。上面代码里用mean(tx_up.^2)估计信号功率如果你的信号有脉冲成形或加窗这个估计会偏建议用长时平均。4. 避坑与排查DSSS 抗窄带干扰仿真里最容易翻车的五件事4.1 误码率曲线不降反升现象加大扩频码长 N误码率反而比小 N 时更高。原因最常见的是 PN 码生成有误码的自相关性差导致解扩时有用信号没有相干累加。另一个可能是采样率没跟着 N 调整码片率变了但fs没变导致每码片采样点数不是整数下采样时相位错位。解决先单独验证 PN 码的自相关xcorr(pn)应该在零延迟处出现尖峰、其他位置接近零。再检查fs / N是否为整数不是整数就把fs调成 N 的整数倍。4.2 干扰频率设成 0 时几乎无影响误以为仿真成功现象JSR 加到 20 dB误码率还是接近零。原因干扰落在直流附近解扩时被 PN 码搬到高频积分器把它抑制掉了。这不代表系统抗干扰强只是你选了一个最有利的干扰频点。解决按 3.1 节扫一遍干扰频率找到最坏频点再评估性能。工程评估必须用最坏情况不能用最有利情况。4.3 带限干扰滤波器设计报错或结果异常现象butter报错或者滤波后干扰功率和设定值差很多。原因归一化频率越界或者滤波器阶数太高导致数值不稳定。另外filter的瞬态响应会让前几个样本功率异常影响功率归一化。解决把干扰中心频率限制在(0.1, 0.9) * fs/2范围内阶数降到 2 到 4 阶。功率归一化前先丢掉前 100 个样本用稳态段估计标准差。4.4 解扩同步偏移导致性能骤降现象误码率比理论值高一个数量级但频谱看起来正常。原因本地 PN 码和接收信号的码相位没对齐哪怕偏一个码片相干积分就会大幅损失。解决在解扩前加一个滑动相关同步扫一遍码相位取相关峰最大的位置作为积分起点。仿真里可以先用已知的发送码相位做理想同步确认链路无误后再加同步模块。4.5 蒙特卡洛次数不够导致曲线抖动现象误码率曲线在高 JSR 段上下跳重复跑结果不一致。原因高 JSR 时误码率本身很低num_bits不够统计涨落大。解决低误码率段把num_bits加到 1e6 以上或者用重要性采样。我一般会保证每个误码率点至少统计到 100 个错误比特否则曲线不可信。5. 进阶技巧用处理增益反推干扰容限并验证你的仿真边界5.1 从误码率曲线反推干扰容限干扰容限的定义是在保证一定误码率的前提下系统能承受的最大干信比。有了前面的仿真链路你可以固定一个目标误码率比如 1e-3扫 JSR 找到对应的临界值再和理论处理增益对比。target_ber 1e-3; N_list [31, 63, 127]; for i 1:length(N_list) N N_list(i); jsr 0; while true ber dsss_link(N, 1e5, jsr, chip_rate/4, 1e6, 10); if ber target_ber fprintf(N%d, 干扰容限约 %d dB, 理论处理增益 %.1f dB\n, ... N, jsr, 10*log10(N)); break; end jsr jsr 1; end end跑出来你会看到干扰容限通常比理论处理增益低几个 dB差值来自噪声、积分损失和判决门限。这个差值就是你的仿真链路“效率”的度量。如果差值超过 5 dB说明链路里有明显的实现损失值得回头查同步和功率归一化。5.2 用频谱图验证“二次扩频”是否真的发生理论说窄带干扰解扩后被摊开这个结论可以直接在频谱上看。把解扩前和解扩后的信号分别做 FFT对比干扰分量的带宽% 解扩前频谱 N_fft 4096; spec_before abs(fftshift(fft(rx_up(1:N_fft)))).^2; % 解扩后乘本地码再变换 rx_despread rx_up .* rectpulse(repmat(pn, 1, num_bits), sps); spec_after abs(fftshift(fft(rx_despread(1:N_fft)))).^2; f (-N_fft/2 : N_fft/2-1) * fs / N_fft; plot(f, 10*log10(spec_before), b, f, 10*log10(spec_after), r); legend(解扩前, 解扩后); xlabel(频率 (Hz)); ylabel(功率谱 (dB)); grid on;如果解扩后干扰峰明显展宽、峰值下降说明二次扩频生效了。如果峰值没怎么变检查本地码是否和发送码对齐——码不对齐时乘上去的不是同一个 PN 序列扩频效果就出不来。5.3 一个我常犯的错误早期做这个仿真我总想把num_bits设小一点跑得快结果高 JSR 段曲线全是噪声白白浪费一下午调参数。后来养成习惯先用小num_bits快速扫参数范围确定大致趋势后再用大num_bits在关键点上精算。另外每次改完参数一定先看时域波形和频谱别直接看误码率数字——波形不对数字再好看也是假的。希望帮到你。本文还有配套的精品资源点击获取