☰
直接序列扩频通信MATLAB仿真:处理增益、PN码与误码率分析
2026/10/28 5:49:46 网站建设 项目流程

简介:面向通信原理课程学习与扩频通信入门实践的MATLAB仿真文档,适合电子、通信专业学生及需要理解直接序列扩频(DSSS)链路的自学者。内容围绕直扩系统模型、BPSK调制与解扩流程展开,并梳理m序列、GOLD码、WALSH码和OVSF码的适用场景,结合2kbps信源、扩频因子64、高斯信道下的误码率仿真,帮助读者建立从原理到参数验证的完整认知。包内共1个doc文件,约320KB,体量轻便,便于按章节查阅实验原理、程序代码与结果分析。已有142人学习,可作为课程实验报告撰写、MATLAB仿真复现和抗干扰性能对比的参考材料,文中对处理增益、抗多径与抗同频干扰的讨论也便于延伸至码分多址相关学习。

1. 扩频不是「把信号摊薄」:为什么加了噪声反而更容易判对

把 2 kbps 的信息流塞进 64 倍宽的频带里,功率谱密度掉到原来的六十四分之一——这是直接序列扩频通信系统最直观的样子。按常理,同样的发射功率摊在更宽的频带上,每赫兹承载的能量更少,接收机理应更难把信号捞出来。可基于 MATLAB 的直接序列扩频通信系统仿真设计跑出来的曲线恰好相反:信噪比从 1 dB 扫到 15 dB,误码率一路往下掉,扩频因子越大,拐点来得越早。

这个反差是整个直扩体系的地基。答案不在发射端的频谱搬移里,而在接收端那个看起来最不起眼的动作——把收到的序列再乘一遍伪随机码(PN 码)。乘法做两次等于没做,信号被还原;干扰只被乘了一次,反而被推得更宽。处理增益就是这么凭空长出来的,不是放大器给的,是相关运算给的。

搞懂这条链路值当的地方在于,它同时解释了抗同频干扰、抗多径、抗频率选择性衰落这三件事为什么能用同一套数学描述,也解释了码分多址为什么能在一根天线上叠几十路用户。下面从能量账本算起,一路推到移位寄存器抽头和积分清零判决器。

2. 处理增益的账怎么算:从模二加到相关累加的能量守恒

2.1 一个比特被「摊」成 N 个码片之后,能量去哪了

设信源序列 a(t) 的码元周期为 Ta,伪随机码 c(t) 的码片周期为 Tc,且 Tc 远小于 Ta,扩频因子 N = Ta / Tc。双极性表示下,模二加等价于乘法:信息比特 1 映射为 +1、0 映射为 -1,PN 码也用同样的映射,两路序列逐位相乘就完成了扩频。原文那句「1 用某个序列代替、0 用另一个序列代替」,说的正是这个操作在波形层的样子——每个信息比特位置上放的不是一个方波,而是一整段正负跳变的码片图案。

关键在于能量账本。扩频前后每个比特的能量 Eb 没变,仍是 Eb = Ps × Ta(Ps 为平均功率);但信号占用的带宽从 Bs 变成了约 N × Bs。功率谱密度等于能量除以带宽,带宽涨 N 倍,谱密度就掉 N 倍。所以扩频确实是在「摊薄」,摊薄的是功率谱密度,不是总能量。

这一点必须先钉死,否则后面会误以为解扩能造出能量来。能量一直躺在那段宽频带里,只是被摊得低于噪声底,单看任何一个窄带滤波器都捞不出来。接收端要做的不是放大,而是把散落在 N 个码片上的能量重新聚回一个符号周期内——这就是相关运算的全部工作。

顺便说清采样层面的对应关系。在仿真里,一个信息符号被展开成 L 个采样点,每个 PN 码片又被复制成若干采样点,L 就等于「码片数 × 每码片采样数」。后面第 5 章会看到,这两个倍数没对齐时误码率曲线会莫名其妙地抖,根子就在这里。

2.2 相关器为什么等价于窄带滤波器:干扰被扩频、信号被压缩

接收端把收到的信号再乘一次本地 PN 码。对信号项而言,a(t)·c(t)·c(t) = a(t)·c²(t) = a(t),因为 c(t) 只取 ±1,平方恒等于 1。乘两次相互抵消,宽带扩频信号被压回原来的窄带。这一步在频域上相当于把信号频谱从 N·Bs 重新搬回 Bs,能量密度回升 N 倍。

