资讯详情

资讯详情

MATLAB仿真对比m序列、Gold序列与Walsh码:扩频序列选型与性能分析

简介MATLAB实现的数字通信系统性能仿真资源面向通信工程与信号处理领域的研究者、工程师及学生聚焦M、Gold、Walsh序列在CDMA系统中的性能分析。资源包内含2个文件分别为MATLAB主程序.m与说明文档.md压缩包约4KB结构精简便于快速运行与理解说明文档概述了序列生成原理与仿真思路。已有156人学习浏览适合中高级通信专业学生与工程师。通过仿真可直观对比三种序列的自相关与互相关特性M序列具有尖锐自相关峰Gold序列具备更优互相关Walsh序列展现正交性可有效区分信道。借助信噪比、误码率等指标能够评估不同噪声与多用户干扰下的系统表现主程序还支持调整序列长度、信道模型等参数便于开展多组对照实验从而理解序列选择对系统容量、抗干扰能力及多址访问效果的影响为数字通信系统设计优化提供实用参考。1. 三种扩频序列选型难在哪这套MATLAB仿真就把答案直接跑给你看做数字通信仿真的人在序列选择上翻车概率比想象中高。m序列结构简单、自相关尖锐但可供分配的序列数量有限Gold序列组合多可优选对挑不好互相关就会失控Walsh码严格正交可一旦码片失步正交性就瞬间崩塌。这套MATLAB仿真资源把三种序列的生成、扩频调制、AWGN信道传输、相关解扩和误码率统计串成一条完整链路跑通一次就能直观看到每种序列在相同信噪比条件下的真实差异。适合刚接触扩频通信方向的研究生复现理论也适合需要快速验证序列性能的通信工程师做选型参考。接下来我按代码链路把每一段的设计逻辑和参数含义拆开讲顺带说明实际运行中容易踩的坑。2. 序列生成原理与MATLAB实现m序列、Gold序列、Walsh码差在哪三种序列在MATLAB里的生成方式差异很大对应的通信场景也完全不同。本章先从生成原理入手把每一类序列的代码写清楚再解释参数为什么这么设。理解了生成层面的差异后面搭建仿真链路时才能知道该在什么位置替换哪种序列。2.1 m序列LFSR反馈结构与初态设置的细节m序列的全称是最大长度线性反馈移位寄存器序列本质是由n级移位寄存器配合特定反馈多项式产生的周期为2^n-1的伪随机序列。它之所以被称为最大长度是因为n级寄存器理论上可以有2^n个状态去掉全零状态后最长周期就是2^n-1。下面这段代码生成一个5级m序列本原多项式取x^5 x^2 1对应LFSR抽头在第5级和第2级% m序列生成本原多项式 x^5 x^2 1周期 N 31 n 5; % 移位寄存器级数 N 2^n - 1; % m序列周期非零状态总数 reg [1 0 0 0 0]; % 初始状态注意不能是全零 m_seq zeros(1, N); % 存储m序列的0/1逻辑序列 for i 1:N m_seq(i) reg(5); % 取最高位作为当前输出 feedback xor(reg(5), reg(2)); % 反馈位抽头5和抽头2的异或 reg [feedback, reg(1:4)]; % 反馈值移入最高位其余右移 end % 映射为双极性信号0 - 11 - -1 m_bipolar 1 - 2 * m_seq;这段代码的核心逻辑是循环移位加反馈。每次迭代先把最高位保存为输出再把抽头位置的异或结果注入到最高位同时整个寄存器右移一位。feedback xor(reg(5), reg(2))这一行决定了序列的特性抽头位置必须对应本原多项式的非零系数。初态设置上有一个必须注意的细节LFSR一旦进入全零状态就无法跳出输出会恒为0。所以reg的初值不能是[0 0 0 0 0]任意非零组合都可以只是不同初态会让序列产生循环移位本质上是同一条序列的不同相位。实际工程里常用初态来区分不同小区或不同用户但要注意这对单条m序列的自相关性能无影响。关于抽头选择x^5 x^2 1是本原多项式这一点可以查表确认。如果随意挑几个抽头组合生成的序列可能不是最大长度周期会缩短这是仿真中比较隐蔽的坑。常见做法是先用MATLAB的gfprimfd函数验证多项式是否为本原多项式再写入代码。2.2 Gold序列优选对判定与循环偏移生成Gold序列的生成思路是用两条m序列做模2加。它的价值在于序列数量远超m序列——m序列只有有限几条而Gold序列可以通过循环偏移组合出2^n1条。但前提是两条m序列必须构成优选对。优选对的定义是两条周期相同的m序列它们的互相关函数只有三个取值且这三个值都在允许范围内。判断是否构成优选对不能凭肉眼判断要靠计算互相关函数% 判断两条m序列是否构成优选对 N 31; % 周期 m1 m_seq_1; % 第一条m序列0/1序列 m2 m_seq_2; % 第二条m序列0/1序列 % 转双极性后计算循环互相关 b1 1 - 2 * m1; b2 1 - 2 * m2; corr_vals zeros(1, N); for shift 0:N-1 b2_shift circshift(b2, [0, shift]); corr_vals(shift1) sum(b1 .* b2_shift); end % 输出互相关取值集合 unique_corr unique(corr_vals); disp(unique_corr);如果输出只有三个不同数值典型如-1、-9、7这种这两条m序列就是优选对可以放心拿去做Gold序列。如果输出的取值超过三个那就要换一组m序列重试。这个判断过程在所有Gold序列生成的教程里都有但很少有人提醒MATLAB里不同初态生成的m序列之间是否构成优选对需要逐对验证不能假设任意两条都满足条件。确认优选对之后生成Gold序列就很简单% 生成Gold序列两条优选对m序列模2加 g1 m_seq_1; % 第一条m序列 g2 circshift(m_seq_2, [0, 5]); % 第二条m序列循环偏移5位 gold_seq xor(g1, g2); % 模2加得到Gold序列 gold_bipolar 1 - 2 * gold_seq; % 双极性映射用于扩频这里的循环偏移参数是生成不同Gold序列的手段。偏移量从0到N-1每换一个偏移值就得到一条不同的Gold序列所以一组优选对可以生成N2条Gold序列。多用户仿真中给不同用户分配不同的偏移量即可区分用户。实际仿真时还有一个细节Gold序列的周期和参与生成的两条m序列完全一致均为N。这意味着码片速率不变的前提下Gold序列的扩频增益和m序列相同。很多人误以为Gold序列的扩频增益更高这是概念上的误区两者周期一样单位比特消耗的码片数一样扩频增益自然一样。2.3 Walsh序列Hadamard递归构造与正交性边界Walsh序列基于Hadamard矩阵生成核心特征是任意两条不同行的序列在周期内完全正交。Hadamard矩阵的递归构造规则是H(2N) [H(N), H(N); H(N), -H(N)]。% Walsh序列生成递归构造Hadamard矩阵 M 64; % 目标矩阵阶数对应64位Walsh码 H 1; % 1阶Hadamard矩阵初始化 for k 1:log2(M) H [H, H; H, -H]; % 每次迭代矩阵阶数翻倍 end % 取出第3行作为一条Walsh码 walsh_row H(3, :); % 双极性取值1/-1这段代码的递归逻辑需要一点线性代数直觉。每迭代一次矩阵尺寸翻倍同时保持行与行之间的正交性。H [H, H; H, -H]这条语句把当前矩阵复制四块拼成新矩阵右下角那块取负号这个负号是保证正交性的关键。关于Walsh序列有几个容易被忽略的边界条件。第一Walsh码的正交性只在完全同步的码片对齐条件下成立。如果发射端和接收端之间有任意一个码片的时间偏移两条Walsh码的相关值就不再是零干扰会直接显现。第二Hadamard矩阵的行之间存在顺序差异不同行对应的Walsh码频域特性不同在多径信道中某些行的抗衰落能力会差一些。第三Walsh码序列长度必须是2的幂次也就是说扩频因子只能是2、4、8、16、32、64这种值如果系统要求扩频因子是31或63Walsh码就完全不可用只能用m序列或Gold序列。理解了三种序列的生成方式和边界条件接下来就可以把它们放进完整的通信链路里跑仿真的。3. 完整仿真链路搭建发射端、信道模型与接收端解扩的每一步序列生成只是原材料真正的难点在于把扩频调制、信道传输、解扩判决和误码率统计串成一条能跑的链路。这一章我按发射端、信道、接收端三段拆解给出可直接运行的MATLAB实现并解释每个参数的影响。3.1 发射端扩频调制与三个关键参数发射端的工作可以分成三步产生随机数据比特、用扩频序列对每个比特扩展、将扩频后的码片序列调制到载波上。下面是完整的发射端代码% 发射端BPSK调制 扩频 bit_count 10000; % 仿真比特数 N 31; % 扩频增益m序列周期 fs 100e3; % 码片采样率 100 kHz fc 1e6; % 载波频率 1 MHz T_b N / fs; % 比特周期每个比特对应N个码片 data randi([0 1], [1, bit_count]); % 随机数据比特 data_bipolar 1 - 2 * data; % 双极性映射0-1, 1--1 % 扩频每个数据比特与完整序列周期相乘 m_seq generate_m_sequence(5); % 调用m序列生成函数 m_bipolar 1 - 2 * m_seq; % 转双极性 spread zeros(1, bit_count * N); for i 1:bit_count % 第i个比特扩展为N个码片 spread((i-1)*N 1 : i*N) data_bipolar(i) * m_bipolar; end % BPSK调制到载波 t_axis (0:length(spread)-1) / fs; Eb 1; % 归一化比特能量 A sqrt(2 * Eb / T_b); % 载波幅度 carrier cos(2 * pi * fc * t_axis); tx_signal A * spread .* carrier;三个关键参数需要重点解释。第一个是码片采样率fs它决定每个码片用多少个采样点表示这里设100kHz意味着每个码片只有1个采样点属于最简配置。如果接收端要做成形滤波或匹配滤波通常需要4到8倍过采样此时fs要调高到400kHz或800kHz。第二个是载波频率fc一般设为码片速率的整数倍这里1MHz是100kHz的10倍相干解调时混频产生的镜像频率能被低通滤波器干净滤除。第三个是比特能量Eb代码里归一化为1实际仿真中可以取任意正值因为它和噪声功率是一起换算的最终BER只取决于Eb/N0比值绝对大小无影响。扩频操作里用了循环遍历MATLAB里也可以用reshape和矩阵乘法加速但循环版本的逻辑更直观方便第一次跑通。每个数据比特和m_bipolar逐点相乘相当于把比特能量摊到N个码片上这就是扩频的本质。3.2 信道模型AWGN噪声功率计算与多径设置AWGN信道是整个仿真里最容易算错的地方。噪声功率的换算不是随便加一个randn乘以常数就行的必须从Eb/N0出发推导。接收端信号经过相干解调后进入基带判决噪声功率要和码片采样率关联起来。% AWGN信道按目标Eb/N0添加噪声 EbN0_dB 6; % 目标Eb/N0单位dB EbN0 10^(EbN0_dB / 10); % 转为线性值 N0 Eb / EbN0; % 噪声功率谱密度 % 关键噪声功率与采样率的关系 noise_power N0 * fs / 2; % 带通信道的实噪声功率 noise sqrt(noise_power) * randn(1, length(tx_signal)); rx_signal tx_signal noise;噪声功率为什么要乘以fs/2原因是时域离散噪声经过采样后功率谱密度分布在-Nyquist频率到Nyquist频率之间总带宽等于fs但实信号的频谱关于0频率对称等效单边带宽是fs/2。如果直接令noise_power N0实际噪声会被放大2倍BER曲线整体向右偏移约3dB。这是新手最容易踩的坑我在带人调试时至少有一半的BER曲线对不上理论值原因是噪声功率系数问题。多径信道相对复杂MATLAB自带的comm.RayleighChannel可以处理但参数设置上有讲究% 多径瑞利信道可选对比用 rayleigh_chan comm.RayleighChannel(... SampleRate, fs, ... PathDelays, [0, 1.2e-5, 2.5e-5], ...% 三径时延单位秒 AveragePathGains, [0, -2, -5], ... % 各径平均增益单位dB MaximumDopplerShift, 50); % 多普勒频移低速移动场景 rx_multipath rayleigh_chan(tx_signal.).;多径参数中时延和增益要尽量和实际信道条件匹配。PathDelays如果超过一个符号周期的整数倍会引入码间干扰此时单靠解扩无法完全消除需要加均衡器。MaximumDopplerShift设为50Hz对应步行场景车载场景要调到100-200Hz。初学者建议先跑AWGN信道确认链路无误后再切多径否则一旦BER不对很难定位是序列问题还是信道问题。3.3 接收端解扩相关运算与误码率统计接收端的核心是相干解调加相关解扩。相干解调需要本地载波与发送端同频同相仿真里默认理想同步。解扩的本质是相关运算接收信号与本地扩频序列做内积信号分量因相关而累积增益噪声分量因不相关而趋零。% 接收端相干解调 解扩 判决 rx_baseband rx_signal .* cos(2 * pi * fc * t_axis); % 混频解调 % 低通滤波混频后的高频分量简单滑窗平均即可 window_len 10; % 滤波器窗长经验值 b ones(1, window_len) / window_len; rx_filtered filter(b, 1, rx_baseband); % 去除滤波引入的群延迟 rx_filtered rx_filtered(floor(window_len/2)1:end); filtered_len length(rx_filtered); rx_filtered rx_filtered(1:floor(length(rx_filtered)/length(spread))*length(spread)); % 解扩每个比特区间内与本地序列相关累加 bit_soft zeros(1, bit_count); for i 1:bit_count start_idx (i-1)*N 1; end_idx i*N; rx_chip rx_filtered(start_idx:end_idx); % 相关累加等价于匹配滤波 bit_soft(i) sum(rx_chip .* m_bipolar); end % 判决软判决值大于0判为1原始映射1--1 rx_data_bipolar sign(bit_soft); rx_data (1 - rx_data_bipolar) / 2; % 误码率统计 ber sum(rx_data ~ data) / bit_count; fprintf(Eb/N0 %.1f dB, BER %.5f\n, EbN0_dB, ber);解扩这一步的数学含义是每个比特持续期间有N个码片接收到的每个码片都含有信号分量加噪声分量。乘以本地序列后N个码片中的信号分量方向一致因为发射端乘的同一个序列叠加后幅度变为原来的N倍也就是说信号能量变成N^2倍而噪声乘序列后方向随机叠加后能量约等于N倍。所以解扩后的信噪比提升了N倍这就是扩频增益。低通滤波器的窗长是经验值设小了滤不干净混频产生的高频分量设大了会引入符号间干扰。仿真时可以从5试到20看哪个值BER最低就选哪个。4. 性能对比与参数扫描三种序列在不同场景下的真实差异做完链路搭建接下来要回答一个核心问题三种序列在同一套系统里Performance差异到底有多大这需要通过对比仿真来验证而不是凭理论推导直接下结论。4.1 单用户AWGN场景BER曲线为何几乎重合又略有差异单用户AWGN是扩频通信的理想基准场景。理论上来讲BPSK调制下三种序列的BER完全一致因为它只取决于解调后比特信噪比序列本身不引入额外干扰。实际仿真中三条BER曲线会非常贴近但不完全重合。m序列在完全同步时解扩后每比特的软输出固定性能最接近理论Walsh序列在码片采样点恰好落在最佳位置时同样接近理论值但如果采样点偏移半个码片Walsh码的自相关旁瓣非零特性会导致性能轻微下降Gold序列因为互相关旁瓣的存在在噪声较低时偶尔会发生相关峰值错判BER曲线末端会出现微小平台。这个平台的来源值得展开说一下。Gold序列的自相关函数是四值/三值的在偏移不为零时相关值可能达到-9/31或7/31当噪声很小而本地序列同步出现微小偏差时主相关峰和旁瓣的差值变小判决裕度降低。4.2 多用户干扰场景正交性的价值与代价多用户仿真中给不同用户分配不同序列。用Gold序列时理论上用户间干扰受互相关上界限制只要用户数不超过序列总数干扰可控。用Walsh码时完全同步情况下用户间干扰为零这是它最大的优势。但Walsh的正交优势有个前提是同步精度。一旦两个用户的Walsh码之间有码片级偏移正交性就会被破坏产生多址干扰。下面的仿真代码演示了不同步情况下的性能变化% 多用户干扰仿真两个用户共享信道 user1_seq walsh_row_1; % 用户1的Walsh码 user2_seq walsh_row_2; % 用户2的Walsh码 data1 randi([0 1], [1, bit_count]); data2 randi([0 1], [1, bit_count]); % 用户2加入多址干扰幅度为用户1的一倍 spread_user1 reshape(repmat(data1, N, 1), 1, []) .* user1_seq; spread_user2 reshape(repmat(data2, N, 1), 1, []) .* user2_seq; % 用户2信号延迟一个码片模拟同步误差 sync_offset 4; spread_user2_synced [zeros(1, sync_offset), spread_user2(1:end-sync_offset)]; tx_signal_multi A_1 * spread_user1 .* carrier A_2 * spread_user2_synced .* carrier;这里的干扰幅度控制是重点。A_2相对A_1的大小代表干扰强度近远效应下A_2可以比A_1大几倍。如果Walsh码没失步无论A_2多大都不会干扰用户1一旦失步A_2越大用户1的BER恶化越明显。这个结论在验证异常定位时非常有用。4.3 扩频增益与Eb/N0参数扫描结果解读扩频增益和Eb/N0的关系也是仿真中经常被误解的点。扩频增益定义为比特速率与码片速率之比等于N。它改善的是抗干扰能力而不是理论BER曲线的斜率。BER曲线的斜率由调制方式决定BPSK就是那一条固定的理论曲线扩频只是把整个系统的工作区间沿着横轴平移。仿真中可以对不同N做参数扫描比如N分别取15、31、63看BER曲线变化% 参数扫描不同扩频增益下的BER对比 N_values [15, 31, 63]; % 三种扩频增益 EbN0_dB_range 0:2:8; % Eb/N0扫描范围 ber_matrix zeros(length(N_values), length(EbN0_dB_range)); for n_idx 1:length(N_values) N_cur N_values(n_idx); % 重新生成对应长度的m序列 m_seq_cur generate_m_sequence_for_period(N_cur); for ebno_idx 1:length(EbN0_dB_range) ber_matrix(n_idx, ebno_idx) simulate_link(N_cur, EbN0_dB_range(ebno_idx)); end end % 结果可视化略去绘图指令扫描结果通常呈现这样的规律扩频增益越大相同Eb/N0条件下BER越低但提升幅度随N增大逐渐收敛。原因是误码率的对数对信噪比线性敏感扩频增益等效为把实际信噪比乘上N倍在信噪比足够高时N增加带来的对数增益变小。实际工程选扩频增益还要看带宽占用N翻倍意味着带宽翻倍所以扩频因子选择是性能和资源的折中。5. 避坑与常见问题排查序列生成与仿真链路的五个关键雷区这一章列出我在这套仿真资源调试过程中反复遇到的5个问题按现象-原因-解决的方式记录很多问题不看源码根本定位不出来。5.1 m序列初态全零输出恒为零现象生成的m序列全部是0扩频后信号变成恒定电平BER曲线乱成一团。原因LFSR初始状态设置成了全零或者循环过程中寄存器误入全零状态。全零状态下反馈异或结果永远是0寄存器无法跳出。解决初始化时检查寄存器是否全零另外在反馈循环里加入状态检测一旦发现全零就强制注入非零值。常规做法是在函数开头加一行断言if all(reg 0) reg(1) 1; % 强制置为非零 end5.2 Gold序列优选对选错互相关峰值超标现象多用户仿真中用户间干扰严重即便没有噪声BER也无法降为零且随着用户数增加恶化明显。原因参与模2加的两条m序列不是优选对互相关函数出现超出允许范围的大峰值。解决生成Gold序列前务必用互相关函数做校验确认取值集合中只有三个数值。我在实际调试中遇到过取值集合有5个不同值的情况直接导致相关接收机判决裕度不足。建议把互相关校验写成一个独立函数每次换序列对就跑一次。5.3 Walsh码同步偏移正交性崩溃现象用Walsh码做多用户仿真时BER在所有Eb/N0区间都偏高且高信噪比时出现底噪平台。原因接收端本地Walsh码与发射端存在码片级偏移。Walsh的正交性建立在逐码片对齐的前提下偏移超出零容忍范围后两条看似正交的码序列实际相关值会变成非零。解决在接收端加入码同步搜索算法最简单的实现是让本地序列在几个偏移位置滑动取相关峰值对应的偏移量作为同步点。Walsh码场景里同步误差必须严格控制在1/4码片以内才算安全。5.4 误码率统计未去除瞬态曲线偏离理论值现象BER曲线在低Eb/N0区间波动剧烈高Eb/N0区间又明显高于理论值重复跑多次结果不稳定。原因仿真开始阶段滤波器的抽头缓存为空前几十个比特的输出不准确。如果把这些瞬态数据计入统计误码数会被污染。解决丢弃前100个符号再开始统计误码。% 丢弃瞬态的推荐写法 ber_valid_count bit_count - 2000; % 前2000比特丢弃 rx_data_valid rx_data(2001:end); data_valid data(2001:end); ber sum(rx_data_valid ~ data_valid) / ber_valid_count;5.5 扩频顺序与加噪声顺序颠倒性能不升反降现象AWGN信道下BER差于未扩频的BPSK让人怀疑扩频是否反而带来了劣势。原因有人把噪声在扩频前加入信号误以为随机化噪声更接近真实信道。但扩频对噪声没有抑制作用反而因为扩频过程把信号能量分散到N个码片接收端解扩后噪声被重新整合整个链路的等效信噪比并未改变。如果噪声添加位置或功率换算有问题BER比理论高是必然的。解决噪声必须在发射信号经过信道时添加也就是扩频和调制之后。% 正确的噪声添加顺序 tx_signal A * spread .* carrier; % 先扩频调制 rx_signal tx_signal sqrt(noise_power) * randn(1, length(tx_signal)); % 再加噪声6. 用眼图和星座图做最后一层验证仿真跑完不等于结果可信误码率曲线跑出来符合理论只能说明链路大致正确它掩盖了很多细节问题。扩频系统里最容易出现的情况是解扩后软输出的分布不均匀——某些比特区间内相关峰被压缩或者噪声底被抬高。这些信息BER曲线上看不出来但眼图和星座图一眼就能暴露。眼图的做法是把接收端解扩前的基带信号按符号周期切段等间距叠加显示。正常的BPSK眼图在采样点位置应该有一个清晰的张开区域睁开度越大噪声容限越高。如果眼图的上半部分和下半部分不对称说明载波相位同步有问题如果眼图中间有雾状拖尾说明码间干扰没有被滤干净。% 解扩前基带眼图绘制抽选部分段落 samples_per_bit N; % 每个比特N个码片采样 num_traces 64; % 显示的轨迹数量 for i 1:num_traces base_idx (i-1) * samples_per_bit 1; plot(1:samples_per_bit, rx_baseband(base_idx : base_idx samples_per_bit - 1)); hold on; end星座图则直接看解扩后软判决值的分布。理想情况下软判决值应该在±1附近聚成两团且距原点的距离远大于噪声的波动幅度。如果两团点之间的间隔小于噪声标准差说明扩频增益不够或者噪声功率计算偏高。% 解扩后星座图所有比特的软判决值 figure; plot(real(bit_soft), zeros(size(bit_soft)), x); xlabel(软判决值); ylabel(0); title(BPSK解扩后星座图);我个人的习惯是每次修改序列参数后三样东西必须重新验证一遍BER曲线、眼图、星座图。如果BER曲线对但星座图两团的间距不对称我会先检查本地序列和发射序列是否相位一致如果眼图上边缘模糊我会检查码片采样率是否过低需要过采样才能看清形态。这套仿真资源里眼图和星座图的绘图代码是现成的直接运行就能看到三种序列在相同条件下的直观差异。有一次我在调试一个多用户场景时BER曲线反复跑都偏高理论推断是同步问题怎么查都查不出来。后来画了星座图才发现本地序列和发射序列之间有1个码片的偏移软判决值分裂成四个簇而不是两个。换回正确同步后四簇变成两簇BER立刻恢复正常。从那以后我每次调序列相关场景都强制走一遍BER加眼图加星座图三件套没有例外。这套验证习惯帮我省下的排查时间以天计算希望也能帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →