BPSK仿真中的上采样与下采样:从插值滤波到采样点对齐的工程实践
2026/9/14 3:02:39 网站建设 项目流程

简介:面向数字信号处理与通信初学者的MATLAB源码包,聚焦BPSK调制中的上采样与下采样关键步骤。上采样通过插入零值提升采样率,下采样通过抽取采样点降低数据率,两者是采样率转换、抗混叠滤波器和系统仿真中的基础操作,而BPSK作为最简数字调制方式,非常适合用来演示采样率变化对信号频谱的影响,也是理解奈奎斯特定理与抗混叠原则的直观入口。资源为rar压缩包,包含2个m文件,总计仅918B,代码精简,便于阅读和修改,可直接嵌入课程设计或通信系统仿真流程。目前已有296人学习/下载,适合通信工程、电子信息类专业学生及MATLAB初学者。通过这两个函数脚本,读者可以快速建立上采样与下采样前后的信号波形对比,直观理解插值与抽取的数学意义,并能结合BPSK系统观察不同采样率下的误码率变化,为后续滤波器与同步设计提供可直接运行的基础模块。

1. BPSK 仿真里最容易翻车的不是调制,而是上下采样

BPSK 的调制解调逻辑简单到几乎没有理解门槛:比特映射、乘以载波、判个符号极性,误码率曲线好像天生就该贴着理论值走。真正让整条 Matlab 链路统计失真、眼图散掉、BER 怎么都压不下来的,往往是上采样和 downsampling 这两步——插入零之后到底要不要滤波、匹配滤波之后从哪个点开始往下抽、滤波器群延迟补几个采样周期,每个细节都能让误码率从 1e-6 变成 0.1。本文就围绕这一点展开:先说清上采样、下采样的信号模型,再给出一段可复现的 BPSK 基带链路脚本,最后讨论滤波器选型和采样点位置这类工程问题。适合做通信课设、算法预研,以及给 AD9361 这类射频前端做离线上变频、下变频验证的工程师。

2. BPSK上采样与下采样的信号模型:插值、抽取和抗混叠边界

2.1 从符号速率到采样速率:为什么 BPSK 基带必须有一串每符号多个样本的序列

BPSK 发送的是一串 +1/-1 符号,数学上可以写成冲激序列与脉冲成形滤波器的卷积。但直接在符号级做离散仿真是不成立的,因为乘法、加噪声、定时同步都发生在波形级别,而波形必须在较高的采样率下才能刻画。常见的做法是设定一个码速率Rb,再取采样速率Fs = sps × Rb,其中sps是每符号采样数。做基带仿真时sps通常取 4、8、16;取太低,脉冲成形的旁瓣在离散域就展不开,取太高则内存和计算量白白翻倍。

Rb = 1e6; % 符号速率 / 比特速率,BPSK 下两者相等 sps = 8; % 每符号采样数 Fs = Rb * sps % 采样速率 = 8 MHz

sps本质是一个采样点计算公式:Fs / Rb。它决定了后续upsample时插零的倍数,也决定了接收端downsample时每隔几个样本取一个判决点。需要记清楚:sps不是随便填的,它必须在发射、接收两端保持一致,但凡一端拿 8、另一端拿 4,符号定时就对不上。若仿真里用根升余弦滤波器和awgn信道,sps低于 2 时滤波器的频域滚降无法在离散域正确展开,眼图基本锁不住,实际工程也最少取 4。

2.2 上采样不是简单插零:插值、频谱压缩与镜像拖尾

Matlab 里做整数倍上采样最直接的是upsample(x, N),它做的事情是在每两个相邻样本之间插入N-1个零。这个操作在频域的效果是:原始频谱被压缩 N 倍,并且在2π/N的整数倍位置复制出镜像频谱。注意,插零本身不会产生新的频率分量,但会让单位带宽内的能量被摊薄,直接把插零后的序列送去 DAC 或后续级联,带外镜像会导致频谱掩膜超标、邻道泄漏不可控。

xUpsample = upsample(symbols, sps); % symbols 为 +1/-1 序列 figure; pwelch(xUpsample, [], [], [], Fs);

这段代码画出插零上采样后序列的功率谱,可以清楚看到主瓣两侧的镜像周期。实际链路里upsample之后必须级联脉冲成形滤波器,既承担插值平滑的职责,又把带外镜像压下去。频率响应上,镜像的位置在符号速率整数倍处,根升余弦或者升余弦滤波器只要滚降系数设计合理,镜像抑制能轻松做到 40 dB 以上。仿真中常见错误是拿interp或线性插值替代插零+RRC,这两者在最小带宽系统里会引入可观的码间干扰,因为线性插值不是奈奎斯特滤波器。