对干扰项而言,情况完全相反。设干扰为 i(t),与 PN 码不相关,乘完之后变成 i(t)·c(t)。两个不相关序列相乘,频谱等于各自频谱的卷积,结果是干扰的带宽被展宽了大约 N·Bs,落进信号通带的那一小段功率只剩约 1/N。原文说「相关解扩对干扰相当于一次扩频」,指的就是这个镜像过程——信号被压缩,干扰被摊开,一压一摊之间信噪比抬高了 N 倍。

于是处理增益的定义顺理成章:G = 10 lg(N) dB。扩频因子 64 对应约 18 dB,扩频因子 400 对应约 26 dB。原文提到「处理增益达到 10 dB 以上」,那是保守说法;只要码长够,几十 dB 都能拿到,代价是带宽。这条增益不是白拿的,它用带宽换信噪比,带宽就是扩频系统的硬通货。

多径干扰为什么也能被吃掉,用同一套逻辑就能解释。不同路径到达的信号是同一 PN 码的不同延迟副本,只要延迟超过一个码片周期 Tc,本地码与其相关值就掉到接近零,几路多径在相关器输出端被分成几个互不重叠的尖峰。想合成一路就把它们按时间对齐后相加,想要哪一路就只在一个码片窗口内积分。抗多径能力本质上来自 PN 码尖锐的自相关峰,而不来自任何滤波电路。

2.3 从 10lg(N) 到仿真里的 400 点累加:增益在代码的哪一行兑现

理论归理论,增益在代码里究竟落在哪一行?答案是判决器前面那段看起来最笨的累加循环。

% 相关解扩后的积分清零判决:一个信息符号对应 400 个采样点 xo = zeros(size(x)); % 预分配判决输出,长度等于信源符号数 for i = 1:100 % 逐个信息符号做判决 z2 = 0; % 积分器清零,"积分清零"这个名字的由来 for j = (1+(i-1)*400):(i*400) z2 = z2 + zl(j); % 400 点累加,等价于与矩形窗做相关 end if z2 >= 0 % 相关值非负判为 +1 xo(i) = 1; else xo(i) = -1; % 相关值为负判为 -1 end end

这段代码里 400 就是每个符号的采样点数 L,循环变量 i 走 100 次对应 100 个信息符号。内层 400 次加法完成的是矩形窗匹配滤波,数学上等于把解扩后的波形与一个宽度为 Ta 的矩形脉冲做相关。判决门限取 0,是因为双极性映射下「+1 与 -1 等概」的中点在零,只有这样才能让误判概率最小。

真正兑现处理增益的动作发生在加法之前——jk_code = rs .* k_code这一行把接收信号与本地扩频码逐点相乘,把 400 个采样点上散落的信号能量重新同相相加,而噪声因为与本地码不相关,相加后按 √400 增长,信号按 400 增长,幅度信噪比提升 √400 = 20 倍,功率信噪比提升 400 倍。这就是 10 lg(400) ≈ 26 dB 在代码里的落点。

有一个容易忽略的细节:这段累加只统计了 100 个符号,z1(a) = z/100的误码率分辨率被钉死在 0.01。曲线画到 10⁻⁴ 的坐标轴上时会突然「掉不下去」,不是系统性能到顶了,是统计样本用完了。这个坑留到第 5 章细说。

3. PN 码生成:m 序列的移位寄存器为什么必须「抽头」

3.1 线性反馈移位寄存器的状态转移与周期 2^n-1

扩频码决定了抗干扰能力的上限:自相关峰越尖、互相关底越低,接收端分辨信号与干扰的本事越大。仿真里最常打交道的 m 序列由线性反馈移位寄存器(LFSR)产生,n 级寄存器最多能枚举 2ⁿ 个状态,其中一个全零状态是死锁——各级都输出 0,反馈回来还是 0,永远出不来。所以可用状态是 2ⁿ - 1 个,m 序列的最大周期也就是 2ⁿ - 1。

stage = 3; % 移位寄存器级数 n,决定码长 2^n - 1 ptap1 = [1 3]; % 反馈抽头位置,等价于选择一个本原多项式 regi1 = [1 1 1]; % 初始状态,绝不能全零,否则寄存器死锁 code = mseq(stage, ptap1, regi1, user); % 生成周期 7 的 m 序列

三个参数各司其职:stage定码长,ptap1定反馈结构,regi1定从哪个状态起跑。user参数用于在多用户场景下取不同相位的副本,本质上是给同一序列换一个起始偏移。

