☰
OOK调制误码率仿真解析:从原理到MATLAB实现
2026/10/11 16:33:21 网站建设 项目流程

简介:本资源是一份面向通信工程专业本科生及无线通信初学者的OOK调制与误码特性MATLAB仿真实践包,聚焦数字通信基础原理验证与性能分析。资源共4个文件,含2个核心MATLAB脚本(.m)实现OOK调制与非相干解调,以及2个同名ASV备份文件(MATLAB自动保存格式),总大小仅2KB,轻量易读,便于理解调制生成、加噪信道建模、阈值判决解调及BER统计全流程。已有786人学习下载,适合课程实验、课程设计或自学巩固。读者可直接运行代码复现OOK信号波形、观察不同SNR下的误码率变化趋势,深入掌握包络检测原理、门限设置对BER的影响机制,并获得完整可调试的仿真实验框架,为后续ASK、BPSK等调制方式对比研究奠定基础。 做通信系统仿真的人,大部分绕不开 OOK 调制误码率分析。大学通信原理课上,老师会告诉你 OOK 是最基础的二进制振幅调制方式,而到了实际项目和课设里,你会发现这个“基础”并不等于“简单”——同样一条 OOK 链路,参数没设对、采样率没想清楚、判决门限选偏了,出来的误码率曲线就能和理论值差好几个数量级。今天要拆的这个“ook调制仿真.zip”工程包,正好围绕 OOK 信号调制与误码率仿真,把发送端调制、信道加噪、接收端解调和误码统计整条链路都完整跑了一遍。不管你是正在做通信原理课设,还是刚接手 RFID、遥控开关这类低速无线项目,这篇拆解都能帮你快速搞懂 OOK 调制的完整仿真套路,也能在遇到“误码率曲线对不上理论值”这类常见坑的时候少走弯路。

1. 项目背景与整体设计思路

1.1 OOK 调制是什么,为什么值得单独做一个仿真工程

OOK 全称 On-Off Keying,中文叫通断键控,本质上就是 2ASK(二进制振幅键控)的一种最简实现:码元为“1”时发送一个固定频率的载波,码元为“0”时发送端完全不输出功率,相当于把载波“关掉”。用数学表达式写就是:

s(t) = A·cos(2πfct) ,对应比特 1;s(t) = 0,对应比特 0。

看起来简单,但实际用途一点都不小。RFID 无源标签的反向散射通信、红外遥控、光纤通信里的强度调制、部分低速无线传感器网络,用的都是 OOK 或者它的变体。为什么这种“古老”的调制方式现在还活着?因为实现成本低。非相干解调不需要载波同步,一个检波二极管加个低通滤波器就能把数据恢复出来,这在标签芯片、遥控接收端这类对功耗和成本极其敏感的场景里,是 QPSK、16QAM 这些高阶调制比不了的。

从频谱上看,OOK 相当于把二进制基带信号线性搬移到载波频率上。这里有个很有意思的点:OOK 的频谱里除了以载波为中心的两个双边带分量外,还会在载波频率 fc 处残留一条离散谱线。这条谱线在“AM 调制 双边带”的分析里也经常出现——因为它本质上就是 100% 调幅的一种数字特例。这个离散载波分量会白白消耗一部分发射功率,所以从功率效率角度看 OOK 并不优秀,但反过来看,接收端可以利用这条谱线做非相干检测,这也算是一种折中。

1.2 仿真链路总体设计:从发端到收端不跳步

这个仿真工程的核心不是只算一个理论公式,而是要把物理层的完整链路搭出来。整条链路分五个模块:随机比特生成、码元波形映射、载波调制、AWGN 信道加噪、接收端解调解判。每个模块都是独立可替换的,这也是我拿到类似工程后第一件要做的事——先看链路通不通,再去看误码率对不对。

随机比特生成用 MATLAB 的 randi,保证 0/1 等概率。码元波形映射就是把每个比特扩展成 sps 个采样点,这样数字信号才能映射到连续时间域。载波调制是让每个“1”码元乘上一段余弦波,让“0”码元保持为零。AWGN 信道则是往信号里叠加高斯白噪声,模拟真实信道中的热噪声。接收端我做了两套方案:相干解调和包络检波的非相干解调,方便对比它们之间的性能差距。

