
简介这份DSSS扩频信号生成与解扩演示资源面向通信工程专业学生和无线通信入门开发者用于理解直接序列扩频的核心流程。资源共4个文件均为Matlab脚本整体仅2KB脚本模块划分清晰适合快速运行并对照学习PN码生成、扩频调制与解扩同步等关键环节。已有358人学习浏览。包内脚本覆盖m序列生成、DSSS信号构造和跳频扩展等典型实现可辅助读者将伪随机码、扩频因子、码片同步等抽象概念转化为可运行的仿真代码并可与跳频体制对比加深对扩展频谱通信原理的理解。通过阅读和调试源码能直观观察扩频前后频谱变化掌握收发两端PN码同步对解扩的影响为课程设计、期末复习或后续学习CDMA、Wi-Fi及GPS物理层技术打下基础也可作为毕业设计前的快速验证工具。1. 为什么DSSS扩频信号至今仍是抗干扰主力在GPS、Wi-Fi 802.11b、军事抗干扰链路里DSSS直接序列扩频一直在线。原理一句话能说清把低速数据乘上一串高速伪随机码信号带宽被展宽功率密度被压低然后靠本地同样的一串码把信号捞回来。真正动手写过扩频收发机的人都知道难点不在“相乘”这一步而在m序列怎么选抽头、扩频因子怎么定、接收端码同步怎么锁。手头这套Dsss.rar里恰好有gen_mseq.m、gen_dsss.m、gen_fhss.m和main.m四个程序文件覆盖了PN码生成、DSSS调制、FHSS发射和顶层控制逻辑。下面按文件顺序拆解把每个函数的底层原理、参数选型和易错点都过一遍新手能照着复现老手也能看看自己的同步逻辑有没有漏掉关键参数。2. m序列生成LFSR本原多项式与gen_mseq.m实现2.1 LFSR和本原多项式的关系m序列是PN码的基石本质是一个线性反馈移位寄存器LFSR在特定反馈抽头下产生的最大长度序列。一个n级LFSR最多产生周期为2^n - 1的序列这个序列就是m序列。关键在反馈多项式比如n7时的本原多项式x^7 x^3 1对应反馈从第7级和第3级引出。只有本原多项式才能让LFSR遍历除全零外的所有状态否则序列会退化为短周期扩频性能直接报废。DSSS里选m序列的原因在于它的自相关函数几乎是二值的周期内自相关峰值为周期L偏离一个码片后迅速落到恒定的-1。这个特性决定了接收端滑动相关时能看见锐利的峰也决定了码同步的检测门限可以定得很清晰。相比之下Gold码由两个m序列异或生成互相关性更好适合CDMA这类多址系统但单组序列生成要比m序列多一个寄存器组。对于单用户的扩频演示和绝大多数抗干扰链路m序列是性价比最高的选择。判断反馈多项式是不是本原多项式工程上最省事的方法是查表。下表列出常用级数的本原抽头配置这些配置可以直接用到gen_mseq.m里寄存器级数n周期L2^n-1常用本原抽头531[5 2]663[6 1]7127[7 3]8255[8 4 3 2]9511[9 4]101023[10 3]注意抽头向量里必须包含最高级n否则LFSR只是在较低级数上打转。寄存器初值不能全0全0会让序列永远卡在零状态输出全是恒定的电平这是最容易犯的低级错误。2.2 gen_mseq.m抽头配置和寄存器初值这份源码里的gen_mseq.m就是为上面这些本原多项式设计的。按标准LFSR结构补全一个可直接运行的版本方便对照原包里的函数看差异function [seq, taps] gen_mseq(n, taps, init) % 生成n级m序列 % 输入: n - 寄存器级数 % taps - 反馈抽头索引向量(从1开始,必须包含n) % init - 寄存器初值(长度n的0/1向量,不能全0) % 输出: seq - 周期为2^n-1的m序列(映射为1/-1) if nargin 3 || isempty(init) init [1 zeros(1, n-1)]; % 默认初值100...0 end if nargin 2 || isempty(taps) switch n case 5, taps [5 2]; case 7, taps [7 3]; case 8, taps [8 4 3 2]; case 10, taps [10 3]; otherwise, error(未配置该级数抽头); end end L 2^n - 1; reg init(:); seq_bit zeros(1, L); for k 1:L seq_bit(k) reg(end); % 取最低位作为输出 fb mod(sum(reg(taps)), 2); % 反馈位 抽头异或 reg [fb; reg(1:end-1)]; % 反馈位进最高位,右移 end seq 2 * seq_bit - 1; % 0/1转成1/-1 end这段代码的核心在循环里的三行reg(end)取出当前最低位作为序列输出sum(reg(taps))把选中的抽头级数值相加mod(...,2)等效于异或得到反馈位然后反馈位放入最高位原有寄存器右移。整个循环跑完正好是一个周期得到周期L的m序列。最后的2*seq_bit - 1很重要因为后面DSSS扩频要用双极性信号和BPSK符号相乘如果直接用0/1序列乘法后会出现值不匹配。init只要不是全0不同初值产生的序列只是循环移位不影响码型但接收机必须知道初值才能本地复现。taps写错时seq的自相关就会出现多个假峰这一步直接决定了后续所有链路能否正常工作。2.3 m序列性质验证用自相关函数检验生成完m序列不要急着交给下游先验证码是否正确。判断标准有两个周期内±1个数差1自相关零偏移处为周期L偏移一个码片后恒为-1。用一行xcorr就能检查ac xcorr(seq, seq, coeff); mid ceil(length(ac)/2); fprintf(零偏移自相关: %f\n, ac(mid)); fprintf(偏移1码片: %f\n, ac(mid1));如果seq是正确的m序列ac(mid)会非常接近1ac(mid1)约等于-1/L。注意这里用的是归一化自相关所以峰值不是L而是1。若看到ac(mid)明显小于0.9或者ac(mid1)的绝对值和理论值差太远优先检查抽头向量是否包含最高级、初值是否全零。自相关验证是后面同步算法能跑通的前提建议每次修改m序列生成函数后都先跑这一段。3. 扩频与调制gen_dsss.m里扩频因子和BPSK如何配合3.1 从比特到码片扩频因子的作用DSSS扩频的本质是每个信息比特被一组PN码替换。设信息速率为R_bPN码片速率为R_c扩频因子SFR_c/R_b。802.11b的SF是11GPS C/A码SF是1023。SF越大处理增益越高抗干扰能力越强但占用带宽也越宽频谱效率反比下降。所以工程上不能盲目追求大SF要结合无线信道带宽和可用频段来定。扩频顺序有两种做法先扩频再调制或者先调制再扩频。基带仿真常用后者即先把信息比特做BPSK映射成±1然后每个符号复制SF份再与PN码逐点相乘。这样在数学上与先扩频再调制完全等效但代码更直观也方便随时在扩频前后拿出信号对比频谱。gen_dsss.m就是按这个思路实现的。3.2 gen_dsss.m完整实现function [tx, params, pn] gen_dsss(data, sf, pn_seq) % 生成DSSS基带信号 % 输入: data - 原始信息比特(0/1行向量) % sf - 扩频因子(每个比特复制的码片数) % pn_seq - 长度至少为sf的PN码(1/-1) % 输出: tx - 扩频后基带信号(每码片一个采样) % params - 结构体,保存sf和PN码等参数 % pn - 截取后的实际扩频码 if length(pn_seq) sf error(PN码长度不能小于扩频因子); end pn pn_seq(1:sf); % BPSK映射: 0 - 1, 1 - -1 d_mod 2*data(:). - 1; % 每个比特复制sf份 rep_sym kron(d_mod, ones(1, sf)); % PN码按比特周期重复 pn_rep repmat(pn, 1, length(data)); % 逐点相乘完成扩频 tx rep_sym .* pn_rep; params.sf sf; params.pn pn; end这里kron(d_mod, ones(1,sf))实现“每个比特扩展成sf个相同值”repmat(pn,1,length(data))把PN码按信息比特个数重复。两者逐点相乘后每个信息比特都被完整的PN码调制了一遍。如果信息比特是1BPSK符号为-1那么这一比特的扩频输出是PN码的反相。这个反相在解扩时体现为相关峰的极性接收端用绝对值判测即可。参数要注意sf必须小于等于PN码周期。若PN码长度是127而sf设成255pn_seq(1:sf)会越界或者PN码不完整导致自相关特性丢失。常见做法是让sf等于PN码周期例如m序列127位时直接sf127。data的长度会决定tx的长度当sf127、data有1000比特时tx有127000个码片后续画眼图和频谱时内存压力不大。3.3 扩频前后频谱对比扩频是否生效直接看功率谱最直观。MATLAB里用pwelch画出扩频前后的归一化功率谱可以清楚看到带宽被展宽了多少倍fs 10e6; % 采样率 [p_spread, f] pwelch(tx, [], [], [], fs); [p_orig, ~] pwelch(d_mod, [], [], [], fs); plot(f, 10*log10(p_orig/max(p_orig))); hold on; plot(f, 10*log10(p_spread/max(p_spread))); legend(原始BPSK, DSSS扩频后); xlabel(频率/Hz); ylabel(归一化功率/dB);理想情况下扩频后的主瓣宽度是原始BPSK的SF倍峰值功率谱密度下降约10lg(SF)dB。例如SF127时功率谱密度下降约21dB这就是隐蔽性的来源信号埋在噪声下面不容易被检测到。不过这只在理想无码间干扰下成立实际中码片波形成形会让频谱展宽比例与SF有一个近似关系不完全是精确的整数倍。3.4 为什么扩频不提升信噪比却改善抗干扰扩频本身不改变信号总功率也不改变每个比特的能量所以在给定了比特信噪比的AWGN信道里扩频前后误码率一样。这个结论很多人一开始想不明白因为直觉上会觉得“处理增益”应该等效成信噪比提升。处理增益真正起作用的是对抗窄带干扰。窄带干扰只占据很小一部分频带在接收端做解扩相关运算时干扰与本地PN码的乘积被展到整个扩频带宽上等效于把干扰功率摊薄而信号能量被重新收拢成相关峰。这个过程的信噪比改善近似等于SF也就是处理增益。所以DSSS的收益要在存在干扰的场景里才体现出来。我们的测试流程也要按这个逻辑设计先跑无干扰AWGN再叠加窄带干扰看扩频系统的误码率优势。3.5 QPSK-DSSS把并行支路也用上BPSK扩频每比特占用SF个码片频谱效率偏低。实际系统常用QPSK把两根并行支路塞进同一带宽每个QPSK符号携带2比特扩频后码片速率不变数据率翻倍。gen_dsss.m里也可以扩展出一个QPSK版本function tx_q gen_dsss_qpsk(data, sf, pn) % QPSK-DSSS: 奇偶比特分裂到I/Q支路,分别扩频 if mod(length(data),2) ~ 0 data [data 0]; end di data(1:2:end); dq data(2:2:end); i_rep kron(2*di(:).-1, ones(1, sf)); q_rep kron(2*dq(:).-1, ones(1, sf)); pn_rep repmat(pn, 1, length(di)); i_sig i_rep .* pn_rep; q_sig q_rep .* pn_rep; tx_q i_sig 1j * q_sig; end这里I路和Q路使用同一个PN码或两个不同的PN码都可以。用同一个码实现简单但两条支路的扩频码相同在特定干扰角度下I/Q会同时受影响用两个互相关性低的m序列会更稳。输出复数信号后后续调制到载波时可分别乘cos和sin分量。注意QPSK-DSSS的解扩要分别对I/Q做相关再合并判决不能直接把复数信号乘PN码。4. 解扩与码片同步相关峰检测和滑动相关参数设定4.1 为什么同步是DSSS的命门解扩在数学上就是接收信号与本地PN码相乘后积分。只有本地PN码和发送端PN码在码片级对齐乘积才始终保持同一符号积分能形成尖锐的相关峰。一旦错一个码片乘积正负交替积分结果被抹平信号完全沉在噪声里。所以DSSS接收机必须先把码相位找出来这个过程叫码同步。码同步分两步走。第一步是粗同步也叫捕获用滑动相关在不确定的码相位范围内搜索找到相关值超过门限的位置。第二步是细同步也叫跟踪用早迟门Early-Late Gate实时微调码相位抵消收发时钟偏差和晶体漂移。滑动相关实现最直观先把它跑通再谈环路是理解整个接收链路的捷径。4.2 滑动相关捕获的MATLAB实现function [delay, corr_peak] sync_capture(rx, pn, sf, L) % 滑动相关捕获 % 输入: rx - 接收基带信号(至少Lsf个采样) % pn - 本地PN码(1/-1,长度sf) % sf - 扩频因子 % L - 搜索的码片偏移范围,搜索0~L-1 % 输出: delay - 检测到的码片级延迟 % corr_peak - 对应的相关值 corr zeros(1, L); for offset 0:L-1 seg rx(offset1 : offsetsf); corr(offset1) abs(sum(seg .* pn)); end [corr_peak, idx] max(corr); delay idx - 1; end循环里每次从rx取一个长度为sf的窗口与本地PN码做内积。窗口长度等于一个扩频周期如果窗口恰好对齐发送PN码内积绝对值接近信号幅度乘以sf如果没有对齐乘积正负相消结果接近噪声电平。用abs是因为BPSK调制会让发送端PN码有时反相取绝对值后就能无视信息比特的极性只看对齐程度。L的取值决定了搜索范围和捕获时间。如果完全不知道发送相位L至少要等于PN码周期。上面代码假设每码片一个采样实际接收机为了保留码片波形细节通常每码片采2到4个点这时搜索步进就要细分到采样间隔。更精细的做法是先把接收信号以码片速率做匹配滤波再按码片滑动这样搜索次数少且性能稳定。门限的设定不是固定的最大值而是噪声均值加若干倍标准差建议在捕获前先采集一段无信号数据估算噪声底。4.3 相关堆积长度与检测门限单次滑动相关只用一个扩频周期的能量在低信噪比环境下不足以可靠判定。工程上会连续做多个符号周期的相干积分把多个相关值累加再看是否超过门限。相干积分周期数每翻一倍等效信噪比提升约3dB但积分时间太长也会累积相位旋转所以还要配合载波同步。下表是实际调DSSS链路时常用的一组参数可作为初始值再根据实测调整参数典型值说明扩频因子SF31 / 63 / 127根据带宽、处理增益要求选取采样率2 ~ 4倍码片速率每码片至少2个采样点相干积分周期数1 ~ 10每翻倍约提升3dB处理增益捕获门限噪声均值5倍标准差需实测噪声统计量确定搜索步进1码片粗捕获 / 0.1码片细跟踪越细捕获时间越长门限设置如果只看最大值噪声尖峰也能触发误捕。稳妥的做法是跑一段纯噪声序列计算相关值的均值和标准差门限设为均值加5倍标准差这样虚警概率被压到很低。捕获后计算峰值与门限的余量如果峰值只有门限的1.2倍说明SNR太低或堆积周期数不够应增加积分周期数。4.4 早迟门跟踪环路捕获完成后进入跟踪阶段。早迟门跟踪的原理是同时用三个本地PN码早一个码片、准时、迟一个码片分别与接收信号相关得到E、P、L三个值。当本地码恰好对齐时E和L相等偏早时EL偏晚时EL。用E-L作为误差信号输入环路滤波器不断调整码相位。% pn_early / pn_late 分别是左移/右移一位的本地PN码 e abs(sum(rx(off0 : offsf-1) .* pn_early)); p abs(sum(rx(off1 : offsf) .* pn)); l abs(sum(rx(off2 : offsf1) .* pn_late)); err e - l; % 误差信号err为正说明本地码偏早需要把取窗口的起点off向右调整err为负则向左。闭环后off会稳定在零点附近但时钟漂移通常要求环路持续纠错所以不能用一次校准的结果锁死。跟踪步进一般是1/16或1/32码片这取决于DAC和寄存器的精度。这里给的只是码片级环路实际DSSS接收机还要同时做载波频偏估计因为残余频偏会让相关峰幅度周期性衰减严重时跟踪环直接脱锁。把码环和载波环联合起来才是能上信道的完整实现。5. FHSS对照与DSSS验证gen_fhss.m差异及误码率测试技巧5.1 gen_fhss.m另一条扩频路线文件包里还有gen_fhss.m它演示的是跳频扩频正好和DSSS形成对照。FHSS的机制完全不同载波频率按伪随机图案快速跳变每一个时刻信号只占一个窄带但整体上覆盖很宽的频谱。DSSS是把每个比特用长码扩到全带宽FHSS则是每个数据块用一个随机的窄带载波发送。gen_fhss.m的典型实现逻辑是用PN码或简化随机序列生成跳频图案每个数据符号对应一个载波频率BPSK调制后乘上对应频率的载波。核心代码如下function [fhss_sig, hops] gen_fhss(data, hop_freqs, fs, time_per_hop) % 生成BPSK调制的跳频信号 L length(data); hops randi([1 length(hop_freqs)], 1, L); % 简化跳频图案 fhss_sig []; for k 1:L t (0:round(time_per_hop*fs)-1)/fs; carrier exp(1j*2*pi*hop_freqs(hops(k))*t); mod_sym 2*data(k)-1; % BPSK映射 fhss_sig [fhss_sig, mod_sym * carrier]; end endhops变量就是跳频图案每个符号选一个频率。理想情况下这个图案应该由gen_mseq.m产生的PN码映射到频率表而不是纯随机因为接收机必须能实时预测当前频率才能解调。DSSS用PN码直接调制基带信号FHSS用PN码选择载波频率这是两种扩频方式最重要的区别。hop_freqs相邻频率的最小间隔要大于数据符号带宽否则跳频后相邻信道互相泄漏接收端解调会产生符号间干扰。5.2 DSSS/FHSS对比表在项目选型或面试里DSSS和FHSS的对比是高频问题。下面这张表按工程关注点整理维度DSSSFHSS瞬时频谱占用全带宽窄带处理增益来源扩频因子跳频点数抗窄带干扰强解扩会展平干扰弱信号可能正好落在干扰频点抗跟踪干扰中等固定带宽容易被监测强跳频图案随机时难以跟踪同步复杂度码片同步 载波同步时间同步 跳频图案同步典型应用GPS、Wi-Fi 802.11b蓝牙、战术电台注意“抗窄带干扰”这一行不能只看结论。DSSS虽然能把窄带干扰展平但若干扰功率极大解扩后展平的噪声底可能仍然高于信号需要通过窄带干扰抑制滤波先削掉干扰。FHSS在遇到干扰频点时该跳频数据会丢失需要交织和纠错编码来补偿。实际系统里两种技术也会混用比如先FHSS再对每个跳频驻留时间内的符号做DSSS形成混合扩频兼顾两者的优势。5.3 用误码率曲线验证DSSS实现程序写完不能只看波形要验证扩频系统真的有效最直接的办法是画误码率曲线。在AWGN无干扰下BPSK-DSSS的理论误码率和不扩频的BPSK一样因为扩频本身不改变比特能量。但在叠加窄带干扰后扩频系统会明显优于不扩频的系统。snr_db 0:2:10; ber_no_spread zeros(size(snr_db)); ber_spread zeros(size(snr_db)); for k 1:length(snr_db) % tx_int 是未扩频的BPSK信号, tx_dsss 是扩频信号 rx1 awgn(tx_int, snr_db(k), measured); rx2 awgn(tx_dsss, snr_db(k), measured); % 加入窄带干扰: 中心频率在信号频带内的单音 t (0:length(rx1)-1)/fs; rect 0.5 * sin(2*pi*0.1*fs*t); % 中心频率0.1*fs rx1 rx1 rect; rx2 rx2 rect; % 解调并统计误码... end semilogy(snr_db, ber_spread, -o); hold on; semilogy(snr_db, ber_no_spread, --x); grid on;画完曲线后如果看到ber_spread在同等SNR下明显低于ber_no_spread说明扩频链路工作正常。如果两条曲线重叠先检查窄带干扰功率是否太小干扰幅度至少要高于噪声幅度才能体现出差别。如果ber_spread在0.5附近震荡几乎可以断定是同步没锁住不是解调算法的问题。调试顺序建议是第一步跑gen_mseq.m验证自相关峰第二步跑gen_dsss.m观察扩频后频谱带宽是否扩展第三步跑滑动相关捕获打印相关峰的位置和峰值确认捕获结果和发送端的码片偏移一致最后才进入误码率统计。每一步都有一张明确的图或一个明确的数值可以核对出了问题能立刻定位到具体函数。5.4 工程中的一个坑码片波形和根升余弦滤波最后说一个纯理论代码和工程实现的分水岭。前面所有代码都假设码片是理想矩形脉冲频域无限宽这在仿真里没问题但实际发射时要对码片波形做脉冲成形否则旁边的信道会被带外辐射打爆。最常用的成形滤波器是根升余弦滤波器滚降系数取0.22或0.5代码里可以用rcosdesign函数生成滤波器系数再对tx做卷积。引入成形滤波器后码片不再是干净的±1矩形信号波形会平滑过渡。接收端如果仍然按每码片采一个点做相关采样点未必落在波形峰值上会损失信噪比。所以实际DSSS接收机都会做过采样每码片至少采2个点在相关前先做匹配滤波。很多从仿真直接跳到外场的团队第一次性能下降都是忽略了这一层而不是扩频原理本身有问题。main.m里如果只调用了gen_mseq、gen_dsss、gen_fhss建议在发送端末尾加一个根升余弦滤波器接收端再用相同系数做匹配滤波整套DSSS链路才具备走向真实信道的条件。本文还有配套的精品资源点击获取