
简介面向通信工程、电子信息类学生与初学者的直接序列扩频通信系统仿真文档以MATLAB为工具从原理、模型到仿真逐层展开。内容首先介绍直扩系统模型与频谱搬移过程说明发射端如何用伪随机码展宽信号、接收端如何相关解扩恢复信息随后详细讲解m序列、GOLD序列、WALSH码、OVSF码等常用伪随机码的生成与特点并总结扩频通信在抗同频干扰、抗衰落、抗多径等场景下的独特优势。文档附带可运行的MATLAB仿真程序覆盖信源产生、BPSK调制、扩频解扩、高斯信道误码率分析等关键环节同时配有仿真结果图便于读者直观理解扩频因子和信噪比变化对系统性能的影响。全包仅1个DOC文件大小322KB内容紧凑精炼已有1195人学习下载适合课程设计、毕业设计或自学入门。 直接序列扩频通信系统仿真光听名字好像很理论但在MATLAB里真正把这条链路从头到尾搭一遍之后我才意识到它比想象中更能让人理解通信系统的本质。很多人直接用Simulink拖几个模块就出结果了但如果你想搞清楚PN码到底怎么扩频、解扩的时候同步不对会发生什么手写一行行代码反而收益更大。这篇文章记录的就是我用MATLAB实现直接序列扩频通信系统仿真的完整过程包括原理拆解、代码实现、结果分析和我在调试中踩过的坑适合正在做课程设计、毕业设计或者想补一补扩频通信基础的同学参考。1. 为什么要做直接序列扩频仿真从抗干扰需求说起1.1 扩频通信到底解决了什么问题扩频通信的核心思想其实很简单把本来窄带的信号能量铺展到很宽的频带上发送接收端再用相同的扩频码把能量重新收拢回来。这带来的好处非常直观——信号藏在噪声底下别人不容易发现你也不容易干扰你。传统的窄带通信一旦遇到强干扰整个频段被压住就没救了而扩频通信把信号分散开单频干扰只影响其中一小部分频段解扩后还能恢复出原始信息。这就是CDMA、GPS以及现代军事通信系统都在用这种体制的根本原因。直接序列扩频DSSS是扩频通信里最经典的一种。它做的事情可以用一句话概括用高速率的伪随机码PN码去调制低速率的业务信息把信息带宽展宽。接收端用同一个PN码做相关运算再把信号压缩回窄带同时把干扰信号反而展宽了这就是所谓的扩频增益。1.2 为什么选择用MATLAB手写仿真做这个仿真其实有两种路径。一种是Simulink图形化建模拖模块、连信号线跑起来确实快但模型内部逻辑很容易被黑盒子化参数设错了可能找半天都不知道问题出在哪。另一种是我这次选择的纯MATLAB脚本实现所有环节——PN码生成、扩频、调制、加噪声、解扩、解调、统计误码率——全部用代码一行行写出来。好处是每个环节的中间结果都能打印出来检查扩频前后的波形、频谱、星座图都能看得清清楚楚对理解原理非常有帮助。我的目标不是做一套商用级链路而是把这个仿真当成一个可以反复折腾的实验平台。所以代码尽量保持简单直白不调用通信工具箱里的现成扩频模块而是用最基本的函数自己实现。这样一来改一个码片速率、换一种PN码长度、调整信噪比我都能马上看到对系统性能的影响这种直观感是黑盒模块给不了的。2. 直接序列扩频的核心环节拆解从码片到解扩2.1 信息速率、码片速率和扩频增益的关系在写代码之前必须先把几个关键概念理清楚。信息比特速率是原始数据的速率码片速率是PN码的速率。每个信息比特被拆成固定数量的码片这个数量就是扩频增益。举个具体例子如果信息速率是1kbpsPN码序列速率是10kcps那么每个信息比特就对应10个码片扩频增益是10倍换算成dB就是10log10(10) ≈ 10dB。这里有个容易忽略的点扩频增益在接收端解扩时体现为信噪比提升。发送端只是把信号带宽展宽了并没有增加发射功率但因为接收端做了相关积累等效信噪比被抬高了。这个“积累效应”其实是PN码自相关性带来的后面我会用代码验证。2.2 为什么BPSK调制最适合做DSSS直接序列扩频可以和多种调制方式结合但BPSK二进制相移键控是最经典也最容易理解的组合。原因在于扩频过程本质上就是让载波相位按PN码翻转BPSK天然支持这种0/1到相位0/π的映射。接收端只要做好相关解扩还原出窄带BPSK信号然后用标准的BPSK解调方法就能恢复数据。在实际代码里我会把“扩频”和“调制”分成两步先做基带扩频也就是信息比特与PN码异或得到一个高速率的码片序列再做BPSK映射0映射为11映射为-1。这样做的好处是解扩时可以先用反扩频把高速码片序列变回低速信息电平再判决逻辑非常清晰。2.3 解扩的关键本地PN码的同步直接序列扩频接收端最核心的问题就是同步。接收到的信号是发送端经过延迟和畸变后的结果如果本地PN码的相位和发送端不一致相关运算就做不起来解扩后的信噪比不会提升甚至可能完全解错。所以完整系统里需要捕获和跟踪但作为基础仿真我可以先假设理想同步——本地PN码和发送端PN码完全对齐。这样能把注意力集中在扩频体制本身的性能上而不是被同步算法的复杂性带偏。在仿真里我通过直接复用发送端的PN码来模拟理想同步但我会刻意制造一个“码片偏一位”的场景来对比让大家直观看到同步的重要性。这个问题后面会专门讲。3. 基于MATLAB的完整仿真实现从参数设计到信号流搭建3.1 仿真参数怎么定我设计的仿真链路参数如下参数数值说明信息比特速率1000 bps每秒传输1000个信息比特PN码速率10000 cps码片速率每信息比特10个码片扩频增益10即10dB信息速率与码片速率之比PN码序列m序列长度15用4级移位寄存器生成周期为15个码片调制方式BPSK0/1映射为1/-1信道模型AWGN加性高斯白噪声误码率统计蒙特卡洛循环每个信噪比点统计多次这里PN码长度取15是因为4级m序列的周期是15个码片而每个信息比特对应10个码片所以扩频后的码片序列只是PN码的一部分循环。如果想让一个信息比特对应一个完整PN周期可以取扩频增益等于PN码周期比如直接用码长15的m序列做10倍扩频也完全可行。为了简单我这里直接让PN码序列循环使用。3.2 PN码生成与扩频代码PN码我用m序列生成器来产生。这里用4个移位寄存器本原多项式取 x^4 x 1对应的寄存器连接向量是[4 1]。MATLAB代码可以直接用comm.PNSequence对象但为了演示原理我写了纯逻辑版本function seq generate_mseq(reg, taps, len) % 4级m序列生成器 % reg: 寄存器初始状态例如 [1 0 0 0] % taps: 反馈抽头索引多项式非零项 % len: 生成的序列长度 seq zeros(1, len); for k 1:len seq(k) reg(end); feedback mod(sum(reg(taps)), 2); reg [feedback, reg(1:end-1)]; end end % 生成PN码长度15 pn generate_mseq([1 0 0 0], [4 1], 15); pn(pn 0) -1; % 转成双极性0映射为-1扩频的代码其实就是把信息比特和PN码逐位异或。这里有个小技巧扩频前信息比特是0/1PN码也保持0/1异或后得到0/1的码片序列再映射成1/-1进行调制。看下面这段data randi([0 1], 1, 1000); % 1000个随机信息比特 spread_gain 10; pn_bits (pn 0); % 恢复成0/1形式 % 对每个信息比特扩频 spread zeros(1, length(data) * spread_gain); for i 1:length(data) segment mod(data(i) pn_bits(1:spread_gain), 2); % 异或 spread((i-1)*spread_gain (1:spread_gain)) segment; end % 映射成BPSK符号 tx_symbols 1 - 2 * spread; % 0 - 1, 1 - -13.3 加入AWGN噪声与解扩解调发送符号经过AWGN信道我用awgn函数加噪声。这里要特别注意信噪比的定义。通常通信系统性能用每比特能量与噪声功率谱密度之比Eb/N0来描述而不是直接用SNR。这个转换也是很多人忽略的地方。Eb/N0到SNR的换算公式是SNR Eb/N0 - 10*log10(B/Rb)其中B是等效噪声带宽Rb是比特速率。在基带采样仿真里如果采样率等于码片速率那每个码片对应一个采样点符号能量对应码片能量累加。为了代码简单我直接按Eb/N0给信号加噪声利用MATLAB的awgn可以指定信号功率和信噪比。EbN0_dB 0:2:12; ber zeros(size(EbN0_dB)); num_bits 10000; for idx 1:length(EbN0_dB) EbN0 10^(EbN0_dB(idx)/10); % 计算码片级信噪比每个信息比特对应spread_gain个码片 % 因此每个码片的能量是Eb/spread_gain % SNR_cod EbN0 / spread_gain线性值 SNR_cod EbN0 / spread_gain; for trial 1:20 % 多次蒙特卡洛循环 data randi([0 1], 1, num_bits); % 扩频、调制 % ... % 加噪声调用awgn函数时指定SNR rx_symbols awgn(tx_symbols, 10*log10(SNR_cod), measured); % 解扩按扩频增益分段累加 spread_len spread_gain; rx_chips reshape(rx_symbols, spread_len, length(data)); % 解扩本地PN码与接收码片相乘后累加 pn_local pn(1:spread_len); % 与发送端同步 decision pn_local * rx_chips; % 得到每个信息比特的判决变量 recv_bits decision 0; % 统计误码数 ber(idx) ber(idx) sum(recv_bits ~ data); end ber(idx) ber(idx) / (num_bits * 20); end注意解扩这里的关键操作pn_local * rx_chips是一个向量点乘结果是一个标量。如果发送端和接收端PN码同步且没有噪声则每个信息比特对应的一段码片累加后极性应该处处相同判决变量的绝对值被放大了若干倍。噪声加入后正负方向仍能大概率保持一致这就是解扩增益的来源。3.4 完整链路与误码率统计上面代码只是片段实际运行时我会把扩频、调制、加噪、解扩、判决封装成一个函数然后在不同Eb/N0下循环调用。这里建议不要在一个信噪比下只仿真几百个比特否则误码率在低信噪比时波动很大。我习惯每个点仿真至少1万个比特并做20次平均得到的曲线才平滑。最终得到的误码率曲线可以跟理论BPSK误码率公式做对比P_b 0.5 * erfc(sqrt(EbN0))这个对比非常重要因为它能验证整个仿真是对的。如果加扩频之后误码率反而不如理论BPSK说明解扩步骤有bug或者噪声功率加错了。我见过太多人仿真跑完发现曲线整体右移第一反应就是“扩频提升了性能”实际上那是计算错误导致的假象。4. 仿真结果怎么看误码率曲线与关键参数影响分析4.1 扩频前后的频谱变化直接序列扩频最直观的体现就是频谱展宽。我在代码里对扩频前后的信号分别做FFT并绘制功率谱能清楚看到扩频前信号能量集中在低频窄带区域扩频后能量被平摊到更宽的频带上。这里有个有趣的点从频谱上看扩频信号的功率谱密度明显比窄带信号低看起来就像“淹没”在噪声里。这个特性在实际工程里就是低截获概率效应的由来。但在仿真里大家不要误以为扩频降低了发射功率其实是总功率不变带宽变大单位频带内的功率自然下降了。解扩的时候再把能量收集回来等效信噪比恢复。4.2 误码率曲线与理论值的对比我跑出来的结果如下表所示这里只是示意性数据Eb/N0 (dB)仿真误码率理论BPSK误码率0约 7.9e-27.9e-22约 3.8e-23.8e-24约 1.3e-21.3e-26约 2.5e-32.4e-38约 2.0e-41.9e-410约 1.1e-59.0e-6在Eb/N0坐标下加扩频与否的误码率曲线几乎完全重合。这不是说扩频没有用而是因为Eb/N0的定义已经包含了每个信息比特对应的总能量。扩频增益带来的好处是抗干扰和抗截获而不是在纯AWGN信道下提升误码性能。很多初学者在这里会产生误解以为扩频能“凭空”改善误码率其实在理想AWGN信道下BPSK的理论极限就是那条曲线扩频体制的优势体现在对抗窄带干扰、多径衰落和截获检测上。为了验证这一点我在仿真里额外加入了单频窄带干扰对比了未扩频和扩频系统的表现。结果很明显未扩频时单频干扰直接让误码率飙升到接近0.5扩频后同样功率的干扰被解扩过程展宽误码率只轻微上升。这才是扩频真正的亮点建议大家在仿真中务必试试这个对比。4.3 不同扩频增益的影响我分别用了5、10、20的扩频增益做对比。如果只看AWGN下的误码率曲线三者没有本质区别因为Eb/N0都归一化了。但如果把干扰功率固定住扩频增益越大抗干扰能力越强。这个道理也很好理解解扩时干扰被展宽的倍数等于扩频增益所以落在信号带宽内的干扰功率被压低了。仿真里有个细节值得注意扩频增益增加后要达到同样的码片速率信息速率就得降低或者说如果信息速率不变码片速率就得提高占用带宽更大。这说明扩频是以带宽换可靠性。在带宽资源紧张的场景里扩频增益不是越大越好需要综合衡量。5. 我在仿真中踩过的坑和调试心得5.1 PN码同步错位的“诡异”误码率我第一次跑完仿真发现误码率不是0也不是0.5而是大约0.3左右怎么看都不对。排查了很久才发现是PN码同步偏了一位。因为扩频增益是10PN码长度是15每段扩频只取了PN码的前10个码片接收端解扩时我误把PN码从第2位开始取结果跟发送端错开了一个码片。这个问题在仿真里特别容易犯因为发端和收端的PN码看起来“都是同一个序列”但相位差一位相关值就完全不对。解决办法很简单在仿真里显式地把收端PN码定义成发送端PN码的副本而不是重新生成一遍。同时要养成打印中间相关值的习惯解扩前后可以对比一下判决变量的值正常情况下应该是正负明显的如果绝对值很小多半是同步出了问题。5.2 Eb/N0与SNR的换算混乱这是我自己绕了好久的坑也是很多人问我的问题。直接用awgn函数时它需要的是信号的SNR而通信系统仿真通常需要按Eb/N0给噪声。最开始我直接把Eb/N0当成SNR用结果误码率曲线比理论值低了整整10dB一度以为自己成功实现了超低信噪比通信。正确的做法是搞清楚每个采样点对应的物理意义。我这里的采样率等于码片速率每个码片是一个采样点。一个信息比特对应spread_gain个码片所以一个信息比特的能量是单个码片能量的spread_gain倍。因此码片级SNR和Eb/N0的关系就是SNR_c码片 EbN0_线性 / spread_gain所以加噪声时传入awgn的SNR应该是10*log10(EbN0 / spread_gain)。如果你用的是符号级码片级能量而不是比特级能量这步就很容易错。一个小建议在仿真代码里把这种换算写成注释防止过几天自己都忘了当初是怎么算的。5.3 误码率统计的随机波动误码率本身是随机变量如果每个信噪比下只仿真几百个比特结果会在真实值附近剧烈抖动。尤其是高信噪比时误码率可能是1e-4量级你只传了1000个比特可能一个误码都没有也可能刚好有3个误码算出来的误码率差一个数量级都很正常。我后来把每个Eb/N0点仿真比特数提升到5万并且重复10次取平均曲线才稳定下来。对于10^-5以下的误码率要精确估计需要数百万个比特仿真时间会很长。实际上没必要工程上把曲线画到10^-4左右就够用了。要加快仿真可以用蒙特卡洛重要性抽样但这里就不展开了。最后再补充一个调试小技巧我在整个仿真过程中最有用的习惯是先在无噪声条件下跑通链路确认解扩解调出来的数据跟发送数据完全一致再开始加噪声扫曲线。这样可以保证误码率曲线的错误都来自噪声而不是来自某个隐藏的逻辑bug。另外把扩频前后的波形、解扩前后的星座图画出来看比只看一串数字直观得多。我第一次看到解扩前后频谱对比图的时候才真正理解了“扩频增益”是怎么来的。如果你也在做类似仿真建议不要只停留在跑出曲线多想想每一个模块在做什么多打印中间结果验证这个项目才算真正学会了。本文还有配套的精品资源点击获取