拓冰建站拓冰建站
首页 / 资讯中心 / 正文

BPSK调制解调与直序扩频仿真:MATLAB链路实现及误码率分析

BPSK调制解调加扩频解扩这套通信链路我在MATLAB里前前后后折腾了快两周从最开始的“能跑通”到后来彻底把误码率曲线、扩频增益、处理增益这些指标吃透踩了不少坑也积累了不少经验。今天把这些东西整理出来给正在做通信原理课程设计、或者在做扩频通信相关毕设的同学一个可以直接上手的参考。先说清楚这套仿真到底在做什么发射端把二进制比特流先做BPSK调制再做直序扩频DS-SS经过加性高斯白噪声信道AWGN后接收端先解扩再解调统计不同信噪比下的误码率和理论曲线做对比。整个链路麻雀虽小五脏俱全是通信系统仿真里特别经典的一个入门到进阶的组合。适合通信工程、电子信息专业的学生也适合刚接触MATLAB通信工具箱的工程师快速建立系统概念。1. 链路仿真的整体思路拆解1.1 为什么偏偏选BPSK加直序扩频很多同学一上来就问直接做BPSK误码率仿真不是挺简单的吗为什么非要加扩频这个问题的答案恰恰是这个仿真的核心价值。BPSK本身是最基础的数字调制方式它把比特映射到载波的相位上——比特1对应一个相位比特0对应相位反转。它的误码率理论曲线是所有数字调制里最好推导、最容易验证的适合做整个链路的“标尺”。而扩频这里指直序扩频DSSS做的事情是用一个高速率的伪随机序列去乘以低速率的已调信号把信号频谱展宽。接收端再用同步的伪随机序列做相关运算把展宽的频谱“压”回来。这个过程中有一个非常关键的红利处理增益。处理增益约等于扩频倍数它意味着系统能在比常规BPSK更低的信噪比下工作——当然这是在忽略干扰和截获场景下这么理解在纯AWGN信道里扩频本身并不提升理论误码率性能这点特别多初学者搞混。把两者组合在一起可以形成一条逻辑完整的链路调制产生带通信号扩频改变信号带宽与抗干扰潜力AWGN信道注入噪声接收端做解扩恢复信号解调判决还原比特。每一步都有明确的输入输出每个环节都可以单独验证排查问题时非常方便。1.2 链路结构设计与参数选型逻辑这一小节特别重要我建议任何做通信仿真的人都先把系统参数定下来再写代码而不是边写边拍脑袋。我这套仿真的参数是这样定的信息比特率1000 bit/s也就是每秒1000个二进制符号BPSK符号速率和比特率一致1000 symbol/s采样率20000 Hz即每个BPSK符号采20个点载波频率4000 Hz满足采样率大于两倍载波频率的要求也方便观察波形扩频码速率码片速率10000 chip/s扩频码长度10用的是m序列的截短下面细说这套参数组合的意义在哪里关键在于“每个信息比特对应10个码片”扩频倍数为10理论上处理增益就是10lg(10)10dB。而采样率为什么定20k而不是10k因为扩频后的码片速率是10k chip/s根据奈奎斯特定理采样率至少要20k才能无失真表示码片波形同时采样率还得是码片速率的整数倍这样每个码片正好采2个点方便后面做匹配滤波和数据对齐。参数设计时一定要记住一个原则所有速率之间最好成整数倍关系否则接收端做定时同步、符号对齐时会被分数倍延迟折磨到怀疑人生。后面我讲定时同步的问题还会再提这一点。1.3 仿真整体流程和数据流走向定完参数整个数据流的走向是这样的随机二进制数据 → BPSK映射1映射为10映射为-1→ 扩频每个数据符号乘一组10位的PN码→ 上变频到4kHz载波 → 叠加AWGN噪声 → 接收端下变频到基带 → 低通滤波 → 解扩与同步PN码做相关累加→ 判决还原二进制数据 → 与发送端数据对比统计误码率。这里有个非常关键的认知接收端的下变频和低通滤波一步都不能省。很多初学的同学做完扩频后直接把信号搬到基带就去解扩结果高频分量没有被滤掉解扩后的信噪比损失严重误码率曲线莫名其妙高出理论值几个dB还以为是扩频本身的问题。2. BPSK调制解调核心细节解析2.1 调制映射不是简单地把0变成-1就行BPSK的映射方式从原理上讲是相位调制但在MATLAB仿真里最常用的做法是直接用极性码映射1映射为10映射为-1然后乘以载波的余弦分量。这里有一个细节值得展开什么时候直接用极性码什么时候需要做星座映射如果你后面打算扩展仿真比如从BPSK升级到QPSK、16QAM我建议从一开始就养成用复数基带表示的习惯。BPSK可以理解为只有实部的调制方式即符号映射为1或-1载波用cos(2πfct)。这样写的好处是以后扩展到QPSK时只需要把映射变成复数I路和Q路各一个比特载波变成复指数exp(j2πfct)信号发射和接收的框架完全不用改。具体到代码实现发送端的基带信号生成是这样的逻辑先把比特流分组每个比特查表映射为对应的幅度然后对这个符号序列做上采样也就是每个符号重复若干个采样点再与载波相乘完成上变频。上采样这一步很多人忽略但它其实是在模拟“DAC之后的阶梯波输出”。如果跳过上采样直接乘载波你会得到一个在符号切换瞬间相位跳变的信号这在仿真里也算正确但后续加噪声时噪声的统计特性、滤波器的设计参数都会变得很难对齐。所以我强烈建议符号序列先上采样再乘载波这样做出来的波形和真实硬件更接近。2.2 相干解调与载波同步的简化处理接收端解调BPSK理论上最理想的方式是相干解调——也就是接收端知道载波的频率和相位产生一个和发送端完全同步的本地载波去乘接收信号把频谱搬回基带。但在MATLAB仿真里很多人的处理方式是直接用发送端载波做参考这就隐含了一个假设接收端已经有完美的载波同步。这种做法在课程设计里没有问题因为我们的重点是验证调制解调性能而不是研究载波同步算法。但我要提醒一句如果以后做的是全链路同步仿真千万不要这样搞一定要加锁相环或者基于导频的载波恢复否则结果会过于乐观。在这次的仿真里我用了“理想载波同步”的简化方式也就是接收端产生的本地载波频率和相位都与发送端一致。这样做的好处是能把注意力集中在扩频解扩和误码率统计上避免载波同步误差干扰对结论的判断。等到整条链路验证无误了再去替换成带同步算法的接收机这是很稳的调试节奏。2.3 低通滤波器设计这个坑我替你们踩过了下变频之后信号里包含基带分量和2倍载频分量必须用低通滤波器把高频分量滤掉。滤波器参数选择不当会直接导致解扩输出的信噪比严重下降。我在仿真里用的是FIR低通滤波器设计参数为通带截止频率1000Hz阻带起始频率2000Hz采样率20kHz滤波器阶数40阶。这里通带截止频率1000Hz怎么确定的基带信号经过扩频后的单边带宽约等于码片速率10kHz的一半即5kHz。但注意解扩之前我们其实已经不需要那么宽的带宽了因为解扩后的信号带宽就是信息符号速率1kHz的基带带宽约500Hz到1000Hz的量级。这个滤波器真正要保留的是解扩后的信号分量所以通带截止频率设在1000Hz合理2000Hz开始抑制也能把2倍载频分量8kHz彻底压掉。滤波器的阶数也不是随便定的。阶数越高过渡带越窄但群延迟越大信号延迟越明显。40阶FIR在这个采样率下群延迟大概1ms也就是两个符号周期的延迟接收端只要把定时基准往后移一个固定延迟就能对齐不影响最终判决。3. 扩频解扩实现与关键参数计算3.1 m序列生成不要用randi碰运气扩频码的选取是整套扩频系统最核心的部分。这次仿真里用的是m序列的截短——一个10位的m序列。m序列的全称是最大长度线性反馈移位寄存器序列它的特点是周期性、伪随机性、相关特性好。我需要强调的是扩频码最核心的指标是自相关函数理想情况下码与自身对齐时相关值最大码与自身错开一个或多个码片时相关值很小这样接收端才能准确完成解扩。如果你直接用randi生成随机序列当扩频码那自相关性质完全没有保证甚至可能出现错位相关值大于对齐相关值的情况接收端解扩直接失效。这一点是很多自学同学最容易犯的错误。生成m序列有现成的方法用MATLAB的通信工具箱可以直接调用手写实现也不难确定一个本原多项式设定寄存器初值循环移位生成序列。比如10位m序列可以用多项式x^4x1来生成寄存器初值设为全1每次移位后取反馈值填充高位输出的序列映射为1和-1。3.2 扩频倍数与处理增益的定量关系扩频倍数N定义为N 码片速率 / 信息速率。在我的参数里就是10000/100010。这个N意味着什么在直序扩频里发送端每个信息比特被替换成了N个码片频谱宽度变成原来的N倍功率谱密度相应降低到原来的1/N。接收端解扩时用与发送端同步的PN码做相关累加把N个码片的能量累加回一个信息比特的时间窗口内信号被“压缩”回窄带而噪声由于与PN码不相关不会被同等累加这就产生了处理增益。定量计算处理增益 10lg(N) dB。N10时处理增益10dB。这意味着解扩后信号的等效信噪比比输入信噪比高出约10dB。这里必须再次强调在纯AWGN信道里这个处理增益不是白拿的它换来的是带宽的展宽。如果你把信噪比定义为Eb/N0每比特能量与噪声功率谱密度之比扩频前后理论上误码率是完全一样的仿真的结果也应当验证这一点。很多论文或者课程报告里“扩频使误码率下降”的说法是有条件的这个条件是有窄带干扰的对抗场景或者发射功率受限下的抗截获场景。AWGN信道下扩频的唯一收益是抗干扰能力和频谱兼容性不是误码率改善。在做仿真分析和报告总结时一定要把这一点写清楚不然答辩时老师一问就露馅。3.3 解扩的两种实现方式对比解扩的本质是相关运算但实操中有两种写法各有优缺点。第一种是“逐点相乘累加”法把接收到的基带信号与本地PN码逐点相乘然后在一个信息符号周期内累加。这种做法的物理意义非常明确就是在做相关代码可读性高适合教学演示。缺点是比较慢不过对10倍扩频这种小规模场景完全不是问题。第二种是“乘以PN码再匹配滤波”法把接收信号乘以本地PN码序列然后送入匹配滤波器。这种做法本质上和第一种是一致的但更接近真实接收机的实现方式也更容易和后续的均衡器、RAKE接收机设计衔接。我这次先用第一种方式实现逻辑清晰好排查在代码结构上做了函数封装后面如果要做多径信道下的RAKE接收机仿真可以直接把解扩模块替换成第二种实现不需要改动其他部分。3.4 一个特别容易忽略的点解扩前的时钟对齐接收端的PN码必须和发送端的PN码在时间上严格对齐差一个码片都不行。因为m序列的自相关函数虽然主峰尖锐但旁瓣不为零错位一个码片时相关值已经明显下降误码率会劣化好几个dB。在理想仿真里我们通常假设接收端知道PN码的起始时刻直接对齐解扩。但如果你自己在做定时同步实验可以观察一下错位0.5个码片、1个码片、2个码片时相关输出的变化曲线这个实验做完你对扩频系统的“时域同步”的理解会深刻很多。4. 误码率仿真流程与MATLAB落地实现4.1 仿真框架从单次传输到蒙特卡洛统计误码率仿真的核心逻辑是蒙特卡洛统计多次发送随机数据经过信道后统计错误比特比例从而近似理论误码率。具体到BPSK-AWGN链路误码率理论公式是Pb Q(sqrt(2*Eb/No))其中Q是高斯Q函数Eb/No是每比特信噪比。MATLAB里用qfunc或者erfc都可以算。仿真时需要在不同Eb/No下分别统计误码率。Eb/No换算成符号信噪比、再换算成采样点信噪比的过程这里有一个特别容易出错的地方我单独列出来讲。信号加噪的时候我选择在通带加噪。给定Eb/No后单边噪声功率谱密度N0 Eb/(Eb/No)而信号加噪前每个采样点的功率Ps和噪声功率PnN0fs/2的关系是Ps EbRsRs为信息符号速率这里的单位一定要统一。具体推导信号经过BPSK调制后每个信息符号的能量为Eb扩频后每个数据符号包含N个码片总能量不变信号带宽变为N倍。在采样率为fs的条件下信号功率Ps EbRs这里Rs1000 symbol/s则噪声功率Pn N0fs/2 Ebfs/(2Eb/No)。于是噪声标准差 sqrt(Pn)。在MATLAB里sigma sqrt(N0*fs/2)。这个公式用得极其频繁我建议直接背下来。4.2 核心代码结构与关键函数实现下面给出我这次仿真中最核心的代码模块。为了让结构清晰我把整个仿真拆成了几个函数数据生成、BPSK调制、扩频、加信道噪声、解扩解调、误码率统计。主脚本循环扫描Eb/No。%% 参数配置 EbNo_dB 0:2:10; % Eb/No 范围 numBits 1e5; % 每个信噪比点统计的比特数 Rb 1000; % 信息比特率 1000 bps fs 20000; % 采样率 20kHz fc 4000; % 载波频率 4kHz chipRate 10000; % 码片速率 10k chip/s samplesPerChip fs / chipRate; % 每码片采样点数 2 samplesPerSymbol fs / Rb; % 每个信息符号采样点数 20 N chipRate / Rb; % 扩频倍数 10 % m序列生成长度取10 pnSeq mseq(4, 1010); % 假设返回1/-1序列长度至少10 pnSeq pnSeq(1:N); % 截短至10位 %% 单次链路处理示例循环Eb/No统计误码率 for idx 1:length(EbNo_dB) EbNo 10^(EbNo_dB(idx)/10); N0 1 / EbNo; % 归一化Eb1 noiseSigma sqrt(N0 * fs / 2); berNum 0; % 分成多帧发送以节省内存 for frame 1:10 bits randi([0 1], 1, numBits/10); % BPSK映射 sym 2*bits - 1; % 扩频 spread kron(sym, pnSeq); % 上采样与上变频这里给出简化版本 tx_baseband upsample(spread, samplesPerChip); % 实际应用中需加成形滤波器这里为演示做简单保持 tx_baseband filter(ones(1, samplesPerChip), 1, tx_baseband); t (0:length(tx_baseband)-1) / fs; tx_signal tx_baseband .* cos(2*pi*fc*t); % 加噪 rx_signal tx_signal noiseSigma * randn(size(tx_signal)); % 下变频 rx_baseband rx_signal .* 2 * cos(2*pi*fc*t); % 低通滤波设计好的FIR系数 rx_filtered filter(lpf_coeff, 1, rx_baseband); % 定时采样与解扩简化处理需要对齐群延迟 % 这里以第20个采样点作为符号起点做示例 rx_sym rx_filtered(20:samplesPerSymbol:end); % 重塑为符号×码片矩阵累加解扩 rx_chips reshape(rx_sym(1:N*numBits/10), N, []); despread sum(rx_chips .* repmat(pnSeq(:), 1, size(rx_chips,2)), 1); % 判决 rx_bits double(despread 0); berNum berNum sum(rx_bits ~ bits); end ber(idx) berNum / numBits; end上面这段代码里我故意没给出滤波器设计那一行因为如果你直接复制运行大概率得不到理想结果——你需要调用fdesign.lowpass或者fir1来设计滤波器并且处理滤波延迟。我建议你在结合自己参数调整时先把无滤波器的理想解调跑通再加滤波器逐步debug。4.3 理论误码率曲线与仿真曲线的对比验证仿真跑完之后最重要的一步是画误码率曲线对比图。用semilogy画纵坐标对数刻度横坐标是Eb/No纵坐标是误码率。理论曲线用qfunc(sqrt(2*EbNo_linear))直接画出来。一个常见的现象是小信噪比下仿真点和理论曲线完美重合大信噪比下仿真点开始飘甚至出现“地板效应”掉不下去。这通常不是算法问题而是误码统计的置信区间不够——信噪比高时误码率极低比如1e-5意味着统计10万个比特才可能看到1个错误这需要非常大的仿真数据量才能稳定。解决办法是每个信噪比点至少统计100个错误比特或者至少统计1e6个比特如果数据量实在太大也可以把高信噪比点的统计帧数加倍。4.4 加入扩频后的Eb/N0归一化说明有一个点特别容易把人绕晕扩频后信号带宽变了Eb/No到底怎么算我的处理方式是先约定Eb1作为归一化基准然后在通带加噪时根据Eb/No算出N0再乘以fs/2得到噪声方差。由于Eb是固定的噪声功率的变化直接反映了信噪比的变化。这样处理的好处是扩频与否不影响Eb的定义扩频只是改变了发信号的带宽结构不影响误码率的理论值。如果你用MATLAB通信工具箱的awgn函数那就需要特别注意它的单位参数。awgn函数是按“信号功率相对于噪声功率”来加噪的传snr参数时必须自己换算成符号信噪比或采样信噪比建议先确认清楚再调用否则结果会莫名其妙差一个10*log10(samplesPerSymbol)。5. 实操结果与异常排查实录5.1 典型错误一误码率始终比理论差3dB这个现象我见过太多次了先别怀疑算法先排查自己的噪声功率是不是算错了。最常见的原因是你用通带信号加噪但噪声方差直接用了N0/2而不是N0*fs/2。这里差的不是一个常数而是一个和采样率相关的因子。fs20kHz时N0fs/210000N0这个10000倍的系数一旦漏掉噪声功率大得夸张误码率直接趋近0.5这不是3dB的问题是完全不可用。如果只是差3dB另一个常见原因是本地载波用了cos而不是2cos。在相干解调时乘cos得到的基带信号幅度只有乘2cos的一半能量只有四分之一信噪比损失6dB。而有些同学用了根号2倍的修正那损失就是3dB。这个处理细节不同教材写法不一样但仿真的判决只关心相对幅度所以在加噪时就要统一好参考点。我的做法是接收端乘2*cos解调分子和分母的功率基准用同一个信号功率这样噪声功率自然地以信号为参考整体书写的代码和理论公式对应关系最清晰。5.2 典型错误二解扩后星座图一团乱如果解扩后的判决统计量即累加输出没有呈现出明显的双峰分布——正半轴一堆点、负半轴一堆点——而是整体都挤在0附近那就说明解扩没有对齐。排查顺序是先确认发送端的PN码和解扩用的PN码是否一致说白了就是复制粘贴时有没有改错变量。再确认解扩窗口的起始位置是否对准码片边界。上采样后每个码片有2个采样点如果你从第2个采样点开始取数那打到的全是码片的中间值幅度减半但至少符号对如果你从第1点和第2点混着取累加时正负相消输出就会被抹平。如果加了低通滤波器记得补偿滤波器群延迟直接改变取数的起始位置即可。我把取数起始点设置成第20个采样点这个20是怎么来的我前面规定了每个信息比特20个采样点低通FIR滤波器阶数40群延迟就是20个采样点所以从第20点开始取数据正好避开滤波器带来的时延让采样时刻落在每个符号的稳态区间。不同滤波器阶数对应的延迟不同这个值要自己调整最好的办法是先发射一个冲激信号看输出峰值位置再往前走半个符号就能得到比较准确的采样起点。5.3 典型错误三高信噪比下误码率平台期误码率到了10^-4或者10^-5就掉不下去了形成一个平台这几乎可以肯定是“定时抖动”或者“符号间干扰”造成的误码地板。出现这种情况通常是你用简单保持零阶保持做上采样接收端没有做匹配滤波符号之间的过渡沿直接干扰采样点。解决办法有两条路一是在发端做完整的脉冲成形比如根升余弦滤波器收端做对应的匹配滤波让ISI降到可忽略的级别。这是正规做法也应该成为后续扩展的方向。二是在收端做数据辅助的定时估计比如早迟门同步器让采样时钟始终对准眼图张开最大的位置。这个比纯固定采样稳健很多。如果是做课程设计我建议至少做第一种——升余弦成形滤波加匹配滤波。仿真里只做理想采样虽然能跑出理论曲线但面试时被问到“为什么要加成形滤波”就答不上来了。5.4 实用调试技巧逐级验证各模块输出这是我最想分享给新手的一个工作习惯也是很多教程不会教的不要最后一次性看误码率而是逐级画波形验证每一个模块的输出。我做这套仿真的时候每完成一个模块就做一次可视化检查调制后观察时域波形是否在比特翻转处有180度相位跳变扩频后观察码片切换是否清晰带宽是否明显展宽加噪后观察信噪比是否大致符合预期可以从频谱上粗看解扩后把累加输出画成直方图看是否双峰最后再统计误码率每级检查都过关了最终的误码率曲线基本不会出幺蛾子。如果误码率不对通过逐级检查也能快速定位是哪一级出了问题不至于把整个代码从头到尾翻三遍。6. 扩展到更多场景的延伸思路这套链路验证完毕之后往上扩展的空间非常大。我简单说几个和当前链路最贴近的方向也正好是面试和答辩中容易追问的内容。6.1 加窄带干扰验证扩频增益既然之前说过AWGN信道下扩频不提升误码率那扩频的价值怎么在仿真里体现答案是加窄带干扰。在信道模型中加入一个单音干扰信号比如在载波附近加一个正弦干扰。比较两种接收机只做BPSK解调没有扩频的接收机和先解扩再BPSK解调的接收机。你会看到在同样干扰功率下扩频系统的误码率明显优于非扩频系统而且干扰越强、扩频倍数越大优势越明显。这个实验能非常直观地验证扩频抗干扰的机理。6.2 更换扩频码观察相关特性影响把m序列替换成Gold序列或者Walsh序列观察误码率变化。如果扩频码的自相关旁瓣有差异在存在定时偏移时误码率表现就会不同这种细微差异是中高级仿真的经典课题也是实际工程中选码的依据。6.3 从BPSK升级到QPSK当你想把链路做成更高阶调制时只需要把映射模块和判决模块替换尤其是把实数基带改成复数基带其余扩频解扩框架都可以复用。这时候你会体会到通信系统模块化设计的价值所在。6.4 加同步模块做成完整接收机目前的仿真依赖理想同步这是仿真和实机的最大差距。下一步可以把定时同步早迟门、载波同步Costas环或导频辅助加进来把“理想同步”这个假设拿掉这时候误码率曲线会有一点损失但整个模型的工程价值会提高一个档次。我做完这套仿真后最大的感受是通信系统的MATLAB仿真真正花时间的地方不在于把代码写出来跑通而在于理解每一个模块背后的物理意义、参数选择和性能边界。把这套BPSK扩频链路吃透后面做QPSK、OFDM、CDMA系统都会顺手很多。希望这篇记录对你有所启发也欢迎在实际仿真的过程中回来对照看看——尤其是那些排查思路的部分我踩过的坑你就不要再踩一遍了。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门