为什么选择 AWGN 信道而不是瑞利衰落或者多径信道?因为 AWGN 是最基本的信道模型,也是理论误码率公式成立的前提。如果一开始就在衰落信道上调仿真,噪声、相位、幅度都在变化,误码率曲线根本没法判断是链路写错了还是信道本身的特性。先把 AWGN 下的误码率曲线调到和理论公式重合,再往里面加衰落、同步误差、滤波失真这些复杂因素,才是工程上正确的推进方式。

1.3 为什么用 MATLAB 脚本而不是 Simulink

很多人喜欢用 Simulink 搭通信系统,觉得拖拽模块更直观。但这类“误码率特性研究”的仿真,我的习惯是优先用脚本实现。Simulink 的优点是系统结构清晰、信号流明显,适合做演示和验证单个模块行为;缺点是要跑蒙特卡洛仿真时非常难受——每个信噪比点都要配置一遍模型参数、托人检查模块是否收敛、收集波形数据还得自己写回调,批量改参数更麻烦。

脚本的方式就简单直接得多。所有信噪比点用一个 for 循环跑完,每次循环里只改 awgn 的 SNR 参数,2000 万个采样点也只是一个向量而已,内存和速度都完全可控。而且脚本里每一步都能用变量存下来,哪一步出现异常可以直接 plot 出来看,排查问题的效率比 Simulink 高不少。所以我建议所有做“XX 调制误码率仿真”这类课题的朋友,先用脚本把链路跑通,再决定要不要包装成 Simulink 模型交差。

2. 调制解调核心原理与关键参数设计

2.1 调制参数的选择,每一步都要算明白

仿真参数设置是整个工程里最容易被忽略但又最致命的部分。我在这套工程里选用的参数是:码元速率 Rb=1kbps,载波频率 fc=10kHz,采样率 fs=100kHz。这套参数看起来随意,但背后有三个原则。

第一个原则:采样率必须满足奈奎斯特条件。载波频率是 10kHz,采样率至少要到 20kHz 以上才能无混叠地表示这个余弦波。这里取 100kHz,是载波频率的 10 倍,每个载波周期内能采到 10 个点,plot 出来的波形足够平滑,不会出现“三角波”式的失真。

第二个原则:每个码元内必须包含整数个载波周期。这里 fc/Rb = 10kHz/1kbps = 10,一个码元里正好塞了 10 个完整载波周期。这个整数倍数关系非常关键。后面做相干解调时,接收信号乘本地载波会产生一个 20kHz 的二倍频分量和一个直流分量,移动平均滤波器在一个码元长度内刚好覆盖整数个二倍频周期,二倍频分量会被完美滤除,滤波输出稳定在一个固定直流值上,判决才好做。

第三个原则:每个码元内的采样点数是整数且不宜太少。sps = fs/Rb = 100,也就是一个码元持续 0.001 秒里采了 100 个点。这个 100 不仅是采样率与码速率之比,也直接决定了后面的“匹配滤波”效果——移动平均窗口正好等于一个码元长度,等效于对矩形脉冲做匹配滤波。

这里我特别提醒一句:载波频率不要取得太低。我见过有人偷懒把 fc 设成 100Hz、Rb 也设 100,虽然也能跑出波形,但频谱上上下边带会严重重叠,滤波器稍微不完美就会引入符号间干扰,误码率曲线怎么调都压不下去。取 10kHz 这个量级,离频谱边缘有足够余量,仿真结果才稳定。

2.2 相干解调和非相干解调,两套方案怎么选

接收端解调是这套仿真里最值得讲的部分。相干解调的结构是:接收信号先乘以本地恢复出来的同频同相载波,然后通过低通滤波器,在码元末尾采样,最后和判决门限比较。乘以载波这一步会把信号频谱搬回基带,同时产生一个二倍频分量,低通滤波器滤掉二倍频分量后,就得到了基带信号。

