简介:这是一份基于Simulink的直接序列扩频(DSSS)通信仿真资源,面向通信工程、电子信息类学习者与研究人员,旨在帮助理解扩频通信原理、系统建模及抗干扰性能评估。压缩包内共13个文件,包含Simulink模型文件(.slx/.mdl)、MATLAB脚本(.m)以及数据文件(.mat),并附有说明文档,基本覆盖从信源生成、扩频调制、信道加噪到解扩接收的完整仿真链路。资源包整体约144KB,轻量易用,适合在MATLAB/Simulink环境中直接运行与二次修改。已有759人学习下载。通过该资源,学习者可以掌握DSSS系统中伪随机码生成、BPSK/QAM调制、10dB信噪比条件下信道建模、时域与频域波形分析等关键知识点,并能结合文档理解解扩同步与抗干扰机制,进而对系统性能进行直观评估和参数优化。
1. 直接序列扩频通信仿真:为什么每个通信工程师都该在 Simulink 里搭一套
直接序列扩频(DSSS)通信仿真,在 Simulink 里做的价值,很快就超过你预期。我最早只是为了验证一段抗干扰波形,后来实际帮人排查同步问题,才发现把收发链路完整搭出来之后,PN 码相位、码片速率、频偏这些参数,才第一次从公式变成了看得见的波形。直接序列扩频的核心玩法,是把窄带信号用高速伪随机码展宽到很宽的频带上,接收端再用同一个码把能量攒回来,换来抗干扰、抗截获和码分多址能力。Simulink 做这件事的好处是直观:扩频前后的功率谱、相关峰、误码率,点开示波器就能看到;调参数也快,不用反复编译 C 程序。这篇笔记适合三类人:通信方向学生做课设、算法工程师验证扩频波形、系统工程师做方案预研。我会按发射机、接收机、同步、排错、验证的顺序,把能复现的细节都写出来。
2. 发射机建模:PN 码生成与 BPSK 扩频调制,把频谱展宽 1000 倍
2.1 扩频处理增益哪里来:码片速率、信息速率与带宽的关系
直接序列扩频的本质,是把一个低速信息序列和一个高速伪随机序列做模二加,也就是异或。信息码率是 Rb,PN 码率是 Rc,两者比值 SF = Rc / Rb 就是扩频因子。扩频后信号带宽由码片速率决定,大约是 Rc 量级,相比原始窄带信号展宽了 SF 倍。这个展宽不是白做的,接收端重新相乘后才能把信号能量收回来,噪声却不会同步聚拢,于是信噪比提升,理论上的处理增益 Gp = 10 * log10(SF) dB。
一个典型参数组合:信息速率 Rb = 10 kbps,码片速率 Rc = 10 Mcps,扩频因子 SF = 1000,处理增益 30 dB。在 Simulink 里搭发射机之前,先把这些参数放到工作区,模型里所有模块都引用变量,后面改参数只需要动一处。常见做法是用一个 MATLAB 初始化脚本,建模型前先跑一遍。这个脚本同时也是你的实验记录,哪组参数得到什么波形,回头能查。
2.2 Simulink 发射机搭建:PN 码生成、异或扩频与星座映射
发射机的 Simulink 链路从信源开始,我用 Bernoulli Binary Generator 产生随机 0/1 信息序列,概率 0.5,采样时间 1/Rb。PN 码用 Communications Toolbox 里的 PN Sequence Generator,也可以自己写 m 序列生成器,但自带模块更稳。PN Sequence Generator 的关键参数是 Generator polynomial、Initial states 和 Sample time。我习惯把 Sample time 设为 1/Rc,让一个仿真步产出一个码片;多项式选常用的 m 序列本原多项式,比如 7 级寄存器的 1 + x^3 + x^7,生成 127 位码。这样扩频码长度和扩频因子最好能匹配,或者码长是信息码周期的整数倍,后面捕获会省很多事。
扩频这个动作在 Simulink 里用一个 Logical Operator(XOR)模块完成:信息序列和 PN 码逐位异或。异或输出仍然是 0/1,不能直接上信道,需要映射成双极性电平。用 Bias 配合 Gain,把 0 映射到 -1、1 映射到 +1,也可以用 Unipolar to Bipolar Converter 模块,一步到位。映射后的信号就是基带扩频码片流,再乘上一个载波就得到发射信号。这里我建议先不急着加载波,在基带把扩频码片流摸清楚,再上变频,排查问题容易得多。
% 直接序列扩频仿真参数初始化 Rb = 10e3; % 信息速率 10 kbps Rc = 10e6; % 码片速率 10 Mcps SF = Rc / Rb; % 扩频因子 1000 fs = 4 * Rc; % 仿真采样率,取码片速率的 4 倍 Ts = 1 / fs; % 固定步长 samplesPerChip = fs / Rc; % 每码片 4 个采样点这段代码里的 fs 为什么取 4 倍码片速率,说明一下:奈奎斯特最小采样率是 2 倍信号带宽,但仿真里要观察码片沿、做匹配滤波、看相关峰,2 倍采样会让波形很糙。4 倍是我常用的折中:频谱能看到主瓣和第一旁瓣,相关峰也平滑,仿真速度还能接受。samplesPerChip = 4 意味着延迟模块的最小可调步进是 1/4 码片,这个精度足够覆盖大多数同步误差分析。采样率再往上调,比如 8 倍,仿真时间直接翻倍,收益有限;低于 2 倍则会混叠,相关峰出现假峰。
2.3 脉冲成型与频谱观测:让功率谱看起来像直接序列扩频信号
扩频码片流直接上信道,频谱是 sinc 形状,主瓣零点在码片速率整数倍处,旁瓣衰减慢,带外能量高。实际系统里会加升余弦或根升余弦脉冲成型滤波器,限制带宽。仿真里我建议至少加一个简单的矩形脉冲成型,也就是让每个码片保持一个码片周期的高电平,配合 Spectrum Analyzer 看功率谱。加成型滤波后,带宽会从无限展宽变成可控,DSP System Toolbox 里的 Raised Cosine Transmit Filter 是常用模块。
在 Simulink 里加 Spectrum Analyzer,直接把基带码片流拉进去看。扩频成功后,你会看到两个明显特征:第一,功率谱主瓣宽度接近码片速率 Rc,比原始信息速率宽了几百到上千倍;第二,频谱呈 sinc 形状,旁瓣间隔均匀。如果看到频谱还是一片窄的谱线,说明扩频没生效,多半是异或的输入采样率不一致,信息序列和 PN 码的采样时间没有按 Rb 和 Rc 分开设置。PN Sequence Generator 输出的码片宽度要和信息码元宽度有个明显的速率差,否则功率谱看起来就是信息码的频谱,后面处理增益自然不对。
发射机这一段还有个小技巧:把扩频后的码片流和扩频前的信息序列同时接到两个 Scope 里对比,你能直观看到低速元被高速码片切成一段一段。这个对比波形我每次都会截图留档,因为它是判断 PN 码是否工作正常的第一个线索。如果异或后波形没有出现明显的切碎效果,先查采样时间,再查多项式配置,这是发射机最常见的翻车点。
3. 接收机与码同步:相关解扩、延迟锁定环和最容易漏的频偏补偿
3.1 相关解扩的本质:本地 PN 码相位差一个码片会发生什么
接收端的核心操作是相关解扩:把收到的码片流乘上本地 PN 码,然后在一个信息码元周期内积分。m 序列的自相关特性决定了,只有当本地 PN 码和接收码相位完全对齐时,乘积结果才全是 +1,积分值最大;相位差哪怕一个码片,积分值都会塌缩到接近零或变成一个小的旁瓣值。
这个特性意味着,直接序列扩频接收机第一步不是解调,而是先找到 PN 码相位。在 Simulink 里做这个实验成本很低:发射端加一个 Variable Time Delay 模块,把码片流延迟几个码片,接收端用本地 PN 码直接相乘,Scope 里看相关结果的变化。你会发现延迟从 0 逐渐增大到 1 个码片时,相关峰从最高点掉到几乎为零。这个现象理解了,后面所有同步算法都在解决同一件事:让本地 PN 码的相位误差收敛到远小于一个码片。
3.2 码同步捕获与跟踪:滑动相关与延迟锁定环的 Simulink 实现
码同步分成捕获和跟踪两步。捕获阶段先粗对齐 PN 码相位,常见做法是滑动相关:本地 PN 码按码片逐个步进,每步做一次相关,检测相关峰。在 Simulink 里搭滑动相关,可以把接收信号存成帧,再用 MATLAB Function 模块写搜索逻辑,也可以直接用 Communications Toolbox 里的 PN Acquisition 模块。我一般先用 MATLAB 脚本验证捕获算法,确认无误后再移植到模型里,这样区分算法问题和模型问题。
% 滑动相关捕获:搜索本地 PN 码相位 N = 127; % m 序列长度 pn = double(pnSeq); % 本地 PN 码,来自模型导出的变量 rx = RxSignal(1:N); % 取接收端前 N 个码片采样 corr = zeros(1, N); for shift = 0:N-1 pnShifted = circshift(pn, [0, shift]); product = rx .* pnShifted; corr(shift+1) = sum(product); % 每个候选相位的相关积分 end [peakVal, peakIdx] = max(corr); % 最大相关峰对应的相位 fprintf('峰值位置=%d, 峰值=%f\n', peakIdx, peakVal);这段代码背后的假设是接收码片和本地 PN 码采样率已经一致,所以在码片整数倍上搜索就够。实际操作中要注意:rx 里的采样点如果和 pn 采样数不匹配,比如每码片 4 个采样,那滑动步进应该是 1 个采样点而不是 1 个码片。我上面给的是按码片步进的简化版,适合先验证原理;实际捕获搜索步进要取采样点,精度 1/4 码片,搜索范围 N * 采样倍数,计算量会明显上升,这时候可以先粗搜再细搜两级捕获。
跟踪阶段用延迟锁定环(DLL)。DLL 结构不复杂:本地 PN 码产生早、即时、晚三路,分别超前和滞后半个码片,两路相关值之差作为误差信号,经过环路滤波器后调整本地码片时钟的相位。在 Simulink 里,早迟路的实现就是三个延迟副本乘以接收信号再积分,环路滤波器用 Discrete PID Controller 或自己搭一阶滤波器都行。环路带宽建议取码片速率的 0.01 到 0.1 倍,阻尼系数 0.707 附近起步。
DLL 的环路带宽是个关键参数,我给个经验值:码片速率 10 Mcps,环路带宽取 100 kHz,收敛时间大约在几万个码片周期量级。带宽太大,跟踪噪声高,解扩后的误码率会变差;带宽太小,环路跟不上频偏和相位变化。工程上一开始可以取 0.05 * Rc,看示波器里误差信号是否收敛到零附近,再逐步收窄。Simulink 里调试 DLL,最有用的是把误差信号和本地 PN 码相位同时接 Scope,一旦误差信号震荡不收敛,优先检查三路延迟是不是严格相差半个码片。
3.3 载波频偏补偿:解扩前必须处理的残余频偏
很多人搭完扩频解扩,发现误码率降不下去,问题不在 PN 码同步,而在载波频偏。直接序列扩频信号经过信道,接收端本地载波和发射载波存在频偏时,解扩后的信号会带有一个残余旋转因子,相当于把基带信号乘了一个低频复指数。频偏较小时还能容忍,频偏接近码片速率几分之一时,相关峰会被抹平,解扩失败。
Simulink 里模拟这个现象很容易:发射端上变频用 100 MHz 载波,接收端本地载波设 100.01 MHz,频偏 10 kHz,解扩后看星座图,会看到原本该聚在 ±1 的两个点旋转成一个圆环。解决思路分两步:先用锁相环或 Costas 环粗同步载波,把残余频偏压到码片速率的 1% 以内,再做解扩。仿真模型里我习惯把频偏设成一个可调变量 dFreq,从 0 开始逐步加大,观察解扩后信噪比随频偏的退化曲线,这个曲线在系统设计阶段很有用,能直接定出接收机对频偏的容忍范围。
还要注意一个顺序问题:码同步和载波同步谁先谁后。常见做法是先做码捕获,再做载波跟踪,因为扩频码没对齐时,相关结果被噪声淹没,载波环也拿不到可靠的误差信号。反过来,码片同步后信号变回窄带,载波环就很好锁定。这个顺序在 Simulink 里体现为模块的连接层次,别把载波同步环放在解扩之前,否则环路会失锁。
4. 直接扩频仿真的 5 个常见问题:现象、原因与排查
4.1 误码率曲线右移:仿真步长与码片速率的匹配问题
现象:扩频和解扩链路看起来都正常,功率谱也对,但误码率仿真曲线比理论 BPSK 曲线向右偏移 1 到 2 dB,怎么调信噪比都补不回来。
原因:仿真求解器用了变步长,或者步长设得比码片周期还大。码片波形被采样混叠,等效于引入额外噪声。这种问题最隐蔽的地方在于,误码率曲线形状是对的,只是平移,很容易被误判成是滤波器或同步损耗。
解决:打开 Solver 配置,把求解器改为固定步长 discrete,步长设为码片周期的 1/4 或更小,也就是前面脚本里的 Ts = 1 / (4 * Rc)。然后把所有的连续模块,比如 Integrator,替换成 Discrete-Time Integrator,采样时间继承或设为 Ts。这个改动做完,误码率曲线会和理论曲线对齐。我排查这类问题时的经验是,先看频谱再查步长,因为频谱混叠不一定看得出来,但误码率的整体平移一定是采样问题。
4.2 相关峰消失:PN 码延迟半个码片,捕获却搜不到
现象:接收端加了延迟模块,把码片流延迟了 0.5 个码片,滑动相关捕获结果却没有任何明显峰值,只在很小的数值上波动。
原因:滑动相关按码片整步进搜索时,接收码片和本地码片之间是分数码片延迟。每个采样点上的乘积可能正负混杂,积分值被抵消。m 序列的尖锐自相关特性在整数码片对齐时才成立,半码片误差意味着相关值已经掉到峰值的几分之一,如果信噪比不高,这个峰很容易被噪声淹没。
解决:捕获搜索步进改成 1 个采样点,而不是 1 个码片。在 MATLAB 脚本里把 circshift 的步进从 1 改为 1 / samplesPerChip,搜索次数从 N 变成 N * samplesPerChip。代价是计算量增加,但能保证找到整数采样点级别的对齐。进一步的做法是两级捕获:先按码片步进粗搜,确定大致区间,再在该区间内按采样点细搜。仿真里的分数延迟可以用 Variable Time Delay 模块模拟,但要注意模块在 Simulink 里默认按连续时间处理,设成离散模式后,延迟精度受限于采样周期,这是数学模型和离散仿真的固有边界,别在这上面死磕精确定。
4.3 处理增益折损:本地 PN 码同步后的剩余相位误差
现象:DLL 环路看起来收敛了,误差信号在零附近,但解扩后的信噪比理论上应该有 30 dB 增益,实测只有 24 dB 左右,差了几个 dB。
原因:环路收敛后仍有静差,本地 PN 码和接收码存在零点几码片的相位误差。这个误差让相关积分不再等于理想的 N * A,而是 N * A * (1 - ε),其中 ε 是归一化相位误差。30 dB 增益的系统,0.1 码片误差的损耗大约在 1 dB 量级,0.3 码片误差损耗会扩大到 3 dB 以上。
解决:改善环路跟踪精度。第一步收窄环路带宽,比如从 0.05 * Rc 降到 0.03 * Rc,静差会变小;第二步是改用早迟积分时间更长的判别器,或者在一阶环后面补一个二阶环来消除相位斜升。Simulink 里判断剩余误差,可以直接看解扩后信号的星座图:如果散点围绕 ±1 聚拢但半径偏大,就说明相关积分损耗还在。这里不要盲目增大环路增益,增益大了噪声也会变大,处理增益可能不升反降,需要来回试几组参数,记录下每组对应的解扩信噪比。
4.4 频谱没有展宽:扩频因子被设成了 1
现象:功率谱看起来和普通 BPSK 信号一样,带宽很窄,完全没有扩频信号那种铺满整个频段的感觉,处理增益计算出来接近 0 dB。
原因:信息速率和码片速率被设成了同一个值。比如 Bernoulli Generator 采样时间写 1/Rc,PN 码采样时间也写 1/Rc,两者速率相等,异或后只是把一个随机序列换成了另一个随机序列,带宽没有本质变化。这类问题新手经常遇到,尤其是从例程改参数时,把 Rb 和 Rc 一起改了。
解决:检查工作区里 Rb 和 Rc 的数值,确保相差至少 10 到 100 倍。我建议把扩频因子 SF 单独定义成一个变量,模型里所有涉及速率的地方都用 SF 换算,而不是分别手写数值。比如信息速率采样时间写成 SF / Rc,PN 码采样时间写成 1 / Rc,这样只要 Rc 和 SF 两个变量不改错,速率关系就不会坏。还有一个连带检查:解扩侧的低通滤波器带宽要设置成信息速率量级,而不是码片速率量级,否则扩频抑制噪声的作用也会失效。
4.5 代码生成后结果对不上:变步长求解器与连续模块残留
现象:Simulink 里仿真一切正常,但用 Simulink Coder 生成 C 代码,跑到嵌入式板子上或做外部模式联调时,解扩结果和仿真不一致,误码率明显偏高。
原因:模型里残留了连续积分器、Transfer Fcn 这类连续模块,或者求解器还是变步长。代码生成要求全部信号是离散的、采样时间可调度,连续模块在生成代码时会被近似处理,精度和仿真差很多。另外,Spectrum Analyzer、Scope 这些可视化模块在代码生成时也可能引发步长冲突。
解决:做代码生成前,把模型过一遍离散化:Continuous 库里的 Integrator 换 Discrete-Time Integrator,Transfer Fcn 换成 Discrete Transfer Fcn 或直接用滤波器模块;把所有模块的 Sample Time 都显式设置,不继承,不设成 inf;最后把 Spectrum Analyzer 和 Scope 换成 To Workspace 或 Terminator。配置好之后再用代码生成前检查,Simulink 会列出变步长和连续模块的警告,逐条处理完再生成。我早期做这部分时吃过亏,仿真跑得漂亮,模型一生成 C 代码就翻车,后来把固定步长离散化当作代码生成的前置条件,每次都先过一遍,这类问题就很少出现了。
5. 验证与进阶:误码率曲线、处理增益实测和从模型到 C 代码生成
5.1 误码率验证:蒙特卡洛仿真与理论曲线的对照方法
仿真模型的验证,不能只看波形,要跑误码率曲线。AWGN 信道下,BPSK 直接序列扩频的理论误码率和普通 BPSK 一致,因为扩频不改变每比特能量与噪声功率谱密度的比值,只是把噪声带宽也一起展宽了。这条性质是验证模型的最佳基准:如果仿真曲线和理论曲线在 0.5 dB 以内对齐,说明发射、信道、解扩、同步这条链路整体是可信的。
跑蒙特卡洛误码率时,每个信噪比点至少要统计 100 个误码才有统计意义,对应误码率 1e-3 大约需要 10 万比特以上。仿真时间会比较长,常见做法是先把帧长设短跑通流程,再用参数扫描逐步加长。Simulink 里可以用 Error Rate Calculation 模块配合 To Workspace 输出误码数,然后写一个外部循环批量修改信噪比,把一个二维数组的结果存下来,最后一并画成曲线。
5.2 处理增益实测:解扩前后信噪比的测量口径
处理增益的实测方法,在仿真里有标准口径:分别测量解扩前和解扩后的信号功率与噪声功率,做差。解扩前的信号带宽是码片速率量级,解扩后是信息速率量级,两者带宽比的对数,就是处理增益。直接测量信噪比时,解扩前要把信号通过一个带通滤波器限制在扩频带宽内,解扩后再用低通滤波器限制在信息带宽内,滤波器带宽差就是理论处理增益。
Simulink 里测量信噪比,可以用 Spectrum Analyzer 的峰值标记分别读出信号和噪声底的功率,也可以用两个带宽不同的滤波器后接 Average Power 模块,分别测功率。把实测处理增益和 10 * log10(SF) 对比,如果差 1 dB 以上,说明某个环节有额外损耗:同步误差、滤波器滚降、频偏残余都会有贡献。这个对比是我每次调完参数必做的一步,比单纯看误码率更早发现系统层面的问题。
5.3 从仿真到硬件:C 代码生成前要做的四个模型改造
如果你打算把这个仿真模型往硬件方向推进,做 Simulink 模型 C 代码生成前,我建议做四件事。第一,把求解器固定为 discrete,步长显式设定,这是代码生成能通过的前提。第二,把所有可视化模块移除或替换为 Terminator、To Workspace,Scope 和 Spectrum Analyzer 在生成代码时会被忽略或引起步长混乱。第三,逐模块检查数据类型,PN Sequence Generator 输出是 boolean,异或后转 double 再进滤波器,类型转换要显式加 Data Type Conversion 模块,避免生成代码时自动引入额外转换逻辑。第四,把帧同步和定时逻辑改成可复位的状态机结构,避免依赖仿真时间推进,这在 Simulink 外部模式联调时尤其重要,因为实时时钟和仿真时钟的推进方式完全不同。
代码生成后的验证顺序,我习惯先做模型在环(MIL),再做软件在环(SIL),最后再接外部模式。MIL 和 SIL 的误码率曲线要和纯仿真模型一致,如果不一致,逐模块对比信号波形,用 To Workspace 导出中间变量对比,能定位到具体模块。我做这类仿真最大的教训是:不要把全链路误码率当成唯一验证手段,波形对、频谱对、信噪比对,才是硬件移植前真正该确认的事。愿你少走我走过的弯路,希望帮到你。
本文还有配套的精品资源,点击获取