
简介CDMA码分多址技术是第三代3G移动通信系统的核心技术这份仿真资源包面向通信工程、电子信息专业的本科与研究生以及需要快速理解扩频通信原理的硬件或算法工程师帮助完成从码片序列生成、扩频调制、信道叠加到RAKE接收解扩的全流程建模与分析。压缩包共9个文件、约626KB体量虽小但功能完整包含三个MATLAB脚本分别完成伪随机码片序列生成、下行链路RAKE接收、时变多径信道模拟、两个C语言源文件实现维特比译码与卷积编码、配套DLL动态库、仿真数据文件及DOC技术文档可对照原理直接阅读和运行调试。已有119人学习下载。通过这套资料读者可直接运行完整CDMA下行链路仿真直观观察用户码片区分、多用户干扰抑制、RAKE分集合并等关键机制技术文档系统梳理了CDMA原理、优势及MATLAB仿真步骤适合作为通信原理课程设计、毕业设计或3G系统研究的参考起点。1. CDMA仿真包能做什么从PN码到误码率曲线的完整闭环拿到“CDMA技术说明及仿真”这类以 .rar 打包的Matlab项目大部分人是冲着两个目标来的一是搞懂CDMACode Division Multiple Access码分多址在3G通信里到底怎么工作二是想用Matlab把“扩频—加噪声—解扩—解调”这条链路跑通亲眼看到误码率曲线随信噪比变化的趋势。我最初接触这类仿真包时最深的感受是样例代码容易跑但想改参数、换场景比从零写还难。因为CDMA的坑不在“扩频”这个单一动作而在码同步、多用户干扰和功率控制这些连环环节。这篇笔记我会按自己的复现路径把这个仿真方向拆开讲清楚让你不光能跑通还能改出自己想要的结果。适合通信专业学生、初入3G物理层研发的工程师以及任何想用Matlab做无线通信系统级仿真的人。2. 为什么用Matlab仿真CDMA三个绕不开的核心原理2.1 扩频码与正交性Walsh码和m序列到底谁管谁CDMA的本质是“码分”也就是用不同的扩频码区分用户。在Matlab仿真里最常见的两个码是Walsh码和m序列最长线性反馈移位寄存器序列。Walsh码是正交码长度是2的幂比如64、128用于前向链路区分同一小区内的用户码片严格对齐时互相关为0这是“正交”的数学含义。m序列是伪随机码自相关特性尖锐用于扰码和反向链路因为反向链路用户难以严格同步伪随机码的统计独立性比严格正交更实用。很多新手把这两种码混在一起以为反正都是扩频。我在仿真里会这样区分需要“用户间互不干扰”且能保证同步的场景用Walsh比如仿真一个基站下多个用户的下行需要“抗多径和抗截获”的场景用m序列比如仿真移动台的上行。Matlab里生成Walsh码直接用hadamard(n)取一行生成m序列则用comm.PNSequence或自己写LFSR函数。不要小看这一步选码后面误码率曲线的天花板全在码的性质上。2.2 信道模型AWGN与多径衰落下的扩频增益仿真的第二步是把扩频后的信号扔进信道。最简单的信道是AWGN加性高斯白噪声只加噪声不改变信号形状。这时CDMA的扩频增益体现在解扩过程把带宽重新压缩回信息带宽信噪比得到提升提升倍数约等于处理增益也就是码片速率除以符号速率。比如符号速率1.2288 Mcps、信息速率9.6 kbps处理增益约21 dB。在Matlab里awgn函数可以方便地把信号加上指定信噪比的噪声但要注意信噪比的定义是每符号能量还是每比特能量这直接决定误码率曲线横轴是Eb/N0还是Es/N0。多径衰落则是另一个难度信号经过几条不同时延的路径到达接收机码片对齐被破坏正交性下降产生码间干扰和用户间干扰。这时仿真里要加入带抽头延迟线的信道模型例如comm.RayleighChannel。我一般会先用AWGN跑通再切到衰落信道否则连问题出在哪都分不清楚。记住一句话AWGN测的是编码和扩频方案的下限衰落信道测的是接收机算法的上限两个都跑通才算完整。2.3 解扩与RAKE接收仿真主循环里的关键回路发射端是“信息比特 → 扩频 → 加扰 → 调制”接收端反过来“解调 → 解扰 → 解扩 → 判决”。RAKE接收机是CDMA的标志性技术它利用多径分量把不同时延的路径分别相关解扩再按最大比合并。Matlab里实现RAKE通常需要自己写多路相关器每路用不同的延迟对准本地PN码输出乘以权重后合并。这个回路不复杂但非常容易在延迟对齐和权重计算上出错。我在仿真中会先做一个单径的“解扩判决”模块确认无误码率问题后再扩展成多径。如果你拿到的包里已经有 RAKE 的实现别急着直接用先把它拆开确认每路的延迟变量是不是以码片为单位的整数倍。曾见过一个例程里延迟用了采样点数的序号结果换了过采样率后全部错位这个坑会在后面的避坑章细说。3. 把仿真包跑起来目录结构、初始化参数与主循环3.1 解压后先做三件事识别脚本、函数、数据文件拿到.rar压缩包第一步不是双击运行而是先解压到工作目录然后用dir或ls列出所有文件。常见做法是包里至少包含三类文件一个主脚本比如cdma_sim.m或main.m一组被调用的函数文件扩频、解扩、信道等以及一组设置参数的初始化脚本或数据文件.mat。先用type命令或编辑器逐个打开主脚本在文件头找%注释说明快速建立“谁调用谁”的关系。我一般会先把所有.m文件的文件名列出来再搜索主脚本里的函数调用语句。比如出现了walsh_code(64, user)和rake_receive(...)就去对应文件看输入输出。这套做法能帮你快速判断这个仿真包是“演示型”还是“工程型”。演示型只跑一条曲线工程型会留好参数接口。下面的清单是常见的文件分布不同包略有差异。常见文件作用我关注的点cdma_main.m主入口设置全局参数并循环是否写清了 Eb/N0 范围和用户数spread.m/despread.m扩频与解扩函数码片序列是复用的还是每次重新生成channel_model.m信道AWGN或多径是否包含路径时延与增益向量pn_gen.mm序列生成器寄存器初始状态是否可调params.m或setup.m参数初始化是否存在硬编码变量影响复用3.2 核心参数表码长、信噪比、用户数、过采样率跑仿真前先把你手头可调的核心参数列出来。这张表不是照抄别人的而是根据你“想证明什么”来定。比如你只想看单用户AWGN下的扩频增益那码长和信噪比范围是主要参数你想看多用户干扰用户数必须大于1你想看实际信号波形过采样率起决定作用。参数典型值调参影响信息比特数1000 ~ 100000越多曲线越平滑运行时间越长扩频因子 SF16 ~ 128决定处理增益和用户容量上限用户数 K1 ~ 16每增加一用户干扰抬升约10lg(K-1) dB过采样率 sps4 ~ 16过低导致码片对齐性能差过高拖慢仿真Eb/N0 范围0 ~ 12 dB注意横轴是比特信噪比还是符号信噪比3.3 主仿真循环代码解读一个最小单用户CDMA链路直接贴一段最小可运行的单用户CDMA仿真核心循环这是我在干净环境里验证通信链路的标准做法配合注释可以逐行跑通%% 单用户 CDMA 链路仿真BPSK 调制 Walsh 扩频 AWGN clear; clc; SF 64; % 扩频因子对应处理增益约 18 dB numBits 20000; % 仿真比特数太少曲线毛刺多 EbN0_dB 0:2:10; % 比特信噪比范围 ber zeros(size(EbN0_dB)); % 生成 Walsh 码取第 2 行作为本用户扩频码避免全 1 行 walsh hadamard(SF); code walsh(2, :); for idx 1:length(EbN0_dB) EbN0 10^(EbN0_dB(idx)/10); N0 1 / EbN0; % 归一化噪声功率谱密度 % 随机信息比特 data randi([0 1], numBits, 1); % BPSK 映射0 - 1, 1 - -1 sym 1 - 2 * data; % 扩频每个比特重复 SF 次再按码片逐位相乘 spread reshape(repmat(sym, SF, 1), [], 1) .* repmat(code, numBits, 1); % 加噪声实部基带 noise sqrt(N0 / 2) * randn(size(spread)); rx spread noise; % 解扩接收信号与本地码相关再累加 despread reshape(rx, SF, numBits) * code; % 判决大于 0 判为 1小于 0 判为 -1 estSym sign(despread); estData (1 - estSym) / 2; ber(idx) sum(estData ~ data) / numBits; end % 理论误码率曲线BPSK in AWGN theory qfunc(sqrt(2 * 10.^(EbN0_dB/10))); semilogy(EbN0_dB, ber, o-, EbN0_dB, theory, x-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER); legend(仿真值, 理论值);这段代码的逻辑链路是信息比特先映射成 BPSK 符号然后按扩频因子逐码片相乘完成频谱扩展接收端把每个码片周期内的 SF 个采样点与本地码相关求和实现了能量汇聚。代码里的repmat和reshape是把比特流与码片流按矩阵方式对齐的常见技巧比起逐比特循环快一个数量级以上。参数说明N0 1 / EbN0是在归一化符号能量 Es1 的前提下的换算如果你改用了其他调制方式比如 QPSK需要把比特能量和符号能量关系重新换算。这里的hadamard(SF)生成了 SF×SF 的正交矩阵取第 2 行是为了避开全 1 的第 1 行因为全 1 行没有扩频效果这属于实操里的小经验。跑通后你会看到仿真误码率在低信噪比区域与理论曲线几乎重合高信噪比区域因为比特数不够会出现轻微抖动这是正常的不是模型错误。4. 从单用户到多用户干扰建模、功率控制与容量仿真4.1 多用户干扰怎么建模从“正交”到“失步”单用户看起来一切完美一旦把用户数变成 K麻烦就来了。多用户CDMA仿真里最常见的是把每个用户的信号独立扩频后叠加再送入信道。理想情况下不同用户的Walsh码正交用户间互不干扰。但Matlab仿真里有一个很容易被忽略的隐性条件所有用户必须严格码片同步且在同一时刻发射。真实系统很难做到尤其是反向链路用户之间不同步是常态。我一般用两种方式模拟用户干扰。第一种是“同步但不同码”也就是所有用户码片对齐仅靠码的正交性隔离。第二种是“随机失步”给每个用户一个随机的码片偏移比如randi([1, SF-1])个码片延迟这样 Walsh 码正交性被破坏会产生多址干扰。这两种方式的误码率差别非常大。如果你的包里只有第一种建议自己加上随机失步逻辑否则你看到的“多用户性能”是过于乐观的。4.2 功率控制仿真开环和闭环在Matlab里的落法CDMA是自干扰系统远近效应会让离基站近的用户压制远用户所以功率控制不是锦上添花而是生存条件。开环功率控制是移动台根据接收到的导频强度自行估算路径损耗调整发射功率闭环功率控制是基站测量信噪比后下发功率控制命令移动台按命令增减功率。在Matlab里这两者的仿真复杂度差别很大。开环仿真相对简单给每个用户设定一个路径增益然后按增益的反比调整发射幅度。闭环仿真则需要引入反馈环路在每个时隙内计算接收端信干噪比与目标值比较生成功控指令再更新下一帧的发射功率。常见的实现结构是“发射机功率变量 功控步长 测量滤波器”。我在做闭环仿真时会用一个 1 dB 步长、每时隙更新一次的简单模型。对比开环和闭环的误码率曲线可以直观看到闭环功控对多用户容量的提升。4.3 误码率对比实验设计如何证明“多用户容量受限”要证明CDMA多用户容量的瓶颈最有效的实验是固定总发射功率逐步增加用户数记录达到目标误码率比如 BER1e-3所需的Eb/N0。你会发现用户数每翻一倍所需Eb/N0大约增加 3 dB 左右这正是干扰受限系统的特征。%% 多用户误码率对比实验用户数 K 1, 4, 8 % 假设每个用户等功率无功率控制随机失步 clear; clc; SF 64; K_list [1 4 8]; EbN0_dB 0:2:14; ber_all zeros(length(K_list), length(EbN0_dB)); for kIdx 1:length(K_list) K K_list(kIdx); % 给每个用户分配不同的 Walsh 行 walsh hadamard(SF); codes walsh(2:K1, :); % 取前 K 行非全1码 delays randi([0 SF-1], K, 1); % 随机码片级失步 for nIdx 1:length(EbN0_dB) EbN0 10^(EbN0_dB(nIdx)/10); N0 1 / EbN0; numBits 20000; dataAll randi([0 1], K, numBits); symAll 1 - 2 * dataAll; % BPSK txAll zeros(K, numBits * SF); for u 1:K spread_tmp reshape(repmat(symAll(u,:), SF, 1), [], 1); % 按随机码片延迟循环移位示意忽略边缘处理 spread_tmp circshift(spread_tmp, delays(u)); txAll(u, :) spread_tmp; end tx sum(txAll, 1); % 多用户叠加 rx tx sqrt(N0/2) * randn(size(tx)); % 分别解扩用户1假设本地码对准用户1的无延迟版本 rx_reshape reshape(rx, SF, numBits); despread rx_reshape * codes(1,:); est sign(despread); estData (1 - est) / 2; ber_all(kIdx, nIdx) sum(estData ~ dataAll(1,:)) / numBits; end end figure; semilogy(EbN0_dB, ber_all(1,:), o-, ... EbN0_dB, ber_all(2,:), s-, ... EbN0_dB, ber_all(3,:), ^-); grid on; legend(K1,K4,K8,Location,southwest); xlabel(Eb/N0 (dB)); ylabel(BER);这段代码展示了多用户叠加和单用户解扩的基本框架。注意这里用了circshift模拟随机失步但真实的码片延迟会跨越符号边界需要更精细的移位实现这里为了可读性做了简化。运行结果会让你直观看到K8 时误码率曲线整体右移要达到同样的 1e-3需要的Eb/N0比 K1 高大约 6~8 dB。这就是“多址干扰抬高噪声基底”的数值证据。参数说明K_list控制用户数delays是随机失步量如果全为0则退化为同步场景你会看到 K4 和 K1 几乎重合这说明正交码在严格同步下的确能隔离用户。实际做实验时建议固定随机种子比如rng(0)确保曲线可重复对比否则随机失步每次都会让结果上下跳。5. CDMA仿真避坑指南5个常见问题与排查方法5.1 误码率不随信噪比下降或者干脆是一条水平线现象把Eb/N0从 0 dB 调到 12 dB误码率始终在 0.5 左右毫无变化。原因发射端和接收端的扩频码没有同步接收端相关器根本没把信号能量汇聚起来。最常见的是本地码序列没用同一个初始相位或者生成了两次独立的码序列。解决检查发射端和接收端是否使用同一个码生成器对象在循环外一次性生成码序列并分别保存Tx_code和Rx_code确认两者完全相同。一个更隐蔽的陷阱是如果用的是hadamard(SF)接收端取的行号与发射端不一致比如发射取第2行接收误取第3行同样会导致解扩失败。5.2 Walsh码正交性失效多用户性能异常恶化现象K2 时误码率比 K1 差了 10 dB 以上远超理论预期。原因Walsh 码的正交性要求码片对齐精确到一个采样点。如果过采样率是整数且你用整数字延迟往往没问题但如果多用户之间有时偏或者你用了randi造成的随机延迟正交性就会崩溃。解决在仿真多用户时先跑“同步”场景确认delays 0时性能不随 K 恶化然后再引入随机延迟。如果你需要在失步场景下保持用户隔离就得换成 m 序列并配合 RAKE 接收而不是继续用 Walsh 码。5.3 仿真速度极慢跑一个点要几分钟现象numBits 1e6嵌套循环加for逐比特扩频跑一次误码率要等半天。原因没有向量化。CDMA 扩频本质是矩阵操作用repmat和reshape可以一次处理几千个比特。解决把内层循环全部替换为矩阵运算例如spread reshape(repmat(sym, SF, 1), [], 1) .* repmat(code, numBits, 1)。如果仍然慢考虑降低numBits到20000先用毛糙的曲线验证趋势最后用50000做精细确认。还有一个容易忽略的点噪声生成randn也会占时间可以一次性生成整个信噪比循环里最大的噪声矩阵然后在每个信噪比下切片使用。5.4 频谱图看不出扩频效果基带波形没有展宽现象用fft看发射信号频谱发现带宽和信息速率一样完全没有扩频后的带宽展宽。原因过采样率设置太低或者只用了一个码片表示一个比特的“扩频因子1”的错误参数。实际上扩频因子SF必须大于 1否则code长度和比特长度一样根本起不到扩频作用。解决检查SF是否大于1比如SF64同时把过采样率至少设为 4 或 8这样频谱上能看到主瓣带宽从信息速率宽度变成码片速率宽度。另外Matlab 里的fft宽度只看采样点数不是基带带宽的自然显示建议用spectrogram或pwelch观察功率谱密度。5.5 多用户下性能崩溃但单用户正常功率控制缺失现象单用户曲线完美K8 时误码率直接掉到 0.2 以下无法使用。原因不只是码失步更可能是用户间功率差太大强用户完全淹没了弱用户。解决先给每个用户设置不同的发射功率模拟远近效应再实现一个简单的闭环功率控制让基站测量的每个用户信干噪比收敛到同一目标值。常见做法是每隔若干个符号检测一次接收信噪比误差超过 0.5 dB 就给移动台发1 dB或-1 dB的功率调整指令。在仿真里这个反馈回路可以简化成“发射功率 目标SINR - 实时SINR 的差值乘以步长”跑通后你会发现多用户性能会显著改善。6. 让仿真更接近真实系统验证方法、脉冲成形与后续扩展把 AWGN 单用户和多用户链路跑通后别急着收工。我每次写完 CDMA 仿真都会做三件事用来验证自己的模型不是“自嗨”。第一件是拿理论曲线对照。BPSK 在 AWGN 下的理论误码率是qfunc(sqrt(2*EbN0))如果你的仿真点和理论线在低信噪比区间没有贴在一起说明链路里有编码增益或损耗没算对。这里有一个小经验仿真横轴用EbN0而不是SNR因为在扩频系统中两者差一个处理增益换算很多人就是栽在单位混淆上。我习惯在代码里注释明确写“Es Eb * SF / 1BPSK 时一个符号一个比特”防止自己长时间不看后忘记。第二件事是加脉冲成形滤波器。真实 CDMA 系统不会发送矩形的码片波形而是经过根升余弦滤波器限制带宽这样可以降低对相邻信道的干扰。在 Matlab 里用rcosdesign(rolloff, span, sps)生成滤波器系数然后对码片序列滤波。加完后你的频谱会变得“干干净净”不像矩形波形那样旁瓣拖得很长。但要注意成形滤波会引入码间干扰所以接收端必须配一个匹配滤波器或者在下采样时保证最佳采样时刻。这个环节最容易暴露你前面仿真里“理想同步”的漏洞值得一测。第三件事是扩展方向。如果你研究的是 3G 系统下一步可以把 16-QAM 或 QPSK 调制换进去对比不同调制下的 CDMA 频谱效率如果你关注的是现代演进可以对比 CDMA 和 OFDM 在相同信道下的误码率曲线。我自己通常会把仿真结果和理论容量界做一个差值看看离信道容量还有多少距离。这套 CDMA 仿真跑完后你会发现一个非常实用的能力你不再怕“通信物理层黑盒”因为所有环节都是你亲手搭的。最后说一句我的血泪经验仿真里没有“玄学”每一个异常几乎都能追溯到某个具体的代码行或参数设定。遇到曲线不合理时别急着改滤波器、换信道先用单比特单用户把每条路径的信号打到工作区里画出来确认扩频、解扩、判决每一步的数值形态。这样排查半小时比盲目跑一整晚有效得多。希望这篇笔记能帮你少走一点弯路把 CDMA 的仿真从“能跑”做到“可信”。本文还有配套的精品资源点击获取