尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于Matlab的CDMA系统仿真:从扩频到误码率分析的完整实现

基于Matlab的CDMA系统仿真:从扩频到误码率分析的完整实现 简介这是一份基于 MATLAB 的 CDMA 通信系统仿真与实现方向的毕业论文文档适合通信工程、电子信息类本科生及需要开展通信仿真的研究者作为毕业设计与写作参考。文档围绕 CDMA 码分多址核心技术展开系统讲解扩频与多址技术原理并给出基于 MATLAB 对两路信号进行扩频、混合、加噪、调制解调与分离的完整仿真流程通过波形图与频谱图对比可直观评估误码率和系统性能同时便于理解扩频增益、信噪比等因素对通信质量的影响。资源包内共 1 个 doc 文件包体约 1.99MB正文包括中英文摘要、关键词、目录、绪论、国内外发展状况及具体仿真设计结构完整、目录清晰可直接用 Word 打开并编辑。目前已有 127 人学习对于 CDMA 仿真建模、扩频码选择、信道噪声处理、信号分离与误码率优化等关键问题均提供了可复现的分析路径可作为毕业设计选题、论文框架搭建及 MATLAB 通信仿真实战的实用参考也可为后续深入学习移动通信技术奠定基础。1. 想在毕业设计里做CDMA系统仿真Matlab不是唯一选择但确实是最容易出结果的很多通信专业的同学看到“基于Matlab的CDMA通信系统的仿真与实现”这个题目第一反应是去找现成代码。但直接跑别人的脚本图能出来答辩问两句就露馅。这个题目的本质是用Matlab搭建一条完整的CDMA物理层链路从信源比特开始经过扩频、调制、信道加噪、解扩、解调最后统计误码率并且让仿真结果能和理论曲线对上。这里真正要解决的不仅是“跑通”而是知道每一步在做什么、参数为什么这么设、结果为什么可信。下文会沿着一条可复现的仿真路径把理论基模、链路实现、误码率分析和收尾验证拆开讲。适合正在做通信方向毕业设计的学生以及需要快速搭建物理层仿真验证环境的工程师。CDMA背后的扩频与多址思想才是仿真模型里最关键的部分。2. CDMA仿真的理论基模扩频码与Matlab建模选型2.1 为什么选Matlab做CDMA系统仿真而不是自己写CCDMA仿真的核心是大量随机序列运算和相关性统计。Matlab的信号处理和通信工具箱把这些运算封装成了向量化函数比如randn、xcorr、filter连误码率理论曲线都直接提供berawgn。如果一个系统里有几百个用户用C循环算相关性效率并不差但模型改动成本很高。而在毕设阶段改动参数重新跑一遍是常态Matlab的脚本化工作流最适合这种迭代节奏。另外Matlab安装完成后我会先确认已经勾选了Communications Toolbox和Signal Processing Toolbox这两个工具箱覆盖了PN序列生成、调制解调函数库和滤波器设计能省掉大量底层代码。选型还有一个容易被忽略的点仿真代码的可解释性。毕业论文里需要把核心程序放进附录导师会重点关注扩频、解扩这两段代码。Matlab代码天生接近数学表达式比如相关解扩就是一个点乘累加写出来比C容易解释。这也是很多学校默认用Matlab做通信仿真课程与毕设的原因。下面的表格列出了我在CDMA链路里最常用的一组函数前两行负责随机源中间两行负责扩频与相关性验证最后一行是理论参考线。函数用途典型用法randi生成均匀分布的随机信息比特randi([0 1], N, 1)randn生成高斯白噪声样本sigma * randn(size(x))xcorr计算自相关或互相关验证PN码同步xcorr(pn_bipolar)filter实现FIR多径信道卷积filter(taps, 1, spread)berawgn计算BPSK在AWGN下的理论误码率berawgn(EbN0_dB, psk, 2, nondiff)parfor并行循环加速蒙特卡洛统计parfor i 1:num_frames表格里的函数不需要全部用到但前三个是CDMA仿真绕不开的。randn生成的噪声必须和信号长度完全一致否则广播维度会对不上这点我会在信道实现一节展开。2.2 m序列与Gold码的生成参数CDMA系统里扩频码要满足两个条件自相关尖锐、互相关低。最常用的是m序列和由它派生的Gold码。m序列由线性反馈移位寄存器生成寄存器长度r决定序列周期2^r-1。比如r5时生成长度31的序列特征多项式可以选择x^5x^21。我在仿真里通常用下面这段代码生成m序列% m序列生成线性反馈移位寄存器 r 5; % 寄存器长度 pn_len 2^r - 1; % 序列周期 reg ones(1, r); % 初始状态不能全零 pn zeros(1, pn_len); for k 1:pn_len pn(k) reg(r); % 输出最高位 feedback xor(reg(2), reg(r)); % 抽头对应特征多项式 x^5x^21 reg(2:r) reg(1:r-1); % 寄存器右移 reg(1) feedback; % 反馈位进入最低位 end % 将逻辑0/1转换为双极性电平 1/-1 pn_bipolar 2*pn - 1;这段代码的关键在反馈抽头。reg(2)和reg(r)这两个位置对应本原多项式里的非零系数选错的话生成序列的周期会变短自相关特性也会恶化。迭代收尾时我会用pn_bipolar做相关运算因为双极性电平使相关结果在同步点正好等于序列长度不同步点接近0。在实际仿真里我更推荐直接使用通信工具箱的comm.PNSequence对象它能指定抽头索引并生成Gold码但自己写LFSR更容易理解原理参数调整也更透明。提示m序列生成时寄存器初始状态全零会导致输出永远是0很多仿真异常都是从这个小疏忽开始的。2.3 扩频与解扩的数学表达扩频的本质是每个信息符号乘上一整段PN码。假设信息符号周期为Tb扩频码周期TcTb/SF其中SF就是扩频因子。发送信号在数学上可以写成s(t)d(t)c(t)d是BPSK符号1或-1c是PN码序列。接收端做相关运算把接收信号与本地PN码相乘后积分。当两端PN码同步时乘积的积分结果会把符号能量累加SF倍而噪声因为与PN码不相关不会获得同样的增益。这就是CDMA处理增益的来源也是接收机能从噪声中恢复信号的基础。在Matlab仿真里我会把连续积分改成离散向量点乘。下面是一个在发射链路中使用的扩频操作注意扩频因子与PN码长度要一致% 发射端数据符号复制SF次后逐码片乘以PN序列 SF 31; % 扩频因子 data_symbols 2*randi([0 1], 200, 1) - 1; % 200个BPSK符号 spread zeros(length(data_symbols) * SF, 1); for i 1:length(data_symbols) seg_idx (i-1)*SF 1 : i*SF; spread(seg_idx) data_symbols(i) * pn_bipolar; end % spread就是待发送的码片序列这里的扩频因子直接决定码片速率扩频因子越大抗干扰能力越强但占用带宽也越大。在单用户仿真中即使没有多用户干扰也要保留“每个符号复制SF次”这个结构因为后边做相关解扩时需要按这个分段方式切回符号边界。很多人在这个步骤直接把数据整体和PN码点乘从数学上等价但同步和误码统计会变得很绕一旦算错很难排查。3. 搭一套完整的CDMA链路从发射机到接收机3.1 发射机端实现信源映射与扩频在2.3节的扩频代码之上需要把“数据比特”和“符号”的概念分开。比特经过BPSK映射变成1/-1然后按扩频因子复制再与PN码相乘。发射机端的完整流程是随机生成比特映射为符号逐符号扩频。在Matlab中用向量化写法可以避免循环代码更紧凑% 发射机完整流程 N_sym 200; % 传输的符号数 SF 31; % 扩频因子 bits randi([0 1], N_sym, 1); % 原始信息比特 symbols 2*bits - 1; % BPSK映射到 1 / -1 % 扩频先把每个符号重复SF次再与PN码按列相乘 spread kron(symbols, ones(SF,1)) .* repmat(pn_bipolar, N_sym, 1);kron函数把每个符号替换成一段长度SF的全1向量repmat把PN码沿纵向复制N_sym次两者点乘就得到码片序列。为什么要用repmat而不是循环因为Matlab的向量化操作在5000个符号、31倍扩频的规模上比for循环快一个量级而且写法更接近公式。仿真参数里扩频因子、PN码周期、符号数三者需要匹配如果kron后的总长度不是PN码周期的整数倍repmat就会截断或补零导致误码率异常升高。调试时可以检查spread的长度是否能整除SF同时确认PN码没有因为复制而出现跨周期的相位跳变。在单用户仿真里发射机的功率归一化也需要注意。如果符号幅度设置为±1扩频后每个码片幅度也是±1因此整个码片序列的平均功率等于1。这样在加噪声时Eb/N0和N0之间的换算就只由数据符号决定不会引入缩放因子。下表是我搭建链路时固定的参数之后所有误码率仿真都沿用这套配置。参数数值说明扩频因子SF31每个符号对应的码片数符号数N_sym200~500越大误码率统计越稳定PN码长度31等于扩频因子噪声类型AWGN也可扩展为两径信道Eb/N0范围0 ~ 10 dB步进2dB3.2 信道模型加性白高斯噪声与两径衰落CDMA信道模型里最基础的是AWGN信道。在Matlab里直接使用randn生成高斯随机数噪声功率由信噪比决定。仿真时通常以Eb/N0为横轴比特能量Eb需要根据码片能量和扩频因子换算。常见做法是固定信号平均功率为1然后按目标Eb/N0计算噪声方差Eb sum(abs(symbols).^2) / N_sym; % 符号能量BPSK下等于1 N0 Eb / (10^(EbN0_dB/10)); % 噪声功率谱密度 noise_power N0 / 2; % 双边带噪声实信号只看实部 rx spread sqrt(noise_power) * randn(size(spread));这里要注意噪声功率为什么除以2。基带等效模型里的复高斯噪声在实部和虚部分别是N0/2对于实信号BPSK只需要实部噪声所以噪声方差取N0/2。如果写成randn(size(spread))乘以某个sigma就要先算清楚sigma的物理单位。很多人仿真的误码率曲线比理论差2到3个dB大多数是噪声功率里的系数写错了。如果论文里需要体现CDMA的抗多径能力简单的方法是加一个两径滤波器。滤波器抽头设置为第一条径增益1第二条径延迟一个码片、增益0.5% 两径信道主径增益1延迟一个码片增益0.5 channel_taps [1, zeros(1, 1), 0.5]; rx_faded filter(channel_taps, 1, spread); rx rx_faded sqrt(noise_power) * randn(size(rx_faded));filter函数按照抽头延迟线结构输出卷积结果两个抽头之间加了一个零表示第二径延迟一个码片。这里默认每个码片采样一个点如果仿真中一个码片有多个采样点延迟的值要改成对应的采样点个数。多径场景下直接相关解扩会导致码间干扰这是RAKE接收机存在的意义。如果论文只是验证CDMA基本流程AWGN信道已经足够多径可以放在改进章节单独展开。3.3 接收机端解扩与判决接收机要做的是把本地PN码对齐到发送码片序列上然后分段累加。解扩代码和发射端的扩频结构严格对应分段起点尤其不能错% 接收端按SF长度分段与PN码逐码片相乘后累加 rx_symbols zeros(N_sym, 1); for k 1:N_sym seg rx((k-1)*SF 1 : k*SF); rx_symbols(k) sum(seg .* pn_bipolar); end % 判决累加结果正负映射回0/1 rx_bits rx_symbols 0; ber sum(rx_bits ~ bits) / N_sym;解扩输出的rx_symbols是在每个符号上累加的相关能量判决门限取0大于0判为比特1小于0判为比特0。sum操作把SF个码片的相关结果加起来噪声项因为PN码的正负交替被部分抵消所以判决信噪比高于码片级信噪比。如果仿真里出现误码率几乎不随信噪比下降的情况先检查接收端是否用了与发射端相同相位的PN码以及分段起点是否偏移。可以用xcorr(rx(1:100), pn_bipolar)找到相关峰用峰值位置反推同步起点。4. 误码率仿真、参数调优与常见坑4.1 用蒙特卡洛仿真统计误码率CDMA链路的误码率需要用多帧数据重复统计。单次传输200个符号误码率结果方差太大一般要循环几千个符号或者对每个Eb/N0点重复几十次。下面的脚本是所有通信系统仿真里最常用的骨架也是通信仿真验证的标配写法EbN0_dB 0:2:10; num_frames 50; % 每个信噪比下重复50次 symbols_per_frame 500; ber_sim zeros(size(EbN0_dB)); for idx 1:length(EbN0_dB) errors 0; total_bits 0; for f 1:num_frames bits randi([0 1], symbols_per_frame, 1); symbols 2*bits - 1; spread kron(symbols, ones(SF,1)) .* repmat(pn_bipolar, symbols_per_frame, 1); Eb sum(abs(symbols).^2) / symbols_per_frame; N0 Eb / (10^(EbN0_dB(idx)/10)); rx spread sqrt(N0/2) * randn(size(spread)); rx_symbols zeros(symbols_per_frame, 1); for k 1:symbols_per_frame seg rx((k-1)*SF1 : k*SF); rx_symbols(k) sum(seg .* pn_bipolar); end errors errors sum((rx_symbols 0) ~ bits); total_bits total_bits symbols_per_frame; end ber_sim(idx) errors / total_bits; end semilogy(EbN0_dB, ber_sim, o-); hold on; semilogy(EbN0_dB, berawgn(EbN0_dB, psk, 2, nondiff), r-); legend(CDMA仿真,BPSK理论); xlabel(Eb/N0 (dB)); ylabel(误码率); grid on;外层循环扫信噪比内层循环把噪声重新置位并重新统计误码。berawgn函数给出的理论曲线是无扩频BPSK在AWGN下的结果和CDMA单用户链路在理想同步下应该重合。如果仿真曲线在高信噪比区域出现水平平台说明噪声之外的干扰占了主导比如PN码未同步或扩频因子与PN码长度不一致。跑完这个脚本后保存ber_sim变量后面画图和多轮平均都要用到。4.2 仿真发散与性能异常的排查思路“仿真发散”这个词在通信仿真里有两层含义一是结果数值不收敛随着仿真次数增加误码率反而波动变大二是某些迭代算法比如自适应均衡的权重发散。CDMA仿真主要遇到的是第一种。我把常见的异常现象和排查方向汇总成下面这张表实际调试时可以按表格里的顺序逐个试。异常现象可能原因排查方法误码率在5dB以上不下降符号间干扰或PN码未对齐检查接收端分段起点与发送端是否一致曲线整体比理论上移噪声功率计算系数错误重算Eb/N0到噪声方差的换算公式同一参数每次运行结果差很多随机数种子不固定或符号数太少使用rng(0)固定种子并增加帧数扩频后波形幅度异常大数据符号与PN码相位不匹配确认PN码双极性转化是否完成仿真耗时太长单层循环太大且未并行化用parfor替换内层帧循环做毕设时很多同学看到误码率曲线不平第一反应是继续加循环次数但问题可能出在模型结构化错误上。我一般会先做一个极端参数验证把信噪比设为很高比如20dB如果误码率不是0那一定存在PN码同步或判决门限的问题。这个方法比无脑加随机数更快。另外如果用了filter做多径信道输出序列会比输入长需要手动截断到与spread相同长度否则解扩分段会偏移。4.3 用Matlab优化工具箱与并行计算加速仿真蒙特卡洛仿真的耗时集中在循环和矩阵操作。如果一台机器跑500个符号、50帧需要十几秒那扫10个点就要几分钟还能接受。但如果扩频因子到127、用户数到32就必须优化。两种常见做法一是把内层帧循环改成parfor并行执行二是一次性生成整个噪声矩阵减少randn的调用次数。% 用parfor替代第4.1节中的内层帧循环 parfor f 1:num_frames bits randi([0 1], symbols_per_frame, 1); % 发送、信道、接收、误码统计全部放在循环体内 % 返回该帧的错误数最后在外面汇总 end使用parfor时要注意循环体内不能有依赖上一次迭代结果的变量Matlab会自动检查并报错。更简单的提速方式是提前生成多帧噪声矩阵然后一次性解扩按帧统计误码。这种方式对内存消耗更大但速度提升明显。至于Matlab优化工具箱它通常解决参数寻优问题比如用fminsearch调接收滤波器抽头系数而不是直接加速蒙特卡洛。如果你论文里的创新点是自适应门限或功率控制优化工具箱才排得上用场。5. 用仿真结果支撑论文图表曲线验证与导出细节5.1 固定随机种子并叠加理论曲线论文里最容易被挑刺的是仿真结果无法复现。代码开头写rng(0)让随机数生成器每次都从头开始误码率曲线就可以精确重跑。叠加理论曲线时我会把berawgn换成显式的Q函数写清楚Eb/N0与误码率的关系导师更容易看懂公式和代码的对应关系rng(0); % 理论误码率BPSK在AWGN下 Pb Q(sqrt(2*Eb/N0)) EbN0_linear 10.^(EbN0_dB/10); ber_theory qfunc(sqrt(2*EbN0_linear));qfunc的输入是sqrt(2Eb/N0)这个式子可以直接写进论文公式部分。仿真点如果不叠加理论线只有自己测的一组数值看起来没有说服力。如果仿真点偏离理论超过0.5dB我会先回看4.2节的排查表而不是直接调整曲线样式。5.2 输出出版级图表论文插图需要高分辨率、白底、无多余边框。直接saveas保存的图线条较粗放进Word容易被拉伸变形。我一般用下面这段设置set(gcf, Color, white, Position, [100 100 560 420]); set(gca, LineWidth, 1.2, FontSize, 11, FontName, Times New Roman); grid on; print(gcf, ber_cdma, -dpng, -r300);-r300表示300dpi分辨率满足大部分学校毕业论文对图片清晰度的要求。图片命名用英文和下划线避免在Word里出现字体问题。多次仿真时打印前要先用figure()新开窗口否则曲线会叠在旧图上导出的图片里就会出现多条颜色相近的线。5.3 用多次运行平均并加误差棒单次仿真就算固定了种子也只是获得一个随机样本。真正验证系统性能时我会对不同随机种子跑5次把误码率平均值和标准差都算出来在图中添加误差棒。这个做法可以看出仿真点落在理论曲线上下的波动范围答辩被问到“为什么仿真点和理论不完全重合”时可以直接用统计波动解释。ber_runs zeros(5, length(EbN0_dB)); for run 1:5 rng(run); % 用不同种子执行第4.1节中的仿真主体 end ber_mean mean(ber_runs, 1); ber_std std(ber_runs, 0, 1); errorbar(EbN0_dB, ber_mean, ber_std, o-);误差棒的长度反映仿真的统计极限符号数越多误差越小但不可能完全消除。对于Eb/N0比较高的点误码率可能为0误差棒无法显示此时需要增加符号数或降低最高信噪比点避免所有点上都清零。最后把脚本里所有硬编码参数集中到一个配置块包括PN码周期、扩频因子、符号数、信噪比范围这样反复改参跑图时不会漏掉对齐关系图表重做起来也只需要按一次运行。本文还有配套的精品资源点击获取
返回列表