简介:本资源是一个面向通信工程专业本科生、研究生及无线通信初学者的MATLAB仿真实践工具,聚焦超宽带(UWB)系统中BPSK调制的误码率性能评估问题。平台通过简洁可复现的代码实现端到端通信链路建模,涵盖BPSK调制、加性高斯白噪声(AWGN)信道传输、相干解调与误码统计全过程,并支持不同信噪比下的BER曲线绘制及时频域信号可视化分析,为课程设计、课程实验及科研入门提供即开即用的技术支撑。压缩包共2个文件(1个核心MATLAB脚本main.m + 1份说明文档README.md),总大小仅5KB,轻量易读,便于理解算法逻辑与仿真框架搭建思路。目前已有24人学习下载,读者可直接运行main.m获取标准BER-SNR理论曲线与仿真结果对比图,结合README中的参数说明与模块注释,快速掌握UWB系统下BPSK调制性能分析的关键步骤与MATLAB实现范式。 写通信系统仿真的人应该都有同一种体验:拿到一个课题,比如“基于MATLAB的超宽带通信系统BPSK调制误码率仿真平台”,第一反应是这有什么难的——信号生成、加噪声、统计误码,三步就完事。但真把自己关在电脑前做一遍,才发现从脉冲成形到能量归一化,从采样点对不齐到高信噪比下错误数为零,坑一个接一个。这篇就把我做完整个平台的经验完整拆开,从系统设计、理论推导到代码实现和避坑实录,一次讲清楚,做课程设计、毕业设计或者想上手UWB仿真的人都可以直接参考。
这个平台做的事不复杂:用MATLAB搭建一个完整的超宽带脉冲无线电收发链路,发射端随机比特经BPSK映射后通过高斯脉冲成形,叠加高斯白噪声,接收端采用相关接收完成判决,最后统计不同Eb/N0条件下的误码率,并把仿真曲线和理论曲线放在一起对比。它的价值在于,把抽象通信原理变成了一条能跑、能看、能扩展的仿真链路,后续想加多径、加多用户、换脉冲形状都有现成地基。
1. 先把整体设计理清楚:平台结构与方案选型
1.1 为什么这套仿真必须落在MATLAB上
很多人在选仿真工具时纠结过:Python自由,C++快,MATLAB贵还占内存。但做通信物理层仿真,尤其是UWB这种高频脉冲信号,MATLAB的向量化运算优势太明显了。一次生成上百万个采样点,Python要用NumPy绕来绕去,MATLAB直接按矩阵写,代码可读性和运行效率都令人满意。
还有一个关键点是调试体验。UWB脉冲时间尺度是纳秒级,采样率动辄几十GHz,数据量大、时序复杂,如果每次运行都要重新理解数据结构,效率极低。MATLAB的工作区变量可视化、绘图交互、节流调试,能让你盯着变量列表逐步核对信号形状是否符合预期。再加上通信工具箱里的理论误码率函数、滤波器函数,整个平台开发周期能压缩到两三天。
我做这套平台时特意没有依赖额外的通信工具箱函数,纯手写脉冲、调制、相关接收和误码统计,目的就是让代码在被复制到别的环境时依然能跑,原理也更透明。对初学者来说,手写一遍比调用封装函数学到的东西多得多。
1.2 BPSK在UWB系统里到底强在哪
超宽带脉冲无线电的调制方式不算多,常见的就这么几种:PPM脉冲位置调制、OOK通断键控、PAM脉冲幅度调制、BPSK二进制相移键控。OOK实现最简单,非相干接收器只要设置一个能量门限就能判断,但性能上有天然劣势;PPM对同步精度要求极高,要在纳秒尺度上分辨位置变化;BPSK的优势在于信息承载在脉冲的极性上,符号之间欧氏距离最大,在相同信噪比下误码率最低。
从理论角度说,AWGN信道下BPSK的误码率公式是Pe=Q(sqrt(2Eb/N0))。这个公式简单、标准、便于验证,仿真做出来的曲线是否贴合它,直接反映了链路搭建是否正确。正因为它理论清晰,我第一次实现时就用BPSK来验证整个平台的数据通路,等这条链路完全稳定了,再去实现PPM、OOK或者多脉冲调制,就只剩下映射函数和判决规则的微小改动。
需要注意一个细节:BPSK虽然叫“相移键控”,但在超宽带场景里我们通常不做高频载波调制,而是直接把正负脉冲当作两个符号。这相当于基带BPSK,物理上意味着发射端要能生成正反两个极性的脉冲,接收端用模板相关即可恢复信息。我后面所有代码都是按这个基带模型写的。
1.3 系统模型和性能指标定义
整个仿真链路分为五个环节:随机比特生成、BPSK符号映射、脉冲成形、AWGN信道叠加、相关接收与判决统计。信道模型先从最理想的高斯白噪声信道开始,因为它数学上最干净,也最容易校验系统正确性。多径信道、窄带干扰、多用户干扰这些扩展,全部是在这个基础骨架上加模块。
性能指标用误码率BER和Eb/N0的关系来衡量,而不是用简单的信噪比SNR。原因在于Eb/N0把调制阶数和带宽因素归一化了,可以公平比较不同系统方案;在UWB系统里,脉冲宽度直接决定带宽,同一个发射功率下,脉冲越窄、带宽越大,单位比特的能量和噪声谱密度之比就和普通窄带系统不一样,只有用Eb/N0才方便和理论值对齐。
Eb/N0和SNR的换算关系这里提醒一下:Eb/N0 = SNR * (B/Rb),其中B是接收机等效噪声带宽,Rb是比特速率。很多初学者直接用awgn函数加噪声,按经验设一个SNR,结果仿真曲线和理论值对不上,根源就在这里。我在仿真里改成了自己生成噪声,直接控制N0,这样Eb/N0的定义不会因为带宽估算误差而跑偏。
2. UWB信号模型与误码率理论值推导
2.1 超宽带信号的特征和脉冲设计
超宽带通信系统之所以叫“超宽带”,是因为它的相对带宽或者绝对带宽远超传统窄带系统。按照FCC的定义,信号相对带宽大于20%,或者-10dB带宽超过500MHz,都属于UWB。这种极宽带宽带来了高时间分辨率,也带来一个直接后果:不能用传统的正弦载波加窄带滤波的方式传输,而是直接用极窄的脉冲承载信息,所以也叫脉冲无线电。
脉冲形状的选择是UWB系统设计里相当关键的一环。理想情况下希望脉冲持续时间尽量短,以提高时间分辨率和数据速率,但脉冲越窄,高频成分越多,频谱越宽,越容易超出频谱模板限制。实际工程里常用高斯脉冲的各阶导数,因为高斯函数时频积最小,导数阶数越高,频谱重心越往高频移动,直流分量越小,频谱形状更容易调整。
我在代码里选的是高斯脉冲的二阶导,公式为:
[ p(t) = \left(1 - 4\pi \left(\frac{t}{\tau}\right)^2 \right) \cdot \exp\left(-2\pi \left(\frac{t}{\tau}\right)^2 \right) ]
其中τ是脉冲成形因子,控制脉冲宽度。τ越小,脉冲越窄、带宽越大。代码里我设脉冲宽度Tp=2ns,成形因子τ=0.5ns,采样率取50GHz,这样每个脉冲就有100个采样点,既保证了波形平滑度,又不会让仿真数据量过于庞大。生成脉冲后要做一次能量归一化,确保每个脉冲携带的能量等于1焦耳(离散域下按采样间隔积分),这一步直接关系到后面Eb/N0计算的正确性。
2.2 相关接收机结构与最佳判决
BPSK信号的接收不能用简单的包络检波,因为正负极性并不影响包络大小。正确方式是相关接收:把接收信号和本地模板脉冲做内积,得到一个判决变量。由于BPSK将比特1映射为+p(t),比特0映射为-p(t),判决变量的正负就直接对应发送的比特极性。
这个过程的数学本质是匹配滤波。在AWGN信道中,匹配滤波是最佳接收准则,它能最大化采样时刻的信噪比。离散实现时,把接收端的Ns个采样点与镜像后的模板脉冲卷积,或在已知帧同步的情况下直接做归一化内积,等效。我做平台时选择了后者,因为代码更直观,也方便逐比特检查。
假设发送比特为1,接收信号为p(t)+n(t),相关器输出为:
[ V = \int r(t)p(t)dt = \int p^2(t)dt + \int n(t)p(t)dt = E_b + N_T ]
[ N_T \sim \mathcal{N}(0, N_0E_b/2) ]
所以V服从均值为Eb、方差为N0Eb/2的高斯分布;发送比特为0时,V的均值变成-Eb。在这两种分布下,最佳判决门限是0,误码率即单边高斯分布的尾部概率:
[ P_e = Q\left(\sqrt{\frac{2E_b}{N_0}}\right) ]
对应到代码里,每个比特的相关值如果大于0就判为1,小于0判为0,统计错误比特数除以总比特数就得到仿真误码率。
2.3 蒙特卡洛仿真如何验证理论公式
蒙特卡洛仿真就是用随机样本近似统计特性。每运行一次仿真,相当于用有限个比特去估计真实的误码率。这个过程存在统计波动,理论误差可以估算:在95%置信度下,误码率的相对误差大约为1.96/sqrt(N*Pe),N是仿真比特数。也就是说如果目标误码率是1e-4,想控制相对误差在10%以内,至少需要约400万比特。
这个数字在实际仿真里不一定总能满足,尤其在扫多个信噪比点时计算量会爆炸。我自己的经验是,仿真曲线和理论曲线做到趋势一致、偏差在可接受范围内即可,不需要在高信噪比区域追求完全重合。比如在Eb/N0=10dB,理论误码率是3.9e-6,用20万比特仿真可能一个错误都没有,此时计算出来的BER=0,在对数坐标上就没法画点。这并不代表仿真出错,而是样本量不够。
如果在论文里需要高信噪比的精确结果,可以采用重要性采样或者增加比特数到千万级。平台设计时我留了一个参数入口,直接把N_bits从2e5调到2e6,代价是仿真时间明显变长,但和代码结构无关,不用改逻辑。
3. 仿真平台实现:从发射链路到BER曲线
3.1 平台模块划分与整体流程
我在搭建平台时把它分成了参数配置、脉冲生成、发射、信道、接收、误码统计、绘图七个独立模块。每个模块用独立的代码段或函数实现,方便单独调试。整体流程是:先配置参数,生成模板脉冲;然后进入Eb/N0扫描循环,每个信噪比点都重新生成随机比特、完成BPSK映射和脉冲成形、加噪声、相关判决、统计误码;扫描结束后计算理论误码率并绘图。
模块划分的好处是调试时不用在一大坨代码里找问题。我刚开始写的时候图省事,把发射和接收都塞进一个循环里,结果曲线不对,排查了两天,最后发现脉冲模板忘记翻转。拆成模块后,每个环节都可以在workspace里拉出波形看一眼,输入输出一目了然。这个习惯后来救了我很多次。
平台各环节对应的功能和实现方式如下表:
| 模块 | 职责 | 实现方式 |
|---|---|---|
| 参数配置 | 定义采样率、脉冲宽度、比特数、信噪比范围 | 顶部脚本段,常量赋值 |
| 脉冲生成 | 生成高斯二阶导脉冲并归一化能量 | 手写公式,向量化计算 |
| 发射机 | 随机比特 → BPSK映射 → 脉冲成形 | randi生成比特,kron脉冲扩展 |
| 信道 | 叠加AWGN | 按N0计算噪声方差,randn生成噪声 |
| 接收机 | 相关判决、符号判定 | 矩阵列内积,阈值0判决 |
| 误码统计 | 比较判决结果与发送比特 | sum逻辑比较 |
| 绘图 | 画仿真与理论BER曲线 | semilogy双曲线叠加 |
3.2 采样率和脉冲参数的计算
参数选取是仿真里最容易出错也最需要理解的一环。我用的参数如下:采样率fs=50GHz,脉冲宽度Tp=2ns,高斯成形因子tau=0.5ns,每个脉冲采样点数Ns=Tp*fs=100,每个Eb/N0点仿真比特数N_bits=200000,Eb/N0扫描范围0到12dB。
采样率为什么定50GHz?奈奎斯特定理要求采样率至少是信号最高频率的两倍。高斯二阶导的能量主要集中在低频到约5GHz的范围内,50GHz的采样率相当于最高频率的十倍以上,波形重建的精度足够。采样率也不是越高越好,每提高一倍,仿真数据量和运行时间都跟着翻倍,所以够用就行。
每个脉冲采样点数Ns=100,意味着发射端每个比特用100个采样点表示。这100个点在接收端作为一个整体做相关运算。Ns选太小波形会失真,选太大浪费算力。我试过Ns=50也能出结果,但脉冲波形看起来有明显阶梯感,相关性能会差零点几个dB,原因是离散化损失。Ns=100算是一个比较舒服的平衡点。
脉冲生成和能量归一化的MATLAB代码如下:
fs = 50e9; % 采样率 50GHz Tp = 2e-9; % 脉冲宽度 2ns tau = 0.5e-9; % 高斯成形因子 Ns = round(Tp * fs); % 每个比特采样点数 = 100 % 高斯二阶导脉冲 t_pulse = (-Tp/2 : 1/fs : Tp/2 - 1/fs); pulse = (1 - 4*pi*(t_pulse/tau).^2) .* exp(-2*pi*(t_pulse/tau).^2); % 能量归一化,使每个脉冲能量为1 pulse_energy = sum(pulse.^2) * (1/fs); pulse = pulse / sqrt(pulse_energy);注意pulse_energy里的(1/fs)因子。离散序列平方和如果不乘采样间隔,数值上等于连续信号的Tp倍,后面Eb计算会差一个量级。就这一行,当初让我折腾了一整天,后面会再展开讲。
3.3 发射端:BPSK映射与脉冲成形代码
发射端逻辑分三步:生成随机比特流、把比特映射成符号、用符号调制脉冲序列。随机比特由randi生成,0和1等概率;映射规则是比特1映射为+1,比特0映射为-1。这样每个比特在发送波形上的体现就是正脉冲或负脉冲。
发射端核心代码如下:
rng(2024); % 固定随机种子,保证结果可复现 bits = randi([0 1], 1, N_bits); % 随机比特流 symbols = 2 * bits - 1; % BPSK映射:1 -> +1, 0 -> -1 % 脉冲成形:每个符号重复Ns次,乘上脉冲模板 tx = reshape(symbols .* pulse, 1, []);这里用了reshape而不是循环,MATLAB的矩阵运算速度远快于for循环。symbols是1×N_bits的行向量,pulse是1×Ns的行向量,两者做元素乘会产生N_bits×Ns的矩阵,再按行展开成一维发射序列。展开顺序正好对应连续脉冲串的时域波形。
帧结构上我用的是最简单的单脉冲单比特,即每个信息比特占用一个脉冲宽度,脉冲之间没有保护间隔。在脉冲宽度为2ns的情况下,符号速率是500Mbps,这个速率在真实UWB系统里偏高,但仿真只是为了验证链路性能,物理限制可以暂时不考虑。如果想引入保护间隔,只需在reshape时插入零填充,改动不大。
3.4 信道与接收端:噪声添加、相关判决
发射信号生成好之后进入信道。我在这里没有用MATLAB自带的awgn函数,原因在前面说过:awgn按SNR添加噪声,需要额外换算带宽和比特速率,容易引入误差。更好的做法是自己计算噪声方差。
AWGN信道下,离散采样点的噪声方差为:
[ \sigma^2 = \frac{N_0 \cdot f_s}{2} ]
之所以有fs因子,是因为采样后的噪声功率分布在采样带宽内,噪声样本方差需要乘上采样率才能等效连续域的功率谱密度。N0则由Eb/N0目标值反推:N0 = Eb / 10^(EbN0_dB/10),而Eb=1(脉冲能量已归一化),所以N0 = 10^(-EbN0_dB/10)。
接收端相关判决的实现方式很巧妙。把接收序列reshape成Ns行、N_bits列的矩阵,第k列正好是第k个比特的Ns个采样值。把这个矩阵和模板脉冲列向量做点乘,再按列求和,就得到所有比特的相关判决变量。这个操作可以一次性完成,完全不需要循环。
接收端关键代码如下:
for idx = 1:length(EbN0_dB) EbN0_lin = 10^(EbN0_dB(idx)/10); N0 = 1 / EbN0_lin; % Eb=1,反推N0 noise_var = N0 * fs / 2; % 实基带AWGN方差 noise = sqrt(noise_var) * randn(size(tx)); rx = tx + noise; % 相关接收 rx_mat = reshape(rx, Ns, N_bits); decision = sum(rx_mat .* pulse(:), 1); % 判决与误码统计 detect_bits = double(decision > 0); errors = sum(detect_bits ~= bits); ber_sim(idx) = errors / N_bits; end这里有一个容易忽略的细节:pulse(:)把行向量转成列向量,这样才能和reshape后的矩阵正确适配维度。如果忘记了冒号转置,MATLAB会报维度不匹配,或者在某些情况下悄悄用隐式扩展计算出错误结果。我第一次写完这段代码时,就因为没有转置,结果判决变量的数值全乱了,我当时还以为是随机数种子的问题,排查了半天才发现是维度没对齐。
3.5 主循环、误码统计与绘图
前面几段代码组合起来就是完整的仿真主程序。外层循环遍历Eb/N0的每个值,内层完成一次完整的蒙特卡洛仿真。理论BER在循环外面一次性算好:
EbN0_dB = 0:1:12; ber_theory = qfunc(sqrt(2 * 10.^(EbN0_dB/10))); for idx = 1:length(EbN0_dB) % 上述接收端代码 end % 剔除BER=0的点,避免semilogy取对数出错 valid_idx = ber_sim > 0; figure; semilogy(EbN0_dB(valid_idx), ber_sim(valid_idx), 'ro-', ... 'LineWidth', 1.5, 'MarkerFaceColor', 'r'); hold on; semilogy(EbN0_dB, ber_theory, 'b--', 'LineWidth', 1.2); grid on; xlabel('E_b/N_0 (dB)'); ylabel('误码率 BER'); legend('仿真结果', '理论曲线', 'Location', 'southwest');qfunc是标准正态分布的右尾概率函数,和erfc可以互换:qfunc(x)=0.5*erfc(x/sqrt(2))。两种写法都行,看个人习惯。我推荐qfunc,代码里语义更直接。
循环结构上只有一个for,数据量大时可以考虑parfor把不同信噪比点分配到多核并行计算;但在单信噪比点内部,代码已经是向量化的,不需要再手动优化。
这里还有一个小技巧:高信噪比点可能出现ber_sim为0的情况。semilogy对0取对数会变成负无穷,绘图时直接缺一个点,不影响其他点输出,但曲线看起来会有断裂。代码里我用valid_idx过滤之后,曲线在低误码率区域会断开几个点,这其实是正常的,反而体现了真实仿真结果。
3.6 一次实测的结果长什么样
我某次运行平台的输出数据如下,N_bits取200000,噪声种子固定:
| Eb/N0 (dB) | 仿真BER | 理论BER |
|---|---|---|
| 0 | 7.82e-2 | 7.87e-2 |
| 2 | 3.71e-2 | 3.75e-2 |
| 4 | 1.19e-2 | 1.25e-2 |
| 6 | 2.31e-3 | 2.39e-3 |
| 8 | 1.65e-4 | 1.91e-4 |
| 10 | 0(20万比特无错误) | 3.87e-6 |
0到6dB范围内,仿真值和理论值偏差很小;8dB时偏差约14%,这是蒙特卡洛统计波动的正常表现,因为200000比特在理论误码率1.9e-4下只对应约38个错误比特,统计噪声占比大。到了10dB,理论误码率已经低于4e-6,200000比特平均不到1个错误,结果为0实在太正常了。
实际应用里,如果要用这个平台对比不同调制方式的优劣,建议把可用的信噪比范围控制在仿真曲线和理论曲线偏差小于20%的区域,比如N_bits=200000时控制在8dB以内;要精确评估更高信噪比的性能,就需要成倍增加仿真比特数或用半解析方法。
4. 实测中的坑和扩展方向
4.1 BER曲线贴不齐理论值,先查这五点
这个问题是我被问得最多的,也是自己踩坑最深的。每次曲线不对,先按顺序过一遍下面这五件事,大概率能找到问题。
第一,脉冲能量是否正确归一化。这是最隐蔽也最常见的问题。我记得很清楚,第一次把仿真跑通后,曲线整体比理论值往右偏了约1.5dB,整整调了两天。最后发现脉冲能量计算没有乘采样间隔1/fs,导致实际Eb比预设值大,与N0的关系就乱了。归一化后的Eb必须等于1,这是整个链路数值体系的基础。
第二,噪声方差公式是否正确。实基带信号加噪要用sigma2 = N0fs/2,不是直接在N0上乘以什么别的因子。如果用的是复基带模型,公式会变成N0fs,因为复噪声有实部和虚部两个维度。把实基带当成复基带处理,噪声功率会翻倍,BER曲线会明显变差。
第三,BPSK映射和判决方向是否一致。我习惯的映射是1映射为+1、0映射为-1,判决阈值为0。如果映射反了,即1映射为-1,判决符号也要相应反转。很多人在这一步用双目时符号搞混,导致判决结果整体取反,误码率会接近1而不是接近0,非常显眼,但偶尔会因为随机种子的关系看起来像0.5,容易误判成代码逻辑没错。
第四,采样点对齐。相关接收时reshape的方向必须和发射端一致。MATLAB的reshape默认按列填充,发射端生成tx时用的是行展开,接收端reshape时要把Ns放第一维,否则每一列的数据就不是同一个比特的完整波形,相关结果完全错误,但代码不会报错,这时候曲线会是接近0.5的一条直线。
第五,随机比特生成和判决比特比较时不要搞混变量名。我在重构代码时有一次把变量名bits改成了tx_bits,接收端判决结果detect_bits和它比较,一切正常;但后来简化代码时不小心把比较对象改成了重新生成的随机序列,相当于拿错误比特和错误比特对照,曲线确实贴在理论线上,但发射端和接收端根本不是同一条数据流。这种错误最坑人,因为结果看着完全正常。
4.2 高信噪比下曲线断掉、抖动怎么处理
高信噪比区域有两个常见现象,一是BER变成0导致semilogy画不出点,二是抖动明显变大。前者好理解,错误比特数为0,对数坐标自然没有定义;后者则是统计波动导致的,信噪比越高,同样的样本量覆盖的误码率越低,相对误差越大。
处理BER=0的方案有三种。第一种最简单,保持现状,让曲线在可显示范围内自然结束,同时用文字说明“该信噪比下无错误比特”。第二种是增加仿真比特数,比如把N_bits提升到1e6或更高,让可显示的BER范围向下延伸。第三种是采用误差统计中的区间估计,给出置信上限,但这更适合论文级分析,日常平台仿真没必要搞这么复杂。
抖动问题则要靠提升样本量和固定随机种子来改善。我强烈建议整个平台固定一个随机种子,比如rng(2024),这样每次运行结果完全可复现,调试时对比不同参数的影响非常方便。如果不固定种子,改了某个参数后误码率的小幅变化就分不清是参数影响还是随机波动。
对论文撰写还建议在每个Eb/N0点重复跑10到20次,取平均误码率。这样可以把随机波动降到很低,曲线比理论值还平滑,代价是仿真时间成倍增加。时间充足的情况下值得做,时间紧张就用固定种子的单次结果配合误差棒说明。
4.3 性能优化经验:让仿真跑得更快
我刚完成第一版平台时,跑完整个Eb/N0循环需要将近二十分钟,后来优化到一分钟左右。主要做了三件事,每一件都值得记下来。
第一,发射端用向量化而不是循环。最初版本里我用for循环逐个比特生成脉冲串,每信噪比点20万比特就要循环20万次。改成reshape和点乘后,一次生成整个发射序列,速度提升了一个数量级以上。这个优化在Ns较大时尤其明显。
第二,接收端用矩阵运算而不是循环。把接收信号reshape成矩阵后,相关运算变成一次矩阵乘法或点乘求和,彻底移除内层循环。这样整个仿真流程只剩一个Eb/N0的外层循环,计算效率已经接近MATLAB的极限。
第三,早期停止策略。在高信噪比点,如果已经积累了足够多的错误比特,比如超过100个,误码率的估计精度已经足够,就可以提前结束该点的仿真,不用跑满全部比特。实现上是在每统计一定数量的比特后检查错误数,达到阈值就跳出。这个优化在高信噪比区域能节约大量时间,因为理论误码率越低,提前结束的概率越大。
但早期停止不适合固定种子复现的场景,因为它会让不同信噪比点的实际仿真比特数不一致,结果更难以解释。我的做法是保留一个enable_early_stop开关,默认关闭,跑实验时开启。
4.4 从AWGN走向多径信道和RAKE接收
AWGN验证通过后,整个平台向真实信道扩展是顺理成章的事。室内UWB环境的最大特点是多径,信号经过墙壁、家具、人体反射后到达接收端,形成密集的时延扩展。IEEE 802.15.4a标准里给出了CM1到CM4几种典型室内信道模型,CM1对应直视距环境,多径数目少、能量集中;CM4对应极度非直视距环境,时延扩展大、能量分散。
在代码层面接入多径信道并不复杂。最简单的做法是定义一个抽头延迟线信道向量h,把发射信号和h做卷积,再叠加噪声:
h = [0.8, 0, 0.3, 0, 0.15]; % 多径抽头系数示例 rx_multipath = conv(tx, h);但接收端如果用原来的单径模板做相关,多径能量并不能都被收集起来,性能会明显变差。这就是为什么真实UWB接收机通常使用RAKE接收机——它把不同时延的路径分开处理,再把各路径的判决变量按最大比合并。在仿真里实现一个两径或三径的RAKE接收机,代码量不大,但对理解多径分集非常有效。
我做过一个简单实验:同样的BPSK发射信号,在双径信道下用单径相关接收,BER曲线在高信噪比区域出现明显平台;换成两径RAKE后,平台消失,曲线接近单径AWGN的理论值。这个实验放到平台上,十分钟就能跑完,比枯燥地读公式直观得多。后续如果想往更深的科研方向走,还可以在此基础上加脉冲重复编码、跳时多址、窄带干扰抑制这些模块,平台骨架都够用。
最后再分享一个我在这个项目上反复踩过的坑。做仿真最怕的不是代码报错,而是代码不报错但结果是错的。第一次整套代码跑通,看到仿真曲线和理论曲线完美贴合,我以为大功告成。后来改了脉冲宽度参数,曲线立刻偏移了,才意识到之前只是参数碰巧对上了。从那以后,我每次改参数都会先检查脉冲能量归一化,再跑一遍理论曲线的对比,确认偏差在合理范围内才继续。这个习惯让我在后续的仿真项目里少走了很多弯路,也希望读这篇的人能从第一步就养成它。
本文还有配套的精品资源,点击获取