☰
扩频通信中m序列与Walsh码:生成、扩频增益与多址干扰避坑指南
2026/10/14 16:07:39 网站建设 项目流程

简介:这份文档面向通信工程、无线通信课程学习者及CDMA系统入门研究者,系统梳理扩频序列中m序列与Walsh码的原理与生成方法,帮助读者理解码分多址的底层逻辑。资源为单个doc文档,压缩包约355KB,内容涵盖m序列的线性移位寄存器结构与反馈系数机制、Walsh码基于Hadamard矩阵的正交序列生成过程,并附有walshf1函数的Matlab实现代码,涉及Paley序、Walsh序及逆Walsh序矩阵的转换。文中还讨论了64阶Walsh序列在前向链路中W0至W63信道分配、1.2288Mc/S码片速率及多址干扰抑制的实际局限,并延伸介绍Gold序列的模2加生成思路。已有636人学习,适合需要对照理论推导与代码实现、快速掌握扩频码生成与应用的读者参考。

1. 扩频序列 m 序列与 Walsh 码:从两个序列的脾气说起

做扩频通信或者多址接入的工程师,迟早会撞上这两个名字:m 序列和 Walsh 码。一个管「把信号摊开、抗干扰、测距」,一个管「让多路信号正交、互不打架」。很多刚接触的同行会把它们混为一谈,觉得都是「伪随机码」,随便挑一个用就行,结果在解调端看到误码率居高不下,或者多用户场景下串扰严重,回头查半天才发现是序列选错了、相位没对齐、或者扩频增益算错了。

这篇笔记就围绕这两个序列展开:它们各自适合什么场景、生成逻辑怎么写、参数怎么定、工程上最容易翻车的地方在哪。如果你正在做直接序列扩频、码分多址、测距、同步或者信道化接收相关的开发,这篇内容可以直接拿去对照你的链路。我尽量把每一步落到可运行的代码和可核对的参数上,少讲空话。

2. m 序列:生成、本原多项式与扩频增益的账怎么算

m 序列(最长线性反馈移位寄存器序列)是扩频系统里最常用的伪随机序列之一。它的核心价值在于:由线性反馈移位寄存器(LFSR)产生,周期为 2^n - 1,自相关特性接近冲激函数,互相关在优选对之间也有较好表现。这意味着它在接收端做相关检测时,能给出尖锐的峰值,适合做同步和测距。

2.1 用 LFSR 生成 m 序列的最小实现

生成 m 序列的关键是选对反馈抽头,也就是本原多项式。下面是一个 Python 实现,用 4 级 LFSR 生成周期为 15 的 m 序列,反馈多项式取 x^4 + x + 1。

# m序列生成:4级LFSR,本原多项式 x^4 + x + 1 def generate_m_sequence(n_stages=4, taps=None, seed=1): """ n_stages: 寄存器级数 taps: 反馈抽头位置(从1开始计数),None则使用默认 x^4 + x + 1 seed: 初始状态,不能为0 """ if taps is None: taps = [4, 1] # 对应 x^4 + x + 1 state = seed period = (1 << n_stages) - 1 seq = [] for _ in range(period): # 输出最低位 seq.append(state & 1) # 计算反馈位:抽头位置异或 feedback = 0 for t in taps: feedback ^= (state >> (t - 1)) & 1 # 右移并注入反馈到最高位 state = (state >> 1) | (feedback << (n_stages - 1)) return seq seq = generate_m_sequence() print("周期:", len(seq)) print("序列:", seq) # 验证自相关:移位0时峰值应等于周期 def autocorr(s, shift): n = len(s) return sum(s[i] * s[(i + shift) % n] for i in range(n)) print("自相关(shift=0):", autocorr(seq, 0)) print("自相关(shift=1):", autocorr(seq, 1))

这段代码的逻辑说明:LFSR 每个时钟周期右移一位,抽头位置做异或后反馈到最高位。taps参数决定了本原多项式,选错抽头会导致周期变短,不再是 m 序列。seed不能为 0,否则寄存器会锁死在全零状态。运行后你会看到 shift=0 时自相关值为 15,shift=1 时为 -1,这正是 m 序列的典型特征。

参数选择上,级数 n 决定了周期和扩频增益。每增加一级,周期翻倍,处理增益增加约 3 dB。常见取值:n=7 周期 127,n=10 周期 1023,n=15 周期 32767。级数越大,抗干扰能力越强,但同步捕获时间也越长,因为接收端需要搜索的相位不确定性增加了。

2.2 本原多项式怎么选:别随手写抽头