2.3 下采样的混叠边界:downsample、decimate、resample 三者的区别

下采样在数学上做的是抽取:y[n] = x[Dn],输出采样率降为原来的1/D。但抽取前必须满足信号带宽小于折叠频率π/D,否则高频分量折叠回通带,产生不可逆混叠。Matlab 的三个函数对应三种策略:downsample是纯抽取,不滤波,只适合信号本身已是窄带的情形;decimate抽取前自带低通抗混叠,不过它默认的 Chebyshev 滤波器群延迟较大;resample则处理有理数倍率变换,内部自动计算插值和抽取的级联。

% 错误示范:直接 downsample,混叠会把噪声折进通带 yBad = downsample(rxFiltered, D); % 正确做法:先匹配滤波,再 decimate 或手动抽样 yGood1 = decimate(rxFiltered, D); % 自带抗混叠滤波 yGood2 = rxFiltertered(1 : D : end); % 手动抽样,前提是前面已滤波

BPSK 链路里,接收端的匹配滤波器本身就是低通特性,因此常见做法是让匹配滤波同时承担抗混叠职责,然后再手动抽样,这比额外加一级decimate更省事,也更容易控制采样相位。必须记住一个原则:上采样先插零后滤波,下采样先滤波后抽取。顺序反了,频谱的镜像或混叠就会直接毁掉误码率曲线。

3. 在 Matlab 搭一条可复现的 BPSK 上采样–下采样链路

3.1 参数选择:码速率、采样速率、滚降系数最少要定四个值

动手写代码之前,先把仿真参数固定下来。最常用的一组取值是:符号速率 1 Mbps,采样速率 8 MHz,即sps = 8;根升余弦滚降系数 0.35,滤波器跨度 6 个符号;蒙特卡洛符号数至少 20000,才能把 1e-4 量级的误码率统计出来。滚降系数越大,占用带宽越大,但定时偏移容忍度越好;0.35 是无线通信里均衡得很好的折中值。

参数推荐值说明
Rb1e6信息速率,决定仿真时长
sps8每符号采样数,建议 4~16
rolloff0.35滚降系数,越小带宽越窄
span6滤波器覆盖符号数,影响群延迟
nSymbol20000统计 BER 用的符号数
EbN0dB0~12扫这组值画 BER 曲线

这里最容易被忽略的是span,它直接决定滤波器抽头数span*sps+1,也就决定了群延迟大小。后面做下采样时刻对齐时,span必须和rcosdesign调用保持一致,改一个数两个地方一起改。

3.2 完整链路脚本:上采样、成型滤波、加噪、匹配滤波、下采样与误码统计

下面这段脚本是一个最小完整的 BPSK 基带仿真,重点全在上采样与下采样的配合上。把整数倍速率变换的每个环节拆开写,方便看清每一步在做的事情。

% BPSK 上采样-下采样基带链路 Rb = 1e6; sps = 8; Fs = Rb*sps; nSymbol = 2e4; rolloff = 0.35; span = 6; EbN0dB = 10; % 发射端 dataBits = randi([0 1], nSymbol, 1); symbols = 2*dataBits - 1; % BPSK 映射:0 -> -1,1 -> +1 xUpsample = upsample(symbols, sps); % 上采样:插零 txPulse = rcosdesign(rolloff, span, sps, 'sqrt'); % 发射成型滤波器 txSignal = filter(txPulse, 1, xUpsample); % 成型滤波 txSignal = txSignal / sqrt(mean(abs(txSignal).^2));% 归一化到单位功率 % AWGN 信道 snr = EbN0dB - 10*log10(sps); % BPSK 实基带: Eb/N0 -> 符号SNR rxSignal = awgn(txSignal, snr, 'measured'); % 接收端 rxMatched = filter(txPulse, 1, rxSignal); % 匹配滤波 delay = (length(txPulse) - 1) / 2; % 单次滤波群延迟 tStart = 2*delay + 1; % 两次滤波总延迟补偿 % 下采样:每隔 sps 个样本取一个判决点 samples = rxMatched(tStart : sps : end); rxBits = samples > 0; % 极性判决 % 误码率统计 ber = biterr(dataBits, rxBits(1:nSymbol)) / nSymbol; berTheory = berawgn(EbN0dB, 'psk', 2, 'nondiff'); fprintf('EbN0 = %.2f dB, BER Sim = %.2e, Theory = %.2e\n', ... EbN0dB, ber, berTheory);