非相干解调最常见的实现是包络检波——对接收信号取绝对值或者平方,再低通滤波,提取出载波包络。它不需要恢复载波的相位信息,电路实现简单,因此在实际系统中广泛使用。不过它也有代价:由于省掉了相干解调中的“同相分量投影”,噪声的非线性变换会让判决统计量不再服从高斯分布,误码性能会比相干解调差。

从我实测的仿真结果看,在误码率 1e-3 附近,非相干解调比相干解调大约差 1dB 左右。这个 1dB 结论在工程上很常用——设计链路预算时,如果选用非相干接收,记得在灵敏度指标上多留出 1dB 余量。下面这个表总结了两种方案在仿真工程中的取舍:

对比维度相干解调非相干解调(包络检波)
是否需要载波同步需要不需要
实现复杂度高,需要锁相环或导频辅助低,检波+滤波即可
理论误码率公式0.5·erfc(0.5·√r)0.5·e^(-0.5r)
相同误码率下所需 Eb/N0低(性能更好)略高约 1dB
典型应用场景高速数字接收机、相干光通信RFID、红外遥控、低功耗无线

在这个工程包里,我建议主跑相干解调,因为误码率曲线和理论公式拟合得比较完美,适合验证链路正确性;非相干解调作为对照实验,用来理解“为什么工程上愿意用性能换复杂度”。

2.3 理论误码率公式,从哪来、怎么对上

理论误码率是这个仿真的“裁判”。只有仿真点贴着理论曲线走,才能证明链路搭对了。两个公式都要记住:

相干 OOK 的理论误比特率: Pe = Q(√(r/2)) = 0.5·erfc(0.5·√r)

非相干 OOK 的理论误比特率: Pe = 0.5·e^(-0.5r)

其中 r = Eb/N0,是每比特能量与噪声功率谱密度之比,单位通常转成 dB 来画横轴。

推导思路其实不复杂。相干解调在抽样判决点上的统计量近似是一个高斯随机变量,发送“1”时均值是 A/2(匹配滤波输出),发送“0”时均值是 0,噪声方差由信道噪声功率谱密度决定。两个均值为 0 和 A/2 的高斯分布,最优判决门限取在中间位置 A/4,于是误码率就是其中一个分布超过门限的概率,最终整理成 Q 函数或者互补误差函数的形式。非相干解调因为是包络检波,包络在有信号时服从莱斯分布、无信号时服从瑞利分布,误码率会变成一个指数表达式。

我在代码里直接调用 MATLAB 的 erfc 函数来画理论曲线,省去自己实现 Q 函数或者查表的麻烦。要特别注意:MATLAB 的 erfc 里,自变量和教科书上的 Q 函数有一个 √2 的换算关系,不要直接套错。

3. 仿真实现详解:核心代码与执行细节

3.1 相干解调误码率仿真完整代码

下面是这个工程里最能打的相干解调完整代码。每一段都有注释,建议直接复制运行,然后对照后面的参数分析看。

% OOK调制解调与误码率仿真(相干解调) clear; clc; close all; % ---------- 参数设置 ---------- Rb = 1000; % 码元速率:1 kbps fc = 10000; % 载波频率:10 kHz fs = 100000; % 采样率:100 kHz sps = fs / Rb; % 每个码元采样点数:100 numBits = 200000; % 仿真比特数 EbN0_dB = 0:2:14; % Eb/N0 范围(dB) % ---------- 发送端 ---------- rng(42); % 固定随机种子,保证结果可复现 bits = randi([0 1], 1, numBits); % 生成等概率随机比特 bitStream = repelem(bits, sps); % 每个比特扩展成 sps 个采样点 t = (0:length(bitStream)-1) / fs; carrier = cos(2*pi*fc*t); % 载波:幅度为 1 tx_signal = bitStream .* carrier; % OOK 调制:1发载波,0发0 % ---------- AWGN信道 + 相干解调 ---------- for k = 1:length(EbN0_dB) % 关键换算:把 Eb/N0(dB) 转成 awgn 函数的 SNR(dB) SNR_dB = EbN0_dB(k) - 10*log10(sps/2); rx_signal = awgn(tx_signal, SNR_dB, 'measured'); % 相干解调:乘以本地载波 demod = rx_signal .* carrier; % 低通滤波:移动平均,窗口长度 = sps h = ones(1, sps) / sps; filtered = filter(h, 1, demod); % 抽样:取每个码元最后一个采样点 sampleIdx = sps : sps : length(filtered); sampleVal = filtered(sampleIdx); % 判决门限:0.25(“1”码滤波输出约0.5,“0”码约0) rxBits = sampleVal > 0.25; % 误码率统计 err(k) = sum(rxBits ~= bits) / numBits; end % ---------- 理论误码率 ---------- EbN0_lin = 10.^(EbN0_dB/10); theory = 0.5 * erfc(0.5 * sqrt(EbN0_lin)); % ---------- 绘图 ---------- figure; semilogy(EbN0_dB, err, 'o-', 'LineWidth', 1.5); hold on; semilogy(EbN0_dB, theory, 'r-', 'LineWidth', 1.5); grid on; xlabel('Eb/N0 (dB)'); ylabel('误码率'); legend('OOK仿真误码率(相干)', 'OOK理论误码率(相干)'); title('OOK相干解调误码率仿真曲线');