这里有个容易被当成玄学的地方:为什么偏偏是 [1 3] 和 [2 3] 这两组抽头能用?n = 3 时,8 个状态去掉全零剩 7 个,想让寄存器跑满 7 个状态再回头,反馈多项式必须是本原多项式。3 级里满足条件的只有 x³ + x + 1 和 x³ + x² + 1 两个,对应抽头 [1 3] 和 [2 3]。换成 [1 2] 或 [2 3] 之外的组合,周期会缩短成 3 或 1,码长不够,处理增益直接打折。

3.2 抽头选择决定本原多项式:为什么 stage=3 只有两组可用

把移位过程摊开看会更清楚。初始状态 111,抽头 [1 3] 意思是把第 1 级和第 3 级异或后反馈到输入端,每来一个时钟,寄存器整体右移一位、最高位填入反馈值。111 → 011 → 001 → 100 → 010 → 101 → 110 → 111,七个状态走完一圈,第七步回到起点,周期正好 7。

失败的情形长什么样?如果抽头选成 [1 2],异或的是第 1、2 级,寄存器会掉进 111 → 011 → 101 → 010 → 001 → 100 → 110 → 111 之外的短循环,序列提前重复,等效码长缩水。仿真里表现为扩频增益对不上理论值,误码率曲线比预期差好几个 dB,而且换随机种子也不会改善——这是结构性的,不是运气问题。

抽头还有一个隐含约束:末级必须参与反馈。如果抽头集合里不含第 n 级,末级的状态永远影响不到输入端,它就成了一个纯延迟单元,实际有效级数变少,周期自然不够。所以 [1 2] 在 n = 3 时必错,[1 3]、[2 3] 才成立。

工程上不会手工枚举这些组合。常见做法是预先查表:给定级数 n,查一张本原多项式表,把对应抽头位置直接填进ptap参数。n 到十几级时表还很短,n 再大就要靠搜索算法验证周期了。

3.3 GOLD 码与正交码族:地址数从 2^n-1 到平方级的跃迁

单个 m 序列的自相关很好,互相关却不理想。码分多址要求几十路用户在同一频段上共存,彼此之间的互相关底必须压得足够低,否则一路用户对另一路就是强干扰。m 序列的互相关峰值随相位差剧烈起伏,不能直接当多址码用。

GOLD 码解决的正是这个问题。取一对码长相等、码速率相同的 m 序列优选对,逐位模二加,每改变两序列的相对位移就得到一个新的 GOLD 序列,一共能凑出 2ⁿ + 1 个。互相关峰值被压到一个可控的三值集合上,虽然比 m 序列的自相关峰差一点,但地址数从 2ⁿ - 1 跃升到 2ⁿ + 1,且互相关特性稳定可预测。

m1 = mseq(stage, ptap1, regi1); % 优选对中的第一个 m 序列 m2 = mseq(stage, ptap2, regi2); % 优选对中的第二个 m 序列 code = goldseq(m1, m2, user); % 模二加生成第 user 个 GOLD 码

goldseq的第三个参数user就是地址索引,不同用户拿到序列循环移位后的不同副本,靠位移区分身份。这也解释了码分多址的基本运作方式:所有用户同时同频发射,接收端用本用户的码做相关,其他用户的信号因为互相关低而被压成噪声底。

另一条路线是正交码。WALSH 函数是一组非正弦的完备正交函数系,两两互相关严格为零,在多址场景里天然免疫用户间干扰,代价是正交性对同步极度敏感——延迟偏了半个码片,正交性立刻崩塌。OVSF 码则把正交性和可变扩频因子结合起来,允许不同速率的业务在同一时隙上共存,速率低的用长码、速率高的用短码,只要不违背码树上的父子关系就能保持正交。

四类码的取舍可以这么记:m 序列自相关最尖、适合单用户测距与同步;GOLD 码互相关可控、适合多址;WALSH 码正交完美但对同步苛刻;OVSF 码灵活但码资源管理复杂。仿真里默认走 GOLD 或 m 序列,是因为它们对定时误差的容忍度更适合教学验证。

4. 仿真链路的实现细节:BPSK 调制、载波搬移与相干解调

4.1 从 x 到 d:符号复制与采样率的对账

信源产生 100 个 ±1 的符号,每个符号要展开成 400 个采样点,才能和后续的扩频码、载波逐点相乘。代码里用了一段笨但直观的循环完成这件事:d((1+(i-1)*400):i*400) = x(i),把第 i 个符号原样填进对应的 400 个位置。等价写法是d = kron(x, ones(1,400)),用 Kronecker 积一次搞定,运行速度快一个数量级,做长序列仿真时差别很明显。

