
简介这份MATLAB仿真资源围绕BPSK基带传输系统的完整链路展开面向通信工程学生、算法初学者及需要快速验证调制方案的科研人员解决从比特映射、基带成形、信道加噪到匹配滤波接收、误码率统计的建模仿真问题BPSK通过载波相位0°与180°分别表示0和1资源中重点演示了这一映射过程并支持方波与sinc两种常见基带波形方便对比不同成形函数下的频谱特性。压缩包共3个m文件包体仅1KB分别对应基带传输主程序、信噪比调整函数以及调制解调核心算法结构精简、便于逐项调用和修改已有744人学习下载广泛用于数字通信课程实验、毕业设计及MATLAB仿真入门。代码在发射端完成调制后叠加高斯白噪声接收端采用匹配滤波器其冲激响应与发送信号共轭匹配以最大化输出信噪比通过理论误码率与实际误码率的对比曲线可直观观察不同SNR条件下的系统性能变化同时帮助理解滤波器参数对检测精度的影响。整体而言这是一套能快速跑通并加深概念认知的轻量级仿真工具适合对照教材逐步研读、二次开发或用于实验报告素材。1. 在 MATLAB 里把 BPSK 基带传输、匹配滤波、传音频串成一条链路很多课程设计和入门项目的写法是先单独跑一个 BPSK 调制解调再单独仿真一个匹配滤波最后把音频文件丢进信道里听个响。分步都能跑合在一起就出错这是常态。因为单点仿真把噪声、滤波器延迟、采样时刻都假设好了一旦音频量化成比特流送进链路这些隐藏假设全部失效。这篇笔记要做的是把 BPSK 基带传输和匹配滤波接收用 MATLAB 完整串起来先跑通最小仿真脚本并画出误码率曲线再把 wav 音频量化成比特流过信道、恢复出来最后给出实际仿真里最容易翻车的几个细节和验证手段。适合通信原理课设、复试手撕以及想快速搭数字基带系统原型的从业者。2. 为什么 BPSK 基带传输要配匹配滤波从最大信噪比到采样时刻2.1 基带 BPSK不搬载波符号就是电压电平教科书里 BPSK 一般画成载波相位 0 和 π 两种状态但工程仿真里更常用的是等效基带模型。所谓基带 BPSK就是不搬载波直接把比特映射成双极性电平0 比特发 11 比特发 -1信号就是一个电压脉冲序列。这样做的好处很实在信道噪声在基带里就是简单的高斯噪声匹配滤波器的效果可以直接在波形上看出来还不用处理载波同步、相位模糊这些额外变量。整条链路的结构是比特 → 符号映射 → 上采样 → 脉冲成型 → 加噪 → 匹配滤波 → 采样判决。标题里强调“基带传输”其实就是把重点从射频搬移转到脉冲成型和最佳接收这两个核心问题上来。很多入门者误以为 BPSK 的关键在“相位”实际在基带仿真里相位信息已经变成了电平的正负真正的技术难点全在滤波和采样时刻上。2.2 匹配滤波的两层作用压噪声和定采样时刻匹配滤波器的冲激响应是发射脉冲的时间反褶在数字实现里它等价于一个相关器。白噪声条件下它在每个符号判决时刻输出的信噪比最大这就是“匹配”两个字的含义。但很多人只记住这一点忽略了它在系统里的第二个作用它和发射端的成型滤波器配合决定了采样点上有没有符号间干扰。常见做法是发射端用根升余弦滤波器做脉冲成型接收端用同样的根升余弦滤波器做匹配滤波。两个根升余弦级联等效成一个升余弦滤波器。升余弦滤波器在符号周期的整数倍处过零也就是说只要你在正确的时刻采样前面符号的拖尾不会干扰当前符号。这就是误码率曲线能够贴近理论值的根基。如果发射端用的是普通矩形脉冲匹配滤波就退化成对每个符号窗口内采样点求和平均。矩形脉冲实现简单但频带利用率差实际系统很少直接用。课程设计和仿真演示里更常见的还是 RRC 成型加 RRC 匹配这个组合也是绝大多数 MATLAB 官方例程和数据传输参考代码的标配。2.3 三个必须调好的仿真参数sps、span、beta基带 BPSK 仿真里参数不是随便填的三个参数直接决定链路的性能和仿真速度。参数含义常用范围影响sps每个符号的采样点个数8 或 16sps 太小波形像台阶匹配滤波效果变差太大仿真变慢span成型滤波器跨越的符号数6 到 10span 太小滤波器截断严重引入符号间干扰太大计算量大边缘效应更明显beta滚降系数0.2 到 0.5beta 越小频带越窄但脉冲拖尾衰减慢对定时偏差越敏感beta 越大眼图睁开越充分但占用带宽变大这三个参数不是独立的。RRC 滤波器的主瓣带宽大约是 Rsym 乘以 (1 beta)滤波器长度是 span 乘以 sps 再加 1。更关键的是滤波器有群延迟RRC 的群延迟是 span 乘以 sps 除以 2 个采样点发射一次、接收一次整条链路的总延迟就是 span 乘以 sps 个采样点。这个延迟不补偿采样点就会落在符号边界上误码率怎么调都下不来。这是后面所有踩坑现象里最隐蔽的一个。提示滤波器长度越长仿真越慢但准确率不一定越高。span 从 8 加到 32性能提升非常有限耗时却成倍增长。课程设计里 span 取 8、sps 取 8、beta 取 0.35 是一个很稳妥的起点。3. 在 MATLAB 里把最小 BPSK 基带链路跑通脚本、参数与误码率曲线3.1 最小链路代码发射成型、加噪、匹配滤波、采样判决下面这段代码可以直接复制到脚本文件里跑。它做的是生成 10000 个随机比特映射成双极性符号RRC 成型加指定信噪比的高斯白噪声再做一次 RRC 匹配滤波最后在正确的采样时刻判决。clear; clc; rng(2); Nsym 10000; % 发送符号数 sps 8; % 每符号采样点 span 8; % 滤波器跨符号数 beta 0.35; % 滚降系数 delay span * sps / 2; % RRC 滤波器群延迟单位采样点 rrc rcosdesign(beta, span, sps, sqrt); % 根升余弦成型/匹配滤波器 % 发送端随机比特 - 双极性符号 - 上采样 - 成型 bits randi([0 1], Nsym, 1); sym 1 - 2 * bits; % 0 映射 11 映射 -1 tx filter(rrc, 1, upsample(sym, sps)); tx tx / sqrt(mean(tx.^2)); % 平均功率归一到 1 % 信道按 SNR 加噪声 snr_dB 8; noise randn(size(tx)) * sqrt(10^(-snr_dB/10)); rx tx noise; % 接收端匹配滤波 mf filter(rrc, 1, rx); % 采样判决注意 2*delay1 是第一个符号的峰值位置 idx (2*delay 1) : sps : (2*delay Nsym*sps); sampled mf(idx); bits_rx double(sampled 0); ber sum(bits_rx ~ bits) / Nsym; fprintf(SNR %d dB, BER %.2e\n, snr_dB, ber);这段代码里最关键的是采样索引那一行。发射端filter引入了一个 delay接收端filter又引入了一个 delay所以第一个符号的峰值不在第 1 个采样点而在第 2*delay1 个采样点。随后每隔 sps 个点采一个值。如果忽略这个偏移直接sampled mf(1:sps:end)误码率会非常难看。rcosdesign(beta, span, sps, sqrt)里的第四个参数sqrt表示设计根升余弦滤波器。发射和接收用同一个滤波器级联后就是升余弦。如果这里不加sqrt发射端用升余弦接收端再用同一个升余弦匹配关系就错了采样点会出现明显的符号间干扰。3.2 误码率扫描把仿真曲线和理论曲线画在一起单点误码率只能证明链路能跑要验证匹配滤波器的行为是否正常必须把 SNR 从低到高扫一遍。下面这段代码在上一小节基础上循环画出 BPSK 的理论误码率曲线和仿真结果。snr_dB_list 0:8; ber_sim zeros(size(snr_dB_list)); for k 1:length(snr_dB_list) snr_dB snr_dB_list(k); noise randn(size(tx)) * sqrt(10^(-snr_dB/10)); rx tx noise; mf filter(rrc, 1, rx); idx (2*delay 1) : sps : (2*delay Nsym*sps); sampled mf(idx); bits_rx double(sampled 0); ber_sim(k) sum(bits_rx ~ bits) / Nsym; end % SNR 较高时仿真误码率可能为 0直接画对数坐标会丢点 ber_plot max(ber_sim, 1/(2*Nsym)); % 理论曲线双极性信号采样点 SNR 意义下的 BPSK 误码率 snr_lin 10.^(snr_dB_list/10); ber_theory qfunc(sqrt(snr_lin)); semilogy(snr_dB_list, ber_plot, o-); hold on; semilogy(snr_dB_list, ber_theory, -); grid on; xlabel(SNR (dB)); ylabel(BER); legend(仿真 BER, 理论 BPSK);这里有一个容易误解的地方。开头的噪声方差写的是10^(-snr_dB/10)这个 SNR 定义是接收信号平均功率和噪声平均功率之比。它和书上 Eb/N0 差一个带宽因子直接画在一个坐标轴上时曲线的横坐标数值不完全等同于 Eb/N0但斜率趋势和判决门限的行为是一致的。课程设计报告里如果非要画 Eb/N0 曲线需要额外把符号速率和带宽考虑进去平时验证链路正确性时用这个简化定义就足够。3.3 三个参数改动会带来什么变化如果把 sps 改成 4每个符号只有 4 个采样点波形看起来会粗糙一些误码率在低 SNR 段和 sps8 差别不大但眼图会明显不如 8 点采样好看。如果把 beta 从 0.35 改成 0.2发射频谱变窄脉冲尾部振铃变大在定时有偏差时误码率会上升。如果把 span 改成 4滤波器长度缩短截断效应引入额外 ISI高 SNR 段会出现误码率平台怎么加噪声功率都压不下去。所以调试时不要一次性改两个参数。固定 span8、sps8只调 beta观察误码率曲线和眼图的变化是相对不容易翻车的做法。4. 用 BPSK 基带链路传一段真实音频量化、打包、恢复4.1 音频为什么能塞进 BPSK先把声音变成比特流BPSK 信道只能传 0 和 1音频文件里存的却是 PCM 采样值所以发端必须先把音频量化成比特流。常见做法是取单声道把幅度归一化到 [-1, 1]然后 8bit 量化成 0 到 255 的无符号整数再把每个整数展开成 8 个比特。8bit 量化对语音内容足够清晰而且这个过程没有任何压缩恢复出来的音频在理想信道下和原始文件只有量化误差的差别。音频采样率一般用 8000 Hz 或者 16000 Hz。8000 Hz 采样率下每秒 8000 个采样点每个采样点 8 bit音频比特率就是 64000 bps。也就是说每传 1 秒音频BPSK 链路至少要发 64000 个符号。这个规模在 MATLAB 里跑起来很快前提是采样点数不要贪多。4.2 传音频的完整 MATLAB 脚本把下面这段代码放到和 wav 文件同一个目录下运行它会把voice.wav的前 1 秒音频量化、调制成 BPSK 信号加噪后匹配滤波、判决、恢复并把结果写成voice_rx.wav。clear; clc; rng(5); % 读音频换成立体声就手动混合成单声道 [audio, fs_audio] audioread(voice.wav); audio mean(audio, 2); audio audio(1 : 1*fs_audio); % 只取前 1 秒控制仿真量 audio audio / max(abs(audio)); % 幅度归一化 % 8bit 量化先把 [-1,1] 映射到 [1,255] audio_q round(audio * 127 128); % 每个采样点展开成 8 个比特串成比特流 bitsTx de2bi(audio_q(:), 8, left-msb); bitsTx bitsTx(:); % BPSK 调制 RRC 成型 sps 8; span 6; beta 0.5; rrc rcosdesign(beta, span, sps, sqrt); delay span * sps / 2; sym 1 - 2 * bitsTx; % 0 - 1, 1 - -1 tx filter(rrc, 1, upsample(sym, sps)); tx tx / sqrt(mean(tx.^2)); % 发端功率归一化 % 信道加噪 snr_dB 10; rx tx randn(size(tx)) * sqrt(10^(-snr_dB/10)); % 匹配滤波 采样判决 mf filter(rrc, 1, rx); idx (2*delay 1) : sps : (2*delay length(bitsTx)*sps); sampled mf(idx); bitsRx double(sampled 0); nBits length(bitsTx); errs sum(bitsRx ~ bitsTx); fprintf(音频比特数 %d误比特数 %dBER %.2e\n, nBits, errs, errs/nBits); % 恢复音频比特流按 8bit 一字节拼回 PCM 采样值 bitsOk bitsRx(1:nBits); audio_rx bi2de(reshape(bitsOk, 8, [])., left-msb); audio_rx (audio_rx - 128) / 127; audiowrite(voice_rx.wav, audio_rx, fs_audio); sound(audio_rx, fs_audio);这段脚本里需要注意de2bi和bi2de的参数left-msb。它保证高比特位在左侧量化、打包、恢复三个环节保持一致。如果这里不统一恢复出来的音频就是一片噪声。如果没有现成 wav 文件可以在脚本前面加几行生成一个测试音t (0:8000*2-1)./8000; audiowrite(voice.wav, 0.5*sin(2*pi*440*t), 8000);这个测试音是 440Hz 的标准 A 音听到的音调如果和原始一致说明链路正确。换成语音文件后SNR 低于 6 dB 时会出现明显噼啪声但内容仍能辨认SNR 放到 10 dB 以上主观听感就基本干净了。4.3 接收端必须对齐的三件事符号定时、比特长度、音频采样时钟符号定时对齐是最容易出错的一环。接收端匹配滤波后第一个符号的有效峰值在 2*delay1 处而不是第 1 个采样点。很多人在这个位置直接用1:sps:end去采样结果误码率接近 50%还以为是噪声太大。比特长度对齐是传音频特有的坑。滤波器不改变符号总数但接收端mf数组长度比有效符号长尾部是滤波器补零产生的过渡段。如果在恢复音频时不截取1:nBits而是直接拿整段bitsRx去 reshape最后会多出几个字节恢复出来的音频末尾会有一段砂纸一样的杂音。音频采样时钟对齐决定播放速度。audiowrite和sound的第二个参数必须使用原始fs_audio不能写成常数 8000。如果原文件是 44100 Hz 采样率你用 8000 播放语速会变成接近 5 倍听起来像磁带快进。提示音频仿真最怕把整个 wav 文件一次性送进链路。一首歌至少几十万符号加上 sps8 的过采样MATLAB 跑起来非常慢。调试阶段先截 0.5 到 1 秒链路确认没问题再放宽。5. 避坑匹配滤波仿真里最容易翻车的 5 个细节5.1 群延迟没补偿误码率永远在 0.5 附近现象SNR 加到 20 dB误码率还是在 0.4 到 0.6 之间波动完全没有下降趋势。原因MATLAB 的filter是因果滤波器输出比输入滞后。RRC 滤波器群延迟是 span 乘以 sps 除以 2 个采样点发射端一次、接收端一次总共偏移 span 乘以 sps 个采样点。没补偿这个偏移采样时刻正好落在符号跳变边界上判决结果接近随机。解决采样索引写成(2*delay 1) : sps : (2*delay Nsym*sps)或者等价的idx delay_total 1 : sps : delay_total Nsym*sps其中delay_total span*sps。如果用的是upfirdn而不是filter也要先确认参考代码里有没有默认处理延迟不要盲目套用。5.2 拿低通滤波器当匹配滤波SNR 越高越难受现象把接收滤波器换成designfilt(lowpassfir, ...)之后低 SNR 时看着还行SNR 一高误码率就下不去了。原因低通滤波器只能抑制带外噪声不保证输出采样点信噪比最大也不保证符号间无干扰。匹配滤波器的冲激响应必须和发射脉冲匹配RRC 发射端的匹配接收端必须也是 RRC而不是随便一个通带够宽的低通。解决发射成型用rcosdesign接收匹配就用同一个rrc系数再做一次filter(rrc, 1, rx)。如果发射端刻意用矩形脉冲接收端的匹配滤波器长度应当等于 sps、系数全为 1 的方窗即h ones(sps,1)/sps。不要把这两个概念混在一起。5.3 噪声方差写死成 0.1误码率曲线变成一条假直线现象扫 SNR 时曲线几乎不变或者趋势和理论完全不同低 SNR 段误码率反而不高。原因噪声没有跟着 SNR 变。写死噪声方差后信道质量不随横坐标变化扫出一个水平线等于测了同一个信噪比十遍。解决噪声标准差必须是sqrt(10^(-snr_dB/10))而且要放在 SNR 循环内部重新生成。发射信号在噪声注入前先做平均功率归一化也就是tx tx / sqrt(mean(tx.^2))这样不同滤波器长度、不同 sps 下信噪比定义是同一把尺子。5.4 恢复音频时比特长度没对齐结尾多出一段杂音现象音频主体内容听得出但每段末尾固定有一小段像摩擦声的杂音时长约几十到几百毫秒。原因接收端采样得到的比特流比发端多出一小段。滤波器补零段被当成有效比特多出来的数据 reshape 成字节后有随机数值恢复的 PCM 尾部就是随机幅度噪声。解决恢复前先截bitsRx(1:nBits)其中 nBits 是发端比特总数。更稳妥的做法是nBytes floor(nBits/8)然后bitsOk bitsRx(1:8*nBytes)确保字节数完整。5.5 RRC 截断太短高 SNR 段出现误码率平台现象低 SNR 时仿真曲线和理论贴合SNR 超过 12 dB 后误码率停在 1e-3 左右上不去。原因RRC 滤波器是对无限长冲激响应的截断。span 太小截断引入的符号间干扰超过了噪声主导区间形成误码率地板。这个地板和信道噪声无关加大 SNR 也压不下去。解决把 span 从 4 提到 8 或 10误码率平台会明显下移。如果对带外抑制要求更高beta 取小值的同时必须适当加大 span否则截断效应反而更严重。这个取舍在实际系统里叫成型滤波器设计不是随便填一个数就完事。6. 用眼图、误码结果和一段语音确认整条链路没白做6.1 一眼看出采样点在哪eyediagram 的使用匹配滤波链路调通之后最直观的验证工具是眼图。接第 3 节的变量直接对匹配滤波输出画眼图% 去掉前面的瞬态段避免过渡态干扰眼图 eyediagram(mf(2*delay1:end), sps);眼图横坐标是一个符号周期纵轴是幅度。理想情况下能看到一条在 1 和 -1 之间清晰张开的“眼睛”眼睛中央最宽处就是最佳采样时刻。如果你的采样索引落在眼睛最张开的位置说明 2*delay1 这个补偿算对了。如果眼睛中央发糊、边缘模糊先查群延迟再查 span 和 beta 的配合。眼图的判断比看误码率直接得多。误码率是一个统计量两个参数配错偶尔也能得到相近的数值眼图是波形形态的直接呈现参数错没错一眼就能看出来。6.2 三重验证仿真 BER、理论曲线、耳朵我的固定习惯是分成三步验证。第一步跑 0 到 8 dB 的误码率扫描确认仿真曲线贴着理论曲线走这一步证明调制解调和匹配滤波在统计意义上是正确的。第二步换传音频SNR 放到 10 dB 以上对比voice.wav和voice_rx.wav的听感这一步证明整条链路能处理真实信源。第三步画发射信号频谱确认主瓣宽度接近 Rsym 乘以 (1 beta)这一步证明成型滤波器的频带参数没有设错。这三步里最容易跳过的是一和三。只靠耳朵听SNR 高的时候很多误码听不出来只靠误码率曲线又发现不了采样时刻偏移带来的隐患。三者互为补充是课程设计和快速验证里性价比最高的组合。提示如果眼图中央张得够开但采样点总是落在眼睛边缘可以检查索引表达式里的2*delay1是不是写成了delay1。这个符号差别导致半个符号周期的时间偏移眼图上立刻露馅。我在做这个链路时踩得最深的坑是认为匹配滤波器越长越好把 span 调成 32 后仿真慢了一倍误码率却几乎没有变化。后来才明白span 决定的是截断精度sps 决定的是波形离散精度beta 决定的是带宽和定时余量的权衡三个参数要一起看。入门阶段按 span8、sps8、beta0.35 起步之后每次只改一个参数观察变化是最省时间的方式。希望这条 BPSK 基带传输加匹配滤波接收的链路和这些参数经验能帮你在自己的仿真里少走两步弯路。本文还有配套的精品资源点击获取