本原多项式不是随便挑几个抽头就能用的。一个 n 级 LFSR 要产生最大长度序列,其特征多项式必须是本原多项式。工程上常用的做法是查表,而不是自己推导。下面列出几个常用级数对应的本原多项式(用八进制表示反馈抽头):

级数 n周期常用本原多项式(八进制)对应多项式
53145x^5 + x^2 + 1
7127203x^7 + x + 1
1010232011x^10 + x^3 + 1
153276760001x^15 + x + 1

如果你选了一个非本原多项式,比如 n=4 时用 x^4 + x^3 + x^2 + x + 1,生成的序列周期会远小于 15,自相关旁瓣也会变差。验证方法很简单:跑一遍生成代码,看周期是否等于 2^n - 1。如果不是,换多项式。

提示:实际工程中,接收端和发射端必须使用完全相同的本原多项式和初始相位,否则相关峰值会消失。相位同步是 m 序列应用中最容易出问题的一环。

2.3 扩频增益与抗干扰余量的计算

扩频增益(处理增益)的定义是:Gp = 10 * log10(码片速率 / 信息速率)。假设信息速率 1 kbps,码片速率 1.023 Mcps(对应 n=10 的 m 序列),则 Gp ≈ 30 dB。这意味着在解扩后,信噪比可以获得 30 dB 的改善。

但实际抗干扰余量还要扣除实现损耗、同步误差、多普勒等因素。我一般会留 3~6 dB 的余量。比如理论 Gp 是 30 dB,实际可用抗干扰能力按 24~27 dB 估算。如果干扰功率超过这个值,解扩后的信噪比仍然不够,误码率就会飙升。

另一个容易忽略的点是:m 序列的互相关特性并不理想。不同 m 序列之间的互相关峰值可能达到周期的 0.1~0.3 倍,在多用户场景下会造成多址干扰。所以 m 序列更适合单用户扩频或测距,多用户场景要配合优选对或者换用其他序列。

3. Walsh 码:正交性的来源与多址场景下的用法

Walsh 码的核心价值是正交性。在同步条件下,不同 Walsh 码之间的互相关为零。这让它成为 CDMA 前向链路、信道化、多路复用场景的首选。但 Walsh 码有一个致命弱点:它的自相关特性很差,不适合做同步和测距。所以工程上常见的组合是:用 m 序列做同步和扰码,用 Walsh 码做信道区分。

3.1 Hadamard 矩阵生成 Walsh 码

Walsh 码可以通过 Hadamard 矩阵递归生成。下面是一个 Python 实现,生成 8 阶 Walsh 码。