采样间隔 dt = Tb / L 是整个仿真时间轴的刻度。Tb = 1/Rb = 4,L = 400,所以 dt = 0.01。后面所有波形的时间轴 t、载波相位 2π·fc·t、滤波器的归一化截止频率,全都挂在这个 dt 上。dt 一旦改动,滤波器系数、载波周期、判决窗口长度都要跟着重算,这是仿真代码耦合最紧的一处。

载波调制那一步把所有能量搬到射频频段:s = b .* cos(2*pi*fc*td)。这里用的是双边带抑制载波,没有直流分量,接收端必须靠本地载波相干解调,不能包络检波。BPSK 的相位只有 0 和 π 两种,映射回比特就是 sign 函数的正负。

4.2 载波搬移与欠采样的隐患

fc = 4e4、fs = 4000这一组参数放在一起需要停下来看一眼。按奈奎斯特准则,采样率至少要达到信号最高频率的两倍才能无失真重建,4 kHz 的采样率对应 40 kHz 的载波,差了整整二十倍。这不是笔误就是参数没有联动更新。

后果不是简单地「波形画得难看」。数字域里 cos(2π·fc·n·dt) 的自变量每步增量是 fc·dt = 400,而余弦函数以 2π 为周期,400 是 2π 的整数倍附近,实际算出来的相位几乎每步都回到同一个等效角度。载波在数值上退化成了常数,调制没把频谱搬走,解调乘的又是同一个常数,整条射频链路在数值层面等于被短路了。这时候误码率当然好看,因为噪声只在基带上加了一次,扩频和解扩的增益评估全被架空。

正确做法有两条路。要么把 fc 降到 fs 的十分之一到五分之一之间,比如 fs = 4000 时取 fc = 400;要么把 fs 提上去,至少 8×10⁴,让每个载波周期有 2 个以上采样点。前者跑得快,适合验证算法逻辑;后者更接近真实射频链路,但循环次数涨二十倍,仿真时间也涨二十倍。做参数扫描时通常选前者,做波形细节核对时选后者。

4.3 解扩、低通与判决:三级流水

接收端整条链路可以拆成三段:加噪、相干解调、解扩滤波判决。每一段的参数口径都不一样,混用是误码率对不上理论值的头号原因。

r = awgn(s, SNR(10), 'measured'); % 按实测信号功率加高斯白噪声 rs = r .* cos(2*pi*fc*td); % 相干解调:乘同频同相本地载波 jk_code = rs .* k_code; % 解扩:乘与发端同步的扩频码 [f, rf] = T2F(td, jk_code); % 时域转频域 [tl, l] = lpf(f, rf, fc/10000); % 低通滤掉倍频分量与带外噪声

awgn的第三个参数'measured'表示先测量输入信号的实际功率,再按第二个参数给定的信噪比注入噪声,省去了手工计算信号功率的步骤。这个口子很方便,也很容易踩坑:它给的 SNR 是「信号总功率与噪声总功率之比」,不是通信理论里常用的 Eb/N0,两者差一个 10 lg(fs/2/Rb) 的换算因子。直接拿这个 SNR 去对理论误码率曲线,永远对不上。

相干解调那一行乘完本地载波后,频谱里同时存在基带分量和二倍载频分量,低通滤波器负责把后者扔掉。lpf的第三个参数fc/10000是归一化截止频率,这个 10000 不是随便写的,它和采样率、FFT 点数绑在一起,改了任何一项都得重算。

解扩那一步要求本地码与发端码严格同步——同码型、同相位、同速率。仿真里因为收发共用同一个k_code变量,同步是白送的;真实系统里这一步要靠捕获与跟踪环路,是整个接收机最复杂的部分。仿真代码把最难的部分跳过去了,这也是为什么仿真曲线总是比实测漂亮。

5. 常见问题排查:这套链路最容易翻车的五处

5.1 信号层的三处翻车:采样率、码周期与噪声口径

现象一:解调后的波形和发端几乎重合,误码率低得反常。原因在 4.2 已经点破——载波频率高于采样率的一半,数字域里载波退化成常数,射频搬移在数值上根本没发生。解决方法是让 fs 至少达到 2fc,工程上取 4 到 10 倍留余量,或者直接把 fc 压到 fs 的十分之一以下。

现象二:判决值在门限附近抖动,误码率曲线不平滑,换随机种子结果跳变很大。根子是扩频码周期与符号长度没对齐。PN 码长 7,每个码片复制 4 份得到 28 个采样点,而一个符号占 400 个采样点,400 / 28 = 14.28,不是整数,最后一个码片被硬生生截断。截断处本地码与发端码失配,相关值少了那一小段的贡献,判决就飘。解决方法是让 L 取「码长 × 每码片采样数」的整数倍,比如 7 × 4 × 14 = 392,或者干脆把码长改成能整除 400 的数。