这段代码运行起来非常快,2e5 比特、8 个信噪比点,普通笔记本十秒内就能跑完。跑出来的曲线在 0~14dB 范围内,仿真点和理论曲线基本重合,只有个别点在低误码率区域有点抖动。

3.2 最容易踩坑的环节:SNR 与 Eb/N0 的换算

如果只看了上面代码,没搞懂 SNR_dB 那一行为什么要减掉 10*log10(sps/2),那你只算会用代码,不算懂仿真。我在这里详细说清楚,这也是整个工程里初学者翻车最多的地方。

awgn 函数里填的 SNR 是“信号平均功率/噪声平均功率”,单位 dB。而误码率曲线的横轴是 Eb/N0,单位也是 dB,但两者完全是两码事。关键在于 OOK 信号的平均功率不等于“1”码的瞬时功率。OOK 平均功率 Pav = Eb·Rb,因为 0 码不发送功率,“1”码的功率是 Eb·Rb 的两倍。噪声部分呢,awgn 在采样率 fs 下产生的总噪声功率是 N0·fs/2,因为高斯白噪声的单边功率谱密度是 N0,经过采样带宽 fs/2 后,总功率就是这个值。

把两边一比:

SNR_linear = (Eb·Rb) / (N0·fs/2) = (2·Rb/fs) · (Eb/N0) = (2/sps) · r

用 dB 表示就是:

SNR_dB = EbN0_dB + 10·log10(2/sps) = EbN0_dB - 10·log10(sps/2)

所以当 sps=100 时,要减去 10·log10(50) ≈ 16.99dB。也就是说,为了让 Eb/N0=10dB,awgn 函数里要填的 SNR 大约是 -7dB。

看到 -7dB 不要慌,这并不代表信道烂得没法用。因为接收端那个移动平均滤波器相当于一个匹配滤波,会把带外噪声滤掉很大一部分,滤波后的等效信噪比就恢复到了理论值。如果你不换算,直接把 Eb/N0 dB 填进 awgn,仿真误码率会比理论值低十几个数量级,甚至低到 0,这种结果一看就是错的。

3.3 抽样时刻和判决门限,细节里藏着魔鬼

移动平均滤波器本身是有延迟的。很多初学者在仿真里相乘、滤波之后,习惯在码元正中间抽样,结果发现误码率偏高,怎么调都调不回理论曲线。原因很简单——没有考虑滤波器的群延迟,抽样的时刻根本不是码元的有效判决点。

这里我用了一个小技巧:在码元末尾抽样,也就是 sampleIdx = sps : sps : length(filtered)。移动平均滤波器的长度正好等于 sps,所以当输出索引是 k·sps 时,滤波器窗口恰好完整覆盖了第 k 个码元的全部采样点,不会混入相邻码元的信息。这种抽样方式等效于“积分清除”接收机,也就是矩形脉冲信号在 AWGN 下的匹配滤波,理论上能达到最优误码性能。