import numpy as np def hadamard(n): """递归生成 n 阶 Hadamard 矩阵,n 必须是 2 的幂""" if n == 1: return np.array([[1]]) h = hadamard(n // 2) return np.block([[h, h], [h, -h]]) def walsh_codes(order=8): """生成 order 个 Walsh 码,每个码长度为 order""" H = hadamard(order) codes = [] for i in range(order): # 将 +1/-1 映射为 1/0,方便后续处理 code = ((H[i] + 1) // 2).astype(int) codes.append(code) return codes codes = walsh_codes(8) for i, c in enumerate(codes): print(f"W{i}: {c}") # 验证正交性:任意两个不同码的互相关应为0 def cross_corr(a, b): # 映射回 +1/-1 计算 a_pm = 2 * a - 1 b_pm = 2 * b - 1 return np.sum(a_pm * b_pm) print("W0与W1互相关:", cross_corr(codes[0], codes[1])) print("W0与W7互相关:", cross_corr(codes[0], codes[7]))

逻辑说明:Hadamard 矩阵的每一行就是一个 Walsh 码。递归构造保证了任意两行正交。walsh_codes函数把 +1/-1 映射为 1/0,方便在数字电路中用异或操作实现。验证部分把码字映射回 +1/-1 后计算互相关,结果应为 0。

参数说明:order必须是 2 的幂,常见取值 8、16、32、64、128。阶数越高,可容纳的正交码越多,但每个码的长度也越长,扩频增益相应增加。在 CDMA 系统中,阶数通常等于一个扇区内的最大信道数。

3.2 Walsh 码的正交条件与同步误差的影响

Walsh 码的正交性有一个前提:所有码字必须严格对齐。如果接收端和发射端之间存在码片级偏移,正交性就会被破坏。假设偏移量为 τ 个码片,互相关值会从 0 上升到与 τ 相关的非零值。

下面这个实验可以直观看到偏移对正交性的影响:

def cross_corr_with_shift(a, b, shift): """计算带循环移位的互相关""" b_shifted = np.roll(b, shift) a_pm = 2 * a - 1 b_pm = 2 * b_shifted - 1 return np.sum(a_pm * b_pm) code_a = codes[0] code_b = codes[1] for shift in range(4): val = cross_corr_with_shift(code_a, code_b, shift) print(f"移位 {shift} 码片,互相关 = {val}")

运行结果会显示:shift=0 时互相关为 0,shift=1 时互相关变为非零值(对于 8 阶 Walsh 码,通常是 ±4 或 ±8)。这意味着在实际系统中,同步误差必须控制在远小于一个码片的范围内,否则多址干扰会显著上升。

工程上常用的做法是:用 m 序列或 Gold 序列做同步头,先把定时对齐到码片级甚至亚码片级,然后再用 Walsh 码做信道解调。同步精度一般要求优于 1/8 码片,具体取决于系统对多址干扰的容忍度。

3.3 多用户场景下 m 序列与 Walsh 码的分工

在一个典型的多用户扩频系统中,两者的分工是这样的:

功能推荐序列原因
同步与捕获m 序列自相关尖锐,便于定时估计
信道区分Walsh 码同步条件下完全正交
扰码m 序列或 Gold 序列降低相邻小区干扰,随机化信号
测距m 序列自相关峰值可精确反映时延

这个分工不是绝对的,但遵循这个思路可以避开大部分坑。我见过有同行直接用 Walsh 码做同步,结果相关峰很宽,定时精度差,误码率一直下不来。换回 m 序列做同步后,问题立刻缓解。

注意:Walsh 码的正交性只在同步条件下成立。异步系统中,Walsh 码的互相关性能甚至不如 m 序列的优选对。所以如果你的系统无法保证严格同步,不要指望 Walsh 码能提供干净的多址隔离。

4. 避坑与排查:序列用错时系统会怎么表现

这一章记录几个我在实际调试中遇到的典型问题,按「现象 → 原因 → 解决」整理。如果你正在调试扩频链路,可以对照排查。

4.1 相关峰消失或峰值远低于预期

现象:接收端做相关检测时,峰值不明显,或者峰值位置随机跳动。

原因:最常见的是本原多项式不匹配。发射端和接收端用了不同的抽头,导致生成的 m 序列不同。另一种可能是初始相位没有对齐,接收端搜索的相位范围不够。

解决:先确认两端的本原多项式和级数完全一致。然后在接收端做全相位搜索,确认峰值出现在哪个相位。如果峰值存在但偏低,检查是否有频偏导致相关峰分裂。频偏超过码片速率的 1/10 时,相关峰会明显展宽和降低。

4.2 多用户串扰严重,误码率随用户数上升

现象:单用户时误码率正常,增加用户后误码率快速恶化。

原因:如果用的是 m 序列做多址区分,互相关峰值较高,用户数增加后多址干扰累积。如果用的是 Walsh 码,可能是同步误差导致正交性退化。

解决:检查同步精度,确保定时误差小于 1/8 码片。如果同步没问题,考虑换用 Gold 序列或正交可变扩频因子码。另外,加扰可以随机化干扰,但不能消除干扰,只能改善统计特性。

4.3 扩频增益算出来够用,实际抗干扰能力不足

现象:理论计算处理增益 30 dB,但干扰功率上升到 20 dB 时误码率就超标了。

原因:理论增益没有扣除实现损耗。包括:滤波器带外抑制不足、ADC 量化噪声、本地振荡器相位噪声、同步误差引起的相关损失。这些因素加起来可能吃掉 6~10 dB。

解决:在链路预算中留足余量。我一般按理论增益的 70%~80% 估算实际抗干扰能力。另外,检查射频前端的线性度,强干扰下如果 LNA 或混频器进入非线性区,扩频增益再高也没用。

4.4 Walsh 码阶数选高了反而不好

现象:为了容纳更多用户,选了 128 阶 Walsh 码,结果每个用户的扩频增益上去了,但同步时间变长,系统响应变慢。

原因:阶数越高,码长越长,同步搜索的相位不确定性越大。同时,高阶 Walsh 码的码片速率更高,对射频带宽和 ADC 采样率的要求也更高。

解决:根据实际用户数和同步时间要求折中。如果用户数不多,没必要追求高阶 Walsh 码。另外,可以用可变扩频因子,让不同业务使用不同阶数,兼顾容量和同步速度。

4.5 忽略直流分量导致相关峰偏移

现象:相关峰位置有固定偏移,或者峰值附近出现不对称的旁瓣。

原因:m 序列的 0/1 映射如果不做直流平衡处理,序列中存在直流分量,经过相关器后会产生固定偏移。Walsh 码如果映射不当,也会引入直流。

解决:在生成序列后,把 0/1 映射为 +1/-1 再做相关。或者在发射端做直流消除。这个坑很隐蔽,因为频谱上看不出来,只有相关峰的形状会暴露问题。

5. 进阶技巧:用互补序列和过采样把定时精度再提一档

前面讲的都是基础用法。如果你已经把 m 序列和 Walsh 码跑通了,但定时精度还差一点,或者多址干扰还想再压一压,可以试试下面两个技巧。

5.1 互补序列对消旁瓣

m 序列的自相关旁瓣虽然低,但不是零。在强干扰或低信噪比下,旁瓣可能被误判为峰值。一个常用的技巧是使用互补序列对:生成一对序列,它们的自相关旁瓣幅度相等、符号相反,叠加后旁瓣抵消,主瓣增强。

具体做法是:取一个 m 序列 s,构造它的互补序列 s',使得 s 和 s' 的自相关函数之和在非零移位处为零。接收端分别做相关,然后相加。这样主瓣幅度翻倍,旁瓣被抑制。

def complementary_pair(seq): """构造简单互补对:原序列和其取反序列""" s1 = seq s2 = [1 - x for x in seq] return s1, s2 def autocorr_sum(s1, s2, max_shift): """计算互补对的自相关之和""" n = len(s1) result = [] for shift in range(max_shift): r1 = sum((2*s1[i]-1) * (2*s1[(i+shift)%n]-1) for i in range(n)) r2 = sum((2*s2[i]-1) * (2*s2[(i+shift)%n]-1) for i in range(n)) result.append(r1 + r2) return result s1, s2 = complementary_pair(seq) sum_corr = autocorr_sum(s1, s2, 8) print("互补对自相关之和:", sum_corr)

运行后你会看到,除了 shift=0 处峰值翻倍,其他移位处的值被压得很低。这个技巧在雷达测距和同步系统中很实用,代价是需要发射两路信号或者做两次相关,资源换性能。

5.2 过采样提升定时分辨率

m 序列的相关峰宽度等于一个码片。如果只用 1 倍采样,定时精度最多到码片级。想要亚码片精度,需要对接收信号过采样,比如 4 倍或 8 倍,然后在相关峰附近做插值。

def oversample_corr(seq, rx_signal, os_factor=4): """过采样相关:rx_signal 是过采样后的接收信号""" n = len(seq) seq_pm = np.array([2*x-1 for x in seq]) # 对本地序列做零阶保持上采样 seq_up = np.repeat(seq_pm, os_factor) corr = np.correlate(rx_signal, seq_up, mode='valid') return corr # 模拟:发射序列过采样后加噪声 tx = np.repeat([2*x-1 for x in seq], 4) rx = tx + 0.5 * np.random.randn(len(tx)) corr = oversample_corr(seq, rx, 4) peak_idx = np.argmax(corr) print("峰值位置:", peak_idx, "对应码片偏移:", peak_idx / 4)

过采样后,相关峰的位置可以精确到 1/4 码片。如果配合抛物线插值,还能进一步细化。代价是计算量按过采样倍数增加,实时系统中需要评估 DSP 或 FPGA 的资源占用。

我一般会在同步阶段用过采样,一旦锁定就降到 1 倍采样跟踪,这样兼顾精度和资源。另外,过采样对 ADC 采样率有要求,前端设计时就要留够带宽。

5.3 把 Walsh 码用在信道估计上

Walsh 码的正交性除了做多址,还可以做信道估计。在发送端,把导频符号用不同的 Walsh 码扩频后叠加发送;接收端用对应的 Walsh 码解扩,就能分离出各条径的信道响应。这个方法在多天线系统中很常见。

具体步骤:选择一组正交 Walsh 码,每个天线或每个数据流分配一个码;导频符号经过 Walsh 扩频后叠加;接收端用相同的 Walsh 码做解扩,得到各流的信道估计。由于 Walsh 码正交,流间干扰被抑制。

需要注意的是,这个方法同样依赖同步。如果各流之间存在定时偏移,正交性退化,信道估计精度会下降。所以定时同步模块要做得足够稳。

最后说一个我自己的习惯:每次调试扩频链路,先单独验证 m 序列的自相关峰,再验证 Walsh 码的正交性,最后把两者串起来跑。不要一上来就调整个系统,否则出了问题你分不清是序列生成错了、同步没对齐、还是射频前端饱和了。分步验证虽然慢一点,但省下的排查时间远超那点前期投入。希望帮到你。

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

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

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

立即咨询