现象三:加不同信噪比扫出来的误码率曲线整体平移,形状对但位置不对。这是awgn的 SNR 口径问题。'measured'模式下参数是信号功率与噪声功率之比,而扩频系统的抗干扰能力应该用 Eb/N0 衡量,换算关系是 Eb/N0 = SNR + 10 lg(fs / (2·Rb))。少了这一步换算,曲线会整体偏移十几 dB,看着像系统性能差,其实是坐标系没对齐。

5.2 统计层的两处翻车:判决门限与误码率分辨率

现象四:误码率曲线落到 0.01 就断崖式结束,怎么加大信噪比都下不去。不是系统到顶,是统计样本用完了。z1(a) = z/100里分母是 100 个符号,能表示的最小非零误码率就是 1/100 = 0.01,再低只能记成 0,画在半对数坐标上就是一条断掉的线。解决方法很简单:把符号数 M 从 100 提到 10⁵ 以上,或者改成统计错误比特数而非错误符号数,让分辨率跟着样本量一起涨。代价是循环次数增加,运行时间线性增长,做参数扫描时要权衡。

现象五:码序列输出全零,或者判决结果里冒出 0 值。两个不同的坑撞在一起了。码序列全零通常是把regi1初始化成了 [0 0 0],LFSR 掉进死锁状态,反馈永远输出 0,扩频码变成直流,扩频增益归零。判决出 0 则是sign函数的行为——sign(0)返回 0,而双极性系统里只应该有 ±1。解法是把初始状态设成非全零,判决改成显式的if z2 >= 0 ... else ...,避免 sign 在零点上的歧义。

这五条里前三条会让人怀疑算法,后两条会让人怀疑理论,实际上全是实现细节。仿真翻车十次有九次不在公式,而在参数口径。

6. 从仿真到工程:处理增益、误码率曲线与三个取舍

把曲线跑出来只是开始,真正要判断的是取舍。扩频因子 N 决定处理增益,也决定带宽占用,两者严格成正比,没有免费午餐。下表是按 10 lg(N) 算出来的对应关系,可以拿来快速估参数:

扩频因子 N处理增益相对带宽占用典型用途
78.5 dB7×短码验证、教学演示
6418.1 dB64×中等抗干扰链路
40026.0 dB400×强干扰环境、低信噪比接收
409536.1 dB4095×远距离扩频、测距

第一个取舍是增益与带宽。增益每涨 3 dB,带宽翻一倍。频谱资源紧张时不可能无限加码长,这时要么靠信道编码补增益,要么靠天线增益补链路预算。仿真里改一个数字就行,工程上改的是射频前端和频谱许可。

第二个取舍是码长与同步时间。捕获一个长度为 N 的码,串行搜索最坏要扫过 N 个相位,每个相位积分一个符号周期,总捕获时间正比于 N·Ta。码越长增益越高,冷启动越慢。工程上常用两级方案:先用短码快速捕获,再用长码精跟踪。

第三个取舍是仿真精度与运行时间。符号数从 100 提到 10⁵,误码率分辨率从 0.01 降到 10⁻⁵,但循环次数涨一千倍。我一般会先拿 100 个符号跑通链路看波形,确认判决正确后再把符号数拉到 10⁵ 出曲线,两轮跑完比一轮跑到底省时间。

验证方法上,最省事的一招是拿无噪声的理想信道跑一遍,误码率必须是零;再拿纯噪声信道跑一遍,误码率必须接近 0.5。这两头对上了,中间的曲线才有意义。如果无噪声都有误码,问题一定在同步或参数对齐;如果纯噪声误码率明显低于 0.5,说明判决器有偏置,多半是门限没取在零。

早些年我做这类链路仿真,习惯是先把所有参数写成一坨常量,改一个忘一个,最后曲线对不上理论值,查了两天才发现是滤波器截止频率还挂在旧的采样率上。从那以后我每次动采样率或载波频率,都会强制把 dt、滤波器归一化频率、判决窗口长度这三个量一起重算一遍,写在代码最上面做联动。这套习惯让我少走了不少弯路,希望帮到你。

这份 MATLAB 仿真设计里,从 m 序列生成、BPSK 调制到相关解扩和误码率统计的完整链路都在,代码虽然带着教学代码特有的松散,但每一段都能对上前面讲的机制,拿它改参数、加信道、换码型都是现成的起点。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询