判决门限取 0.25 也有一番讲究。“1”码经载波相乘再移动平均后,cos²(2πfct) 在一个完整码元内的平均值是 0.5;“0”码的输出是 0。两个判决值的算术中点是 0.25,这在高斯等方差噪声下就是最小错误概率门限。门限不能随便拍脑袋取 0.5,那会把一半“1”码误判成“0”,误码率会飙到 30% 以上。

我在实际调试中经常看到有人把门限写成 0.1 或者 0.3,然后纠结“为什么和理论值差一点”。其实只要滤波链路正确,最佳门限推导出来就是 0.25,不需要靠试错猜。

3.4 非相干解调的补充实验代码

相干解调跑通之后,我建议把非相干解调也补上,两个曲线放在一张图里对比,信息量一下子就有了。非相干这里我用的是平方率检波,实现上最稳定,和理论的贴合度也最好。

% OOK非相干解调(平方率包络检波)误码率仿真 % 复用上一个代码的 tx_signal、bits、sps、carrier 等变量 for k = 1:length(EbN0_dB) SNR_dB = EbN0_dB(k) - 10*log10(sps/2); rx_signal = awgn(tx_signal, SNR_dB, 'measured'); % 平方率检波:对接收信号取平方,提取包络能量 squared = rx_signal .^ 2; % 移动平均,窗口长度 = sps filtered = filter(ones(1, sps)/sps, 1, squared); % 码元末尾抽样 sampleIdx = sps : sps : length(filtered); envSample = filtered(sampleIdx); % 判决门限同样是0.25(平方检波后“1”码平均输出0.5) rxBits = envSample > 0.25; errNoncoh(k) = sum(rxBits ~= bits) / numBits; end theoryNoncoh = 0.5 * exp(-0.5 * EbN0_lin); figure; semilogy(EbN0_dB, err, 'o-', 'LineWidth', 1.5); hold on; semilogy(EbN0_dB, errNoncoh, 's-', 'LineWidth', 1.5); semilogy(EbN0_dB, theory, 'r-', 'LineWidth', 1.5); semilogy(EbN0_dB, theoryNoncoh, 'm--', 'LineWidth', 1.5); grid on; xlabel('Eb/N0 (dB)'); ylabel('误码率'); legend('相干仿真', '非相干仿真', '相干理论', '非相干理论'); title('OOK相干与不相干解调误码率对比');

跑完这条曲线你会发现,在低信噪比区域(0~6dB),两条曲线几乎贴在一起;信噪比越高,差距越明显。到 14dB 时两者大约差了 1.2 个 dB 左右。这正好和教材里“非相干相比相干损失约 1dB”的结论对上了。

4. 误码率特性分析与扩展应用

4.1 仿真结果怎么看:数据不是画完图就结束了

跑完仿真,不能只看“曲线重合了”就完事,还要做几个数据质量检查。第一个检查是每个信噪比点统计到的错误比特数。蒙特卡洛仿真有个简单经验:如果期望误码率是 Pe,那么至少需要统计到 10/Pe 个错误比特,结果才有统计意义。比如在 14dB 时理论误码率大约在 1e-3 量级,2e5 比特能统计到 200 个左右的错误,这个结果是可信的。但如果想仿真到 1e-6 的误码率,2e5 比特就远远不够了,那时需要 1e7 到 1e8 个比特,仿真时间会显著拉长。这也是为什么通信仿真在低误码率区间经常直接转向理论计算或者用 Importance Sampling 等高级技巧。

第二个检查是看误码率曲线的“斜率”。在 AWGN 信道下,OOK 误码率曲线在高信噪比区域应该接近一条指数下降的直线,也就是在 semilogy 坐标下是一条向下的斜线。如果曲线在某个点之后突然“躺平”或者出现平台,大概率不是信道的问题,而是仿真本身引入了地板噪声——比如量化误差、载波同步偏差、滤波器泄漏等。这时候优先检查接收链路,而不是一味增加发射功率。

第三个检查是回归测试。我把门限临时改成 0.25±0.05 看误码率是否恶化;把 sps 改到 50 或 200 看误码率是否基本不变。如果 sps 一变,误码率曲线就换了条线,说明抽样或滤波环节有符号间干扰,需要回头查采样点对齐。

4.2 载波、采样率等参数变化对误码率的影响

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

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

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

立即咨询