尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

基于MATLAB的CDMA通信系统仿真:从PN序列到误码率验证

发布时间:2026/9/27 1:41:45

资讯中心
01
ARTICLE

基于MATLAB的CDMA通信系统仿真:从PN序列到误码率验证

基于MATLAB的CDMA通信系统仿真:从PN序列到误码率验证
简介一份基于MATLAB的CDMA通信系统仿真与实现的毕业论文文档面向通信工程、电子信息类专业学生及科研人员用于理解码分多址的核心原理并掌握MATLAB仿真分析方法。文档聚焦扩频与多址两项关键技术阐述了CDMA如何利用扩频提升抗窄带干扰能力、隐藏信号并允许多用户共用频带同时梳理了两路信号经扩频、混合、加噪、调制解调、分离还原的完整仿真流程结合波形图与频谱图评估误码率并针对问题给出改进调试方案仿真结果验证了系统设计的正确性。资源为单个doc文档大小约1.99MB包含中英文摘要、目录及正文章节结构完整。目前已有127人学习下载适合需要完成CDMA相关课程设计、毕业设计或入门移动通信仿真的读者也可作为教师和研究者辅助教学的参考资料。1. 为什么每个通信方向的学生都要亲手把 CDMA 链路跑通答辩前夜误码率曲线还是比理论值高一个数量级我盯着星座图看了两个钟头最后发现是接收端少做了一拍码片对齐。这类基于 MATLAB 的 CDMA 通信系统仿真与实现绝大多数翻车现场都不是理论不会而是扩频、同步、解扩里某个细节没落地。说白了这个题目要干的事很具体用 MATLAB 把一套直扩 CDMA 链路从头搭到尾包括 PN 序列生成、扩频调制、信道加噪、接收端同步与解扩最后用误码率曲线证明链路是对的。它适合三类人正在写毕业论文需要仿真章节支撑的学生、课堂上要交通信系统大作业的人、以及想借着扩频通信把 MATLAB 信号处理底子补扎实的工程师。别小看这个“老题目”跑通它之后OFDM 的帧同步、LoRa 的扩频解调、测控链路里的捕获很多坑都是同一批。2. 动手前先花半小时倒腾环境工具箱、路径与最小可复现闭环凡是仿真报告写得越急的越容易跳过环境检查。常见做法是先建项目目录再确认通信工具箱在不在最后用一段 20 行的 BPSK 最小闭环验证整条调试链路通了没有。这三步做完后面所有脚本都在同一个环境里跑省掉“在室友电脑上能出图换到自己机器上就报错”的麻烦。2.1 先确认通信工具箱在不在毕设脚本里最常用的几个对象是 comm.PNSequence、comm.RayleighChannel以及波形成形用的 rcosdesign。它们都挂在 Communications Toolbox 下面如果安装 MATLAB 时只勾了基础模块后面一跑就会报“未定义函数或变量”。% 检查 Communications Toolbox 是否可用 % 如果返回 built-in 或某个路径说明工具箱已安装 which comm.PNSequence % 或者直接看整个工具箱列表找 Communications Toolbox 行 verwhich返回空的时候不要急着重装整个 MATLAB先看ver列表里有没有 Communications Toolbox。没有的话去账户后台补装这个工具箱就行装好重启再用ver确认。另外提醒一句新版安装包体积越来越大启动也慢做这种基带仿真老版本完全够用不用为了追新去折腾下载安装。如果不想在本地装大客户端MATLAB Online 也能跑但它每次登录后路径都得重新配置跑蒙特卡洛循环时体验不如本地流畅。还有个小坑是中文注释乱码。如果你拿到别人分享的脚本打开后发现注释全是乱码先检查文件编码再检查 MATLAB 的字体预设。代码里尽量少用特殊字符注释写中文没问题但保存时统一用一种编码别一会儿 UTF-8 一会儿 GBK。2.2 给仿真建一个干净的“实验室目录”很多人的毕设仿真就是桌面上一堆 script1.m、script2.m跑完连自己都分不清哪个是最新版。我一般会建三个目录scripts 放主脚本utils 放自写函数results 放数据和图。这样重跑仿真时旧图不会被覆盖论文需要哪个版本也能直接回溯。% 三个文件夹scripts 放主脚本utils 放自写函数results 放数据与图 mkdir scripts utils results addpath(genpath(pwd)); savepath;addpath(genpath(pwd))把当前目录下所有子文件夹都加进搜索路径savepath把这个路径存下来下次启动 MATLAB 不用重新加。注意如果你用 MATLAB Online这个路径配置是按会话管理的关掉就没了。目录结构看起来是小事但等到你要对比不同扩频码长、不同滚降系数的误码率曲线时目录整洁能省一半时间。2.3 先跑通最小闭环一段 BPSK 过 AWGN 信道正式写 CDMA 链路之前先跑一个不含扩频的最小闭环。它的作用是验证三件事随机数种子可控、awgn 函数用法正确、误码率统计逻辑没问题。这三件事里任何一件出错后面 CDMA 仿真跑出来都是错的而且你还很难定位。% 最小 BPSK 链路验证环境与调试流程 rng(42); % 固定随机种子保证可复现 Nbits 1e4; % 比特数 data randi([0 1], Nbits, 1);% 随机信息位 sym 2*data - 1; % BPSK 映射 EbN0_dB 6; % 以 Eb/N0 为指标 snr_dB EbN0_dB 10*log10(1); % 这里无扩频、无过采样SNREb/N0 rx awgn(sym, snr_dB, measured); % 加高斯白噪声 ber mean((rx 0) ~ data); % 硬判决后统计误码率 fprintf(Eb/N0%.1f dB 实测误码率: %.5f\n, EbN0_dB, ber);rng(42)固定随机源保证同样的脚本跑两次得到同样的误码率这是后面调试的后悔药。awgn的第三个参数填measured意思是在加噪声前先实测信号功率按实测值计算噪声方差避免因为信号功率缩放导致信噪比不对。snr_dB这行先写成和 Eb/N0 相等等第 4 章引入扩频增益之后要改掉这里先埋个伏笔。这一段跑通后你的 MATLAB 环境就具备做 CDMA 仿真的一切条件了。为什么不建议直接用 Simulink 拖几个模块搭发射机和接收机因为第一版代码应该保持信号处理过程透明每个矩阵维度变化都得看得见。Simulink 适合后面做模块化验证不适合一开始就用来理解原理。3. 从 PN 序列到 CDMA 发射链路m 序列、Gold 码与扩频成形CDMA 发射链路的核心是把窄带数据符号“抹”到宽带上这个动作靠 PN 序列完成。展开讲就是三件事生成伪随机序列、用序列与符号做扩频、把码片脉冲成形到合适带宽。这一章按发射机的顺序把三件事全部落地。3.1 用移位寄存器自写 m 序列和 Gold 码生成器m 序列是最基本的 PN 序列周期是 2^n - 1其中 n 是移位寄存器级数。虽然工具箱里直接有 comm.PNSequence但我建议自己写一遍因为移位寄存器的实现只有十行而且写完你就理解“为什么 Gold 码是两个 m 序列异或出来的”。function seq mseq(stages, taps) % stages: 寄存器级数seq 长度 2^stages - 1 % taps: 反馈抽头例如 [5 2] 对应 x^5 x^2 1 N 2^stages - 1; reg ones(1, stages); % 初始状态不能全 0 seq zeros(N, 1); for k 1:N seq(k) reg(end); fb mod(sum(reg(taps)), 2); reg [fb reg(1:end-1)]; end end寄存器初始状态全 1 是常见约定全 0 状态会让序列陷在里面出不来。抽头taps决定特征多项式不同抽头产生不同序列但周期一样。跑一遍mseq(5, [5 2])得到 31 个码片这就是码长 N31 的 m 序列。Gold 码用一对优选对的 m 序列生成通过对其中一个序列做循环移位再异或能派生出多条码。这个特性很关键它回答了一个毕设答辩必问题CDMA 怎么区分不同用户答案是靠不同的扩频码码之间互相关性要足够小。% 用两个优选对 m 序列生成一组 Gold 码 m 5; % 级数N31 g1 mseq(m, [5 2]); g2 mseq(m, [5 4 3 2]); gold mod(g1 circshift(g2, 3), 2); % 相对移位 3 得到一条 Gold 码circshift是循环移位移位量不同得到不同 Gold 码。m5 时一共能产生 33 条 Gold 码给 32 个用户用还多一条。注意这里g1和g2的长度要一致都是 31。实际仿真里我一般用 N31 去验证扩频增益用 N63 去展示多用户容量再往上推到 N127 仿真时长会明显变长论文里没太大必要。3.2 扩频调制码片速率、过采样与脉冲成形扩频在数学上很简单一个数据符号复制成 N 份每一份乘一个码片。MATLAB 里用kron一步就能做完。N 31; % 扩频码长 gold mod(g1 circshift(g2, 3), 2); pn 2*gold - 1; % 把 0/1 序列映射成 ±1 序列 data randi([0 1], 500, 1); sym 2*data - 1; % 每个符号扩展成 N 个码片 chip_seq kron(sym, pn); % 过采样与脉冲成形每码片 4 个采样滚降系数 0.5 sps 4; beta 0.5; shaping rcosdesign(beta, 6, sps); tx upfirdn(chip_seq, shaping, sps);kron(sym, pn)把每个符号替换成整段 PN 序列得到一个长度为 500×31 的码片序列这个动作就是直扩。rcosdesign(beta, 6, sps)生成一个根升余弦滤波器beta0.5是滚降系数6是滤波器截断的符号数sps4表示每个码片采 4 个点。upfirdn(chip_seq, shaping, sps)先插值再滤波。参数选择上sps不是越大越好它决定频谱分辨率和后续同步的粒度。4 是常用值8 会让数据量翻倍但同步精度提升不明显。滚降系数 beta 越大频谱越宽但峰均比越好控制0.5 是容易出图也容易答辩的值。这里有个容易被追问的点用根升余弦成形后接收端要用同样的根升余弦做匹配滤波整个链路才没有码间串扰。第一版可以用矩形匹配简化但论文里要写明“接收端采用匹配滤波后误码率能更贴近理论曲线”这个我在第 4 章会做简化处理。3.3 把信号送进信道AWGN 与多径的第一版实现发射机输出的是码片速率的基带信号加噪声时要特别注意awgn 函数需要的是信噪比不是 Eb/N0。因为一个比特被扩成了 N 个码片每个码片又采了 sps 个点能量折算关系完全不同。EbN0_dB 8; % 关键换算扩频增益 N 会让每个比特的能量分摊到 N*sps 个采样点上 snr_dB EbN0_dB 10*log10(1/N) 10*log10(sps); rx_awgn awgn(tx, snr_dB, measured); % 两径信道主径 延迟 3 个码片、幅度 0.5 的次径 imp zeros(round(sps*3)1, 1); imp(1) 1; imp(end) 0.5; rx_multipath filter(imp, 1, rx_awgn);snr_dB这行是后面各种翻车的重灾区。10*log10(1/N)把扩频增益折算进去10*log10(sps)把过采样增益折算进去。如果漏掉这两项误码率曲线会整体平移看起来像那么回事但数值全错。多径信道用一个简单的 FIR 滤波器模拟imp(1)是主径幅度 1imp(end)是延迟了 3 个码片的次径幅度 0.5。实际信道里多径延迟是连续值这里取整到采样点是工程简化够用。4. 接收端解扩与误码率验证同步、换算与理论曲线对齐发射链路跑通只是第一步接收端才是 CDMA 仿真的分水岭。一个最常见的错误是直接把接收信号从第 1 个采样点开始解扩结果误码率永远接近 0.5因为扩频码没对齐。这一章解决同步、误码率验证和多用户干扰三个问题。4.1 前导序列与滑动相关捕获解扩的前提是“知道每个符号从哪里开始”。所以发射端要在一帧数据前面加一段已知的 PN 序列做前导接收端用滑动相关的办法找峰值位置。% 用一段已知的前导序列做滑动相关 preamble pn(1:64); % 发送端已知的捕获序列 L numel(rx); M numel(preamble); corr zeros(L, 1); for idx 1:L-M1 corr(idx) abs(sum(conj(preamble) .* rx(idx:idxM-1))); end [~, peak] max(corr); fprintf(捕获峰值位置: %d\n, peak);这段循环写法不是性能最优但最直观适合调试时打印每一步结果。corr(idx)计算的是接收信号从 idx 开始的一段与前导的互相关模值当 idx 正好对齐时相关峰出现。m 序列自相关旁瓣是 -1/N所以峰值一定高于噪声基底用max就能捕获。提示实际工程里不会对整帧做全搜索而是先粗搜再细搜把搜索窗限制在一个符号周期内。但毕设仿真做全搜索完全够用而且展示效果更直观。捕获到峰值后数据解扩就从peak偏移处开始取数。注意如果你的接收端做了多径信道imp会带来一条延迟 3 个码片的多径分量滑动相关的峰值旁边会出现一个次峰。这在第 5 章会详细讲怎么处理。4.2 误码率统计Eb/N0 与 SNR 换算以及理论曲线对齐误码率仿真要做蒙特卡洛循环固定发射信号每个 Eb/N0 点独立加一次噪声统计误码后和理论曲线画在一起。理论值本身不是玄学BPSK 在 AWGN 下的误码率公式非常硬。EbN0_vec 0:2:12; ber_sim zeros(size(EbN0_vec)); for k 1:numel(EbN0_vec) % 先算码片域 SNR再做信道仿真 snr_dB EbN0_vec(k) 10*log10(1/N) 10*log10(sps); rx_k awgn(tx, snr_dB, measured); % 按捕获位置截取整帧长度与发送端一致 rx_k rx_k(peak:peak N*numel(sym)*sps - 1); % 解扩每 N 个码片累加判决符号 despread zeros(numel(sym), 1); for s 1:numel(sym) seg rx_k((s-1)*N*sps (1:N*sps)); despread(s) sum(seg .* kron(pn, ones(sps, 1))); end ber_sim(k) mean(despread 0 ~ data); end % 理论 BPSK 误码率 ber_theory qfunc(sqrt(2*10.^(EbN0_vec/10))); semilogy(EbN0_vec, ber_sim, o-, EbN0_vec, ber_theory, x-); legend(仿真,理论); grid on;解扩的数学含义是把每个码片乘以本地 PN 码再累加。注意kron(pn, ones(sps,1))因为发射端做过upfirdn每个码片对应 sps 个采样所以本地序列也要按 sps 重复再与接收信号逐点相乘。despread(s) 0是 BPSK 判决。这里最容易被追问的一个点是为什么用了升余弦成形解扩却用矩形匹配严格做法是先做匹配滤波再解扩。毕设里为了简化通常把匹配滤波隐含在解扩累加里只要滚降系数不过大性能差别不会肉眼可见。这句话建议写进论文的仿真假设里。4.3 加入第二个用户观察多址干扰单用户跑通只能证明你会搭链路双用户才是 CDMA 仿真的精髓。两个用户用不同的 Gold 码发送信号叠加后进同一个信道接收端分别用各自的码解扩。% 第二条 Gold 码改变移位量即可 gold2 mod(g1 circshift(g2, 10), 2); % 相对移位 10 pn2 2*gold2 - 1; data2 randi([0 1], 500, 1); sym2 2*data2 - 1; chip2 kron(sym2, pn2); tx2 upfirdn(chip2, shaping, sps); snr_dB 8 10*log10(1/N) 10*log10(sps); rx_total awgn(tx1 tx2, snr_dB, measured); % 分别用 pn1 和 pn2 解扩统计各自误码率这里tx1和tx2长度相同、功率相同所以直接相加。实际问题来了用 pn1 解扩后pn2 那边残留的干扰不会因为信噪比提高而消失这就是多址干扰 MAI。仿真结果一般能看到用户 1 的误码率比单用户时略差用户 2 也一样。如果两个用户功率不一样比如 tx2 比 tx1 大 10 倍弱用户的误码率会直接崩掉这个效应叫“远近效应”是 CDMA 工程里必须处理的现实问题第 5 章专门讲这个。5. 避坑手记CDMA 仿真最容易翻车的 4 个常见问题这一章写的是我自己和周围人反复踩过的坑。每一条都按“现象 → 原因 → 解决”来写你可以直接对照自己的仿真结果排查。血泪经验是这些坑每一条都至少浪费过我一整天。5.1 现象一解扩后误码率接近 0.5星座图散成一团现象低信噪比时误码率还勉强能看高信噪比反而跳到 0.5 附近星座图上四个象限全都有点看不出聚集。原因接收端没有做码同步直接从头开始按 N 个码片解扩。扩频码没对齐时解扩操作等同于把噪声扩频信号本身被当成干扰抹掉了。这类问题看着像玄学其实把捕获峰值打印出来就明白了——峰值位置根本不在 1。解决发射端加一段已知 PN 前导接收端先做 4.1 的滑动相关找峰值再从峰值处截取数据解扩。注意如果峰值位置打印出来是 0去看看数组索引是不是从 1 开始的问题。改完这段误码率通常立刻就有物理意义。5.2 现象二误码率曲线形状和理论值一致但整体偏移 3~5 dB现象仿真曲线和理论 BPSK 曲线平行但一直偏在左边或右边怎么都不重合。原因Eb/N0 和 SNR 混用。awgn 函数需要的是“信号功率与噪声功率之比”而不是“每比特能量与噪声功率谱密度之比”。CDMA 系统里一个比特被扩成 N 个码片每个码片又采 sps 个点这两个增益如果不折算进去曲线就会整体平移。偏移量恰好等于 10log10(N) 或 10log10(sps) 的整倍数。解决统一用snr_dB EbN0_dB 10*log10(1/N) 10*log10(sps)并把换算公式写在脚本注释里。每次换扩频码长 N 或过采样率 sps这行必须跟着改。建议把 EbN0_vec 和 snr_dB 都存成数组画图前打印出来核对一遍两分钟能省两小时。5.3 现象三脚本一运行就报“未定义函数或变量 comm.PNSequence”现象代码是从别人那儿拷的或者自己换了一台电脑运行到 PN 序列生成那一行直接报错。原因两种情况最常见。一是精简安装没装 Communications Toolboxver里看不到二是老版本 MATLAB 里部分通信相关函数名和用法与新版本不一样工具箱存在但函数被移到了别的包路径下。解决先跑which comm.PNSequence看返回空还是路径。返回空就补装工具箱如果不是很依赖工具箱干脆用第 3 章那个十行的mseq函数自己生成序列任何版本都能跑。实际毕设里自写 m 序列不仅没坏处答辩时解释起来还更清楚因为你能直接画移位寄存器结构图。5.4 现象四多用户场景下弱用户误码率卡在一个固定值不上不下现象两个用户功率相差 10 dB 以上弱用户的误码率曲线随着 Eb/N0 增大先下降然后卡住不再变出现“地板”。原因这就是 CDMA 远近效应。强用户的信号通过 Gold 码之间不为零的互相关泄漏到弱用户解扩结果里而且这个泄漏功率不随噪声降低而减少所以弱用户信噪比再高也没用。解决常见做法是在接收端做串行干扰消除 SIC。先解强用户判出它的符号后重新扩频成形再从总接收信号里减掉最后解弱用户。% 串行干扰消除SIC骨架先解强用户再减掉 s1_est sign(despread_by_pn1); % 强用户符号判决despread_by_pn1 来自 4.2 recon1 upfirdn(kron(s1_est, pn1), shaping, sps); % 重构强用户基带信号 rx_for_weak rx_total - recon1; % 从总信号中减去得到弱用户的净信号重构时必须用同一个成形滤波器和同一个捕获偏移不然减法会把强用户残余当成新的多径干扰。这一段代码建议在论文“系统改进”章节里放进去再配一张 SIC 前后的误码率对比图整体工作的完整度立刻上一个台阶。6. 进阶验证参数扫描、Simulink 互证与答辩用的漂亮图前面的链路是单点验证论文里更有说服力的是参数扫描固定其他条件改变扩频码长 N观察误码率曲线的变化趋势。N 越大扩频增益越高抗噪声能力越强但占用带宽也越宽这个矛盾关系是 CDMA 的核心思想值得用一张图展示。Ns [15 31 63]; % 三种扩频码长 figure; for idx 1:numel(Ns) % 每轮循环重新生成对应码长的扩频码并跑完整链路 % 这里把 4.2 的误码率仿真包成函数berN cdma_ber(N, EbN0_vec) berN cdma_ber(Ns(idx), EbN0_vec); semilogy(EbN0_vec, berN, o-, LineWidth, 1.2); hold on; end semilogy(EbN0_vec, ber_theory, k--, LineWidth, 1.2); legend(N15,N31,N63,BPSK理论); grid on;把 4.2 的仿真代码包成函数cdma_ber(N, EbN0_vec)后扫描就只是一行调用。这里顺带说一个工程技巧仿真函数里把随机种子和发送数据都作为参数传进去这样不同码长之间对比时数据比特完全相同“变量只有 N”这件事在答辩时经得起追问。Simulink 互证是另一个加分项。在 Simulink 里用通信模块库搭一条同样结构的链路发射、信道、接收各用模块实现把误码率结果和 MATLAB 脚本结果画在同一张图上。两条独立实现的链路只要数值一致就说明你的仿真没有受某个特定函数的行为影响。这一步不需要把 Simulink 模型做得非常复杂能把 AWGN 信道和误码率统计模块连起来就够。最后说出图。答辩用的图建议用exportgraphics导出矢量格式再转成 PDF 插进文档不然 Word 里放大就发虚。老版本可以用print(-depsc, ber_curve.eps)效果类似。图上记得把横轴标注成 Eb/N0(dB)纵轴用对数坐标刻度范围从 1e-5 到 1 之间理论曲线和仿真曲线用不同线型区分答辩老师一眼就能看到结论。我自己的教训是第一次做这张曲线图时前导序列和业务扩频码用了同一条 Gold 码导致捕获峰值永远出现在零延迟处换了一条独立的 Gold 码做前导后才正常出峰。后来每套仿真我都坚持“前导码和业务码分家”这个习惯帮我避开了后面很多次类似翻车。这个方向值得做直扩 CDMA 的同步与多址处理思路是后续 OFDM、LoRa、扩频测控都绕不开的底子。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。