ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

MATLAB CDMA链路仿真:从扩频码到BER与功率控制

MATLAB CDMA链路仿真:从扩频码到BER与功率控制 简介面向通信工程、电子信息类专业学生与初学者的一份MATLAB课程设计仿真分析文档围绕CDMA码分多址通信系统的建模、仿真与性能评估展开可帮助读者在缺少硬件平台的情况下理解多址接入原理并完成课程设计或论文写作。压缩包内共1个doc文件约435KB内容为完整的设计报告章节涵盖绪论、CDMA发展现状与趋势、基本模型、卷积编码与扩频、调制、信道传输、解调恢复以及结果分析等模块并给出对应MATLAB仿真语句与参数设置说明中英文摘要与关键词齐备结构接近正式毕业论文便于直接参考行文框架与模块划分。文中还结合AWGN等信道条件讨论系统抗干扰能力指出单用户场景下即使在人为与物理噪声干扰中仍可准确恢复数据。目前已有146人学习下载适合需要快速搭建CDMA仿真流程、对照参数与结论的读者使用。1. CDMA 系统仿真的价值到底在哪里CDMA 这套东西纸上推公式谁都会扩频增益 10log10(SF)相关接收Q 函数算误码率。但真到工程里理论曲线和实测之间总会差出一截——正交码在异步下互相关泄漏、远近效应把弱用户直接压死、功率控制环路跟不上深衰落这些在公式里看不见只有把链路搭起来跑一遍才会暴露。MATLAB 恰好适合干这件事既有现成的通信工具箱也有足够的底层可控性能让人从 PN 序列生成一路调到 BER 曲线中间每一步都能抓出来看波形、看星座、看功率谱。这篇文章面向做通信课设的同学和刚转链路级仿真的工程师按码 → 扩频 → 信道 → 接收 → 多用户的顺序展开每一步都给出能直接跑的代码和参数取值理由。2. 扩频码的 MATLAB 生成m 序列、Gold 序列与 Walsh 码2.1 为什么 CDMA 里至少需要两套码刚接触的人容易把扩频码当成一个东西实际上 CDMA 链路里至少有两个层次。第一层是信道化码负责把同一小区内不同信道或不同用户区分开要求严格正交Walsh-Hadamard 码就是干这个的。第二层是扰码负责把不同小区、不同基站区分开要求互相关低而不是正交m 序列和 Gold 序列是典型选择。这两层码的数学性质完全不同。Walsh 码的正交性只在符号级对齐时才成立一旦引入随机时延——也就是异步场景——正交性立刻退化这正是后面多址干扰的来源。扰码则相反它不追求正交只要任意两条码在任意相对时延下的互相关都足够小让接收端做相关时不被别的小区淹没即可。理解这一点仿真里的很多反直觉结果就顺了同步单径下 Walsh 码的 MAI 等于零BER 曲线和单用户完全重合一旦把时延加进去曲线立刻抬起来。不用纠结 matlab 下载安装教程里那些版本选择近几个大版本的通信工具箱 API 基本稳定直接装完开工即可。2.2 用 LFSR 生成 m 序列的最小实现m 序列本质是最大长度线性反馈移位寄存器序列周期 2^m - 1。用 MATLAB 写出来只有十几行function seq gen_mseq(taps, m, N) % taps: 反馈抽头位置从1开始如 [4 1] 对应 x^4 x 1 % m : 移位寄存器级数决定周期 2^m-1 % N : 输出码片数一般取整数倍周期 reg [1 zeros(1, m-1)]; % 初态非全零即可 seq zeros(1, N); for n 1:N seq(n) reg(end); % 输出末级 fb mod(sum(reg(taps)), 2); % 模2求和作为反馈 reg [fb reg(1:end-1)]; % 右移一位反馈填入首位 end seq 2*seq - 1; % 0/1 映射为 -1/1方便做乘法扩频 end逻辑很直白每一步先读末级作为输出再把抽头位置的寄存器值模 2 相加作为新输入整体右移。最后一步映射成双极性是为了让扩频变成纯乘法省掉异或判断。参数上有两个坑。taps必须是本原多项式对应的抽头否则周期达不到 2^m-1序列会提前进入短循环。常用的几个m4 用 [4 1]m5 用 [5 2]m7 用 [7 1]m10 用 [10 3]。m一旦确定周期就定死了N取周期整数倍可以在做相关时得到干净的周期性自相关峰。2.3 Walsh-Hadamard 码与正交性的数值验证H hadamard(64); % 64 阶 Walsh 码每行一个码字 G H * H / 64; % 归一化互相关矩阵 offdiag max(abs(G - eye(64)), [], all); fprintf(最大非对角元素: %.3e\n, offdiag); % 应接近 2.2e-16即数值零这段代码的价值在于把正交落成了可打印的数字。如果打印出来不是 1e-15 量级多半是阶数写成非 2 的幂了hadamard 对非 2 的幂支持有限会静默返回错误维度。码类型长度主要用途同步要求相关特性m 序列2^m-1扰码、PN 参考低自相关双值互相关不定Gold 序列2^m-1扰码族低互相关三值峰值有界Walsh 码2^k信道化高需符号对齐完全正交2.4 Gold 序列族的生成与选择Gold 码由一对优选 m 序列的循环移位模 2 加得到。双极性表示下模 2 加等价于相乘代码很紧凑s1 gen_mseq([5 2], 5, 31); % 优选 m 序列之一 s2 gen_mseq([5 4 3 2], 5, 31); % 另一个抽头需与其构成优选对 gold zeros(31, 31); for d 0:30 gold(d1,:) s1 .* circshift(s2, [0 d]); % 移位后逐点相乘 end产出的 31 条序列就是一个 Gold 码族。选码时不要随机挑最好先算出整个码族的互相关矩阵挑互相关峰值最小的那几条给相邻小区用C gold * gold / 31; % 31x31 互相关 C(logical(eye(31))) 0; % 去掉自相关对角线 [maxCC, idx] max(abs(C(:))); fprintf(最大互相关 %.3f, 位置 %d\n, maxCC, idx);理论上的互相关峰值被约束在 -1、-t(m)、t(m)-2 三个值上其中 t(m) 1 2^floor((m1)/2)。m5 时 t9所以互相关绝对值不会超过 9/31 ≈ 0.29比随机二值序列好得多。3. 单用户 CDMA 链路的 MATLAB 实现从扩频到 BER 曲线3.1 链路结构设计与参数取值仿真之前先把参数定下来比边写边改省事得多。下面这套取值是课设和验证里的常见配置参数取值选取理由扩频因子 SF64与 Walsh 码长一致扩频增益 18.06 dB信息速率9.6 kbps经典速率便于与教科书曲线对照码片速率614.4 kchip/s等于 SF × 信息速率调制方式BPSK理论 BER 有闭式解便于校准信道AWGN单径先排除干扰标定基线接收相干相关接收与扩频码做匹配滤波扩频增益换算成 dB 就是 10log10(64) ≈ 18.06 dB。这个数字的意义是即使解扩前 SNR 是负的解扩后仍能正过来。3.2 发送端向量化的扩频实现SF 64; Nbits 1e5; % 传输比特数 codeBook hadamard(SF); pn codeBook(1, :); % 本用户扩频码 data randi([0 1], 1, Nbits); % 随机比特流 sym 2*data - 1; % BPSK: 0--1, 1-1 tx kron(sym, pn); % 逐符号扩频这里的关键是kron。它在数学上是 Kronecker 积实现上等价于每个符号复制 SF 份再与码字逐点相乘。相比双重 for 循环速度差两个数量级。Nbits 1e5、SF 64 时产生的 tx 长度是 640 万double 占约 50 MB普通笔记本内存完全够。3.3 AWGN 加噪Eb/N0 到噪声方差的换算这一步是最容易出错的地方。很多人直接调awgn(tx, EbN0_dB, measured)看起来简洁实则隐患很大measured会按信号实际功率反推噪声一旦发送功率因为某些原因变化Eb/N0 的定义就跟着漂了曲线对不上理论值。稳妥的做法是手工换算把能量关系写死EbN0_dB 0:2:10; ber zeros(size(EbN0_dB)); for k 1:length(EbN0_dB) EbN0_lin 10^(EbN0_dB(k)/10); % 码片幅度为1时每比特包含 SF 个码片故 Eb SF % 单边噪声功率谱密度 N0 SF / EbN0_lin % 双边实噪声每维方差 N0/2 noiseVar SF / (2 * EbN0_lin); noise sqrt(noiseVar) * randn(size(tx)); rx tx noise; % ... 解扩判决 end推导链条是码片能量 Ec 1因为幅度 ±1每比特能量 Eb SF × Ec SF由 Eb/N0 定义反解出 N0 SF / EbN0_lin实高斯噪声每维方差为 N0/2。这条链子写清楚之后任何 SF 下都不会算错。3.4 解扩、判决与 BER 统计rxSym reshape(rx, SF, []). * pn. / SF; % 一个符号周期内相关累加 rxBit rxSym 0; % BPSK 门限判决 [~, ber(k)] biterr(data, rxBit); % 误比特率reshape(rx, SF, [])把长向量折成 SF × Nbits 的矩阵每一列恰好是一个符号的码片。转置后左乘 pn 的转置得到的就是每个符号位置的相关值。除以 SF 是归一化让判决门限回到 0正好对应 BPSK 的最大似然判决点。biterr返回误比特数和误比特率第一个输出错误数在后面判断统计置信度时非常有用。3.5 仿真曲线与理论值的对照theory qfunc(sqrt(2 * 10.^(EbN0_dB/10))); semilogy(EbN0_dB, ber, o-, EbN0_dB, theory, k--); grid on; xlabel(E_b/N_0 (dB)); ylabel(BER); legend(仿真, 理论 Q(\surd(2E_b/N_0)));理论上几个锚点可以作为快速验证Eb/N0 0 dB 时 Q(√2) ≈ 7.9e-24 dB 时 Q(2.24) ≈ 1.25e-28 dB 时 Q(4.0) ≈ 3.2e-5。Eb/N0 (dB)理论 BER仿真 BER1e6 比特07.87e-2与理论偏差 5%41.25e-2与理论偏差 8%83.17e-5需 1e7 比特才稳否则抖动大如果仿真点明显低于理论曲线比如在 8 dB 处跑出 1e-6先怀疑噪声方差算小了或者数据比特太少导致统计涨落。如果明显高于理论检查解扩有没有漏掉归一化的 /SF这一项漏了会让相关值放大 64 倍判决门限全乱。4. 多用户场景MAI、远近效应与功率控制的 MATLAB 验证4.1 同步正交下的零 MAI到底是什么很多课设做到多用户就卡住加了 8 个用户每个用一条 Walsh 码结果 BER 曲线和单用户一模一样怀疑代码写错了。其实没写错——在同步、单径、符号级对齐的理想条件下Walsh 码两两正交别的用户经过本用户码相关后贡献恰好为零MAI 严格等于 0。真正让 CDMA 曲线塌下来的是两个条件被破坏一是异步用户到达基站的时间不对齐二是多径同一用户的不同径对 Walsh 码的时延不同。这两者都会破坏正交性产生残余干扰。仿真要想复现 MAI必须显式把这些条件加进去。4.2 构造一个能体现 MAI 的多用户上行模型K 8; % 用户数 SF 64; codes hadamard(SF); userCode codes(1:K, :); % 每个用户分一条 Walsh 码 amp [1 1 1 1 1 1 1 20]; % 第8个用户离基站很近功率大20倍 delay randi([0 SF-1], 1, K); % 每个用户随机码片级时延破坏同步 frameLen Nbits * SF; txAll zeros(K, frameLen SF); for u 1:K d randi([0 1], 1, Nbits); s 2*d - 1; txAll(u, delay(u)1 : delay(u)frameLen) amp(u) * kron(s, userCode(u,:)); end rxSum sum(txAll, 1); % 各用户信号在基站侧叠加delay这一行是整个仿真的转折点。只要它不全为零Walsh 码的正交性就不再成立。amp里第 8 个用户的 20 倍功率模拟的是离基站很近的强用户这是典型的远近效应场景。接收端仍然只用用户 1 的码做相关noiseVar SF / (2 * 10^(EbN0_dB/10)); rx rxSum(1:frameLen) sqrt(noiseVar) * randn(1, frameLen); y reshape(rx, SF, []). * userCode(1,:). / SF;对比有无时延两种设置下的 BER就能看到 MAI 的破坏力时延全零时曲线贴着理论线加入随机时延后弱用户的 BER 会抬高好几个数量级。4.3 功率控制的迭代实现功率控制的目标很朴素让所有用户到达基站时的接收功率尽量相等把 20 dB 的功率差压到 1 dB 以内。工程上用闭环迭代实现仿真里可以写成一个简化版targetSINR_dB 7; % 目标信干噪比 pwr ones(1, K); % 各用户发射功率初始相等 for iter 1:20 rxAll zeros(K, frameLen SF); for u 1:K rxAll(u, delay(u)1 : delay(u)frameLen) ... pwr(u) * amp(u) * kron(2*randi([0 1],1,Nbits)-1, userCode(u,:)); end sig sum(rxAll, 1); for u 1:K y_u reshape(sig, SF, []). * userCode(u,:). / SF; % 简单估计把相关输出的均值平方当作信号方差当作干扰加噪声 sinr_est mean(y_u).^2 / max(var(y_u), 1e-12); % 按目标与实际之比开方调整功率0.5 次方是为了平滑收敛 pwr(u) pwr(u) * (10^(targetSINR_dB/10) / sinr_est)^0.5; end end收敛性的关键在于指数 0.5直接用比值会在目标附近来回震荡取平方根相当于给调整步长加了个阻尼。迭代 20 次后pwr会自发分化——强用户降功率弱用户升功率最后到达基站的功率大致齐平。场景弱用户到达功率强用户到达功率弱用户 BER 量级无功率控制1×20×接近 0.5链路不可用有功控20 次迭代≈ 1×≈ 1.2×回到 1e-2 量级表格里的具体数字随随机种子变化但趋势是稳定的不开功控时最弱用户基本被打成盲猜开了之后整条曲线能压回单用户基线附近几个 dB 以内。4.4 多用户检测从匹配滤波到解相关单用户检测把其他用户一律当噪声容量上不去。多用户检测的思路是联合处理所有用户的匹配滤波输出。解相关检测是最简单的一种代码只有几行R userCode * userCode. / SF; % K×K 码互相关矩阵 R R 1e-6 * eye(K); % 对角加载防止病态 Y zeros(K, Nbits); for u 1:K Y(u,:) reshape(rx, SF, []). * userCode(u,:). / SF; end dHat sign(inv(R) * Y); % 解相关后逐用户判决R在严格正交时是单位阵解相关退化成匹配滤波时延破坏正交后R出现非对角元素取逆相当于把 MAI 从观测里减掉。代价是同时放大了噪声尤其在用户数接近 SF 时噪声放大非常严重。对角加载1e-6*eye(K)是数值上的常规操作避免R接近奇异时求逆爆掉。往上一档还可以试 MMSE 检测把噪声方差也算进去做加权求逆性能和解相关各有胜负取决于 Eb/N0 落在哪个区间。5. 让仿真跑得动、跑得准CDMA 链路仿真的几个实用技巧5.1 向量化与并行的加速比实测链路级仿真的瓶颈几乎全在循环次数上。把发端和解扩都向量化之后还可以用parfor把 Eb/N0 扫描并行化EbN0_dB 0:1:10; ber zeros(size(EbN0_dB)); parfor k 1:length(EbN0_dB) ber(k) runOnePoint(EbN0_dB(k), 1e6); % 每个点独立跑互不依赖 endparfor有几个硬性约束循环体内部不能依赖前一次迭代的变量循环变量会被切片随机数种子要按k单独设定否则每次跑出来的点不一样曲线不可复现。runOnePoint内部第一行写rng(1000k, twister)就能解决。5.2 跑多少比特才够BER 的统计置信度BER 1e-4 时如果只跑 1e5 比特期望错误数是 10 个误差棒大到没法看。经验公式是让期望错误数至少到 100N_bits ≥ 100 / BER_target目标 BER建议最小比特数期望错误数1e-21e41001e-31e51001e-41e61e710010001e-51e7 以上建议改用重要性采样走到 1e-5 以下直接蒙特卡洛会变得很贵这时可以考虑重要性采样或者把 Eb/N0 曲线只画到 8 dB 就收手——超过这个点已经远离实际工作区间了。5.3 固定随机种子并保存中间量rng(20240501, twister); % 全局种子保证结果可复现 % ... 仿真 ... save(cdma_ber.mat, EbN0_dB, ber, SF, Nbits, K);把 SF、Nbits、K 一起存进去是个好习惯。过几天回头看曲线偏了第一件事就是确认这些参数和当时一致。只存 ber 数组事后基本没法复现。5.4 用频谱图确认扩频真的发生了扩频的效果在时域上看不出来必须转频域。pwelch(tx, [], [], [], centered)画出的功率谱应该明显比未扩频的信号宽 SF 倍且主瓣平坦。如果谱形和未扩频时一样多半是kron的顺序写反了——kron(pn, sym)会把整个比特序列复制 SF 遍得到完全不同的波形。一个简单的判别方法fprintf(扩频前后长度比: %.1f (应等于 SF%d)\n, ... length(tx)/Nbits, SF);长度比只有在 1 和 SF 两个值之间写错了立刻现形。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表