链路逻辑分四段。发射端先做upsample插零,再用根升余弦滤波器成型;这里滤波器的作用是平滑插零造成的阶梯波形,同时限制信号带宽。信道部分用awgn按符号信噪比加白噪声,snr = EbN0dB - 10*log10(sps)这个换算是将每比特能量折算到每符号采样能量上,一整条 BPSK 实基带链路都用这个公式,如果加了复数载波还要再减 3 dB。接收端的filter(txPulse, 1, rxSignal)是对接收信号做匹配滤波,等价于与发送脉冲做相关。关键在下采样那行:rxMatched(tStart : sps : end)是从补偿完群延迟的起点开始,每隔sps个样本抽一个采样。

3.3 群延迟为什么是 2×delay+1:最常见的翻车点

很多人在接收端只补偿一次滤波器延迟就开始抽样,结果眼图看起来是睁开的,误码率却怎么都不对。原因在于根升余弦滤波器是发射端和接收端各一个的,两段级联后才构成完整的奈奎斯特滤波。rcosdesign返回的滤波器长度是span*sps+1 = 49,峰值位于正中间索引 25,群延迟delay = (49-1)/2 = 24个采样周期。发射滤波把符号冲激延迟 24 个点,接收匹配滤波又延迟 24 个点,总延迟就是 48 个采样点,对应到从 1 开始计数的数组索引,就是代码里的tStart = 2*delay + 1 = 49

% 错误补偿方式:只补一次群延迟,BER 会高到离谱 tStartBad = delay + 1; samplesBad = rxMatched(tStartBad : sps : end);

这里的+1是 Matlab 数组从 1 编号带来的偏移,别漏掉。如果改成单边带或 QPSK 链路,滤波器个数变了,总延迟的计算也要跟着变。一个更稳妥的做法是用finddelay或直接发一个单脉冲做相关,用相关性峰值位置来锁定抽样起点,但代价是每次仿真都多一步,仿真规模大时不如直接算tStart

4. 从仿真到联调:滤波器选型、非整数倍采样率变换与采样点裕量

4.1 根升余弦的四个参数边界:sps、rolloff、span、sqrt 谁动了会怎样

rcosdesign(rolloff, span, sps, 'sqrt')这四个参数各管一段:sps决定插值的密度,改大等于让每符号采样点数变多,抗混叠更容易,但计算量线性上涨;rolloff决定带宽因子(1+rolloff)/2,低于 0.2 后滤波器过渡带极窄,群延迟波动变大,对定时偏移极敏感;span决定滤波器截断长度,低于 4 时截断能量泄露明显,高于 10 时增益有限而延迟成倍增加;'sqrt'表示使用根升余弦,这是发射端和接收端各分担一半滚降的标准做法。如果漏掉'sqrt'只用普通升余弦,那接收端就不该再级联第二个滤波器,否则等效四次方滚降,带宽被急剧压缩。

对 5 年以上工程师来说,更值得注意的是spsrolloff的耦合关系。当sps=2rolloff=0.35时,滤波器通带边缘接近折叠频率,频域过渡带几乎没有裕量,实际离散实现会有明显 ISI 恶化;因此我在工程里做sps=2的链路时,会把rolloff压到 0.5 以上换性能。而sps=4以上时 0.22~0.35 的低滚降才能正常工作。这个边界不是公式写死的,而是离散采样点数不足以容纳陡峭过渡带的直接后果。

4.2 半带滤波器与 CIC:多级抽取和插值的工程取舍

BPSK 仿真做完,紧接着就是两件事:一是把波形搬回基带,二是把过高采样率降下来。高倍数的下采样如果一次抽取到位,抗混叠滤波器阶数会非常高。常见的工程做法是分级抽取:先在半带滤波器处做 2 倍抽取,再用 CIC 或 FIR 继续降。半带滤波器通带截止在Fs/4,过渡带以Fs/2为对称中心,一半系数为零,运算量比同阶 FIR 少一半;CIC 则完全不需要乘法器,适合 FPGA 里做最后一级大倍数抽取。

% 两级下采样示例:先半带 2 倍,再 FIR 2 倍 hHalf = firhalfband('minorder', 0.5, 'kaiser'); % 通带在 Fs/4 xStage1 = filter(hHalf, 1, rxMatched); xStage1 = xStage1(1 : 2 : end); % 第一级抽取 2 倍 hLast = fir1(32, 0.5); % 第二级抗混叠 xStage2 = filter(hLast, 1, xStage1); xDown = xStage2(1 : 2 : end); % 第二级再抽 2 倍

firhalfband来自 DSP System Toolbox,没有它的环境可以用firpm设计线性相位半带。级联抽取的关键约束是:每一级抽取前的滤波器通带都必须小于该级抽取后剩余采样率的一半,否则当前级就已经混叠了,后面滤波救不回来。具体到这段代码,rxMatched是 8 MHz,半带通带 2 MHz,抽到 4 MHz,裕量充足;第二级fir1(32,0.5)通带约 1 MHz,抽到 2 MHz,也安全。CIC 在这里的价值是在大抽取倍数下用积分-梳状结构省资源,但它的通带纹波明显,通常要在 CIC 后面再接一级补偿 FIR。

非整数倍速率匹配也是联调常客,比如接收机采样 8 MHz、解调器只接受 5 MHz 采样率,这时候直接整数抽取做不到,resample把问题拆成先插值再抽取,内部用多相滤波器一次成型。要注意resample(p, q)里 p 和 q 是插值、抽取因子,必须约分,否则计算量和滤波器质量双双变差。

4.3 采样点选在眼图哪里:BPSK 的采样相位和 CAN FD 采样点设置是同一个问题

下采样不是按下鼠标自动完成的,你必须决定时刻tStart落在眼图的哪个位置。BPSK 的眼图在符号周期内存在一个大开的“眼睛”,最佳采样点位于眼睛张开宽度和高度最大的那一列纵切线上;向左或向右偏,码间干扰和噪声容限同时恶化。这个问题和 CAN FD 总线采样点设置思路一模一样:CAN FD 要在位时间 70%~80% 处采样以避开跳变沿,BPSK 则应在符号中段也就是眼图中心采样,只是 BPSK 的“位时间”就是sps个样本,70% 对应大约第 5~6 个样本附近。

% 观察采样点位置:匹配滤波后、抽取前的眼图 eyediagram(rxMatched(tStart:end), sps, 1/Rb);

eyediagram的横轴按符号周期归一化,竖线范围就是采样时刻相对符号起点的偏移。脚本里tStart已经把采样点顶在峰值处,实际跑起来eyediagram会看到一条干净的竖线扫过眼睛正中。如果这条竖线偏向眼睛边缘,或者眼睛闭合明显,优先检查两件事:群延迟补偿是否 2 倍,以及spsrolloff是否匹配。硬件联调时,接收端 ADC 采样的时刻由 FPGA 的计数器决定,基带仿真的tStart就是那个计数器的行为模型;这是模拟采样电路里孔径抖动的数字域对应,定时抖动在两边都表现为采样点相对眼图中心的偏移。

注意:eyediagram看的一定是匹配滤波之后的信号。看滤波前的波形,眼图会被带外噪声盖住,看不到真正的张开度,也就没法判断采样点是否合理。

5. 拿误码率、眼图和频谱反推采样率变换对不对

5.1 频谱镜像和眼图张开度检查

验证采样率变换的第一步是看频谱。上采样后如果成型滤波器斜率正常,pwelch应该看到以Fs/2为周期、带外至少 40 dB 衰减的谱形;如果镜像凸起明显,说明滤波器抽头数或sps不匹配。下采样前则看折叠频率附近是否积累能量,有的话是抗混叠滤波没做或截止太靠后。

figure; pwelch(xUpsample, hanning(1024), 512, 1024, Fs); figure; pwelch(txSignal, hanning(1024), 512, 1024, Fs);

第一张图能看到插零后周期性的镜像频谱,第二张图是成型滤波后的结果,两张对比,镜像应当被明显压制。

5.2 用定时偏移扫描量化采样相位裕量

把整条链路收敛成一个带offset参数的函数,扫一遍偏移量看误码率变化,能直观量化系统对采样时刻偏差的容忍度——这就是数字域孔径抖动的量化评估。以tStart = 2*delay + 1 + offset为基准,offset 从-3扫到+3,记录每个偏移下的 BER,曲线呈现一条以 0 为中心的“碗形”曲线。碗底越宽,说明成型滤波器滚降越足,定时同步设计要求越低;碗底很窄则说明sps太小或rolloff太小,后续若要用 Gardner 这类定时同步算法收敛困难。用采集卡录下的实际 ADC 数据做验证时,把readmatrix读进来的样本按同样逻辑切片即可复用这套扫描流程,偏移参数直接对应硬件里可配置的采样延迟寄存器。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询