MATLAB通信仿真实战:双极性、正交与PAM信号全解析
发布时间:2026/9/15 6:11:41来源:尧图网络
简介面向通信与信号处理学习者的MATLAB仿真资源包聚焦双极性信号、正交信号与PAM信号三类调制技术的建模与仿真适用于课程设计、期末复习及通信系统入门实践。压缩包共12个文件包括8个m脚本、3个Simulink模型及1份详细建模说明文档大小仅165KB。脚本覆盖信号生成、调制、加噪与解调等核心环节Simulink模型便于可视化验证说明文档则梳理运行方法与结果分析。已有369人学习下载。资源以循序渐进的方式展开典型实验从双极性波形产生、正交多载波调制到多进制PAM解调各m文件可独立运行也可组合成完整仿真链路模型文件帮助直接观察频谱与波形变化配合文档可快速修改参数并扩展到其他调制技术整体是理论联系实践的高性价比工具。1. 从“三个电平”开始的MATLAB通信仿真很多人第一次接触双极性信号、正交信号和PAM信号时会把它们当成三个无关的调制知识点一个用来画波形一个用在OFDM里一个拿pammod一行命令就能带过。但在一个完整的MATLAB通信系统仿真包里三者其实是同一条基带链路的三个环节双极性信号决定码元如何映射为电平正交信号决定载波如何承载信息PAM则把整个过程的幅度调制部分统一起来。这个压缩包里的exe1.m到exe8.m、exe4.mdl、exe5.mdl和exe7.mdl以及那份“建模及仿真说明.doc”恰好覆盖了从波形生成、噪声信道到Simulink模型联调的完整路径。适合正在做通信课程设计、需要交付误码率曲线的学生也适合想快速回顾基带仿真细节的工程师。下面直接按信号类型拆开讲。2. 双极性信号建模NRZ波形与抗噪能力分析双极性信号是整个仿真的第一块基石。它把二进制数据映射成正负两个电平典型实现是双极性不归零码。相比单极性信号只在“0”和“1”之间切换双极性信号没有直流分量因此在通过变压器耦合的基带系统中更友好也能够以电平极性直接参与后续的匹配滤波和判决。2.1 双极性信号的数学定义与带宽效率双极性信号可以写为s(t) ∑ a_k g(t − kT_b), a_k ∈ {−A, A}其中T_b是码元周期g(t)是成形脉冲通常取矩形脉冲。这里最关键的参数是A的取值和T_b的确定。MATLAB里仿真时一般先把数据序列变成−1和1再用repelem或upsample把每个码元展开成多个采样点形成连续波形。从频域看双极性NRZ信号的功率谱主瓣宽度约为码元速率R_b。相比单极性NRZ双极性信号没有直流分量功率谱在零频处不会出现离散谱线这对后续加入载波调制非常有利。在MATLAB里可以用periodogram或pwelch直接观察这两者差异。若你看到exe1.m的绘图部分有fft和abs多半就是在做这件事。带宽效率的差异不在码元速率上而在低频成分上这也是双极性信号在基带传输中更常见的原因。2.2 用MATLAB生成双极性NRZ序列下面这段代码是一个可靠起点我一般把每个码元展开成sps个采样点方便后面加任意信噪比的噪声。% bipolar_nrz_demo.m numBits 2000; % 测试比特数 sps 64; % 每个码元采样的点数 data randi([0 1], numBits, 1); bipolar 2*data - 1; % 0 - -1, 1 - 1 waveform repelem(bipolar, sps); % 每个码元重复sps次 fs 64000; % 采样率Hz Tb sps / fs; % 码元周期即每个码元的时长 % 查看前8个码元 stem(bipolar(1:8), filled); xlabel(码元序号); ylabel(电平); title(前8个双极性码元);代码里randi([0 1], numBits, 1)生成0/1随机序列2*data - 1完成电平映射。repelem是按码元重复比upsample更直观因为upsample会在采样点之间插入零必须再做低通或保持而repelem直接生成零阶保持波形。sps64是为了让波形在时域显示时足够平滑同时做FFT时频率分辨率也够。实际中sps取8到128都可以太小时波形包络像阶梯太大会增加仿真内存但不会改变误码率结论。2.3 双极性信号在噪声信道中的判决双极性信号在AWGN信道里最优判决方式就是看采样点的符号。关键操作是要在码元中心采样而不是随便抽一个点。仿真的代码结构通常是% bipolar_awgn_demo.m EbN0dB 8; EbN0 10^(EbN0dB/10); sigma sqrt(1 / (2*EbN0)); % 双极性信号单位能量时的噪声标准差 rx waveform sigma * randn(size(waveform)); rx_sampled rx(1 : sps : end); % 每个码元取第一个采样点作为判决值 if 1 % 使用码元中点采样更贴近实际采样时钟 rx_mid reshape(rx, sps, numBits); rx_sampled rx_mid(end/2, :); end decision sign(rx_sampled); % 0判为10判为-1 err sum(decision ~ bipolar); ser err / numBits; fprintf(Eb/N0 %.1f dB, SER %.4f\n, EbN0dB, ser);sigma sqrt(1/(2*EbN0))的推导前提是双极性信号每个比特能量Eb1所以噪声方差按N0/2折算。如果直接用randn(size(waveform))生成的噪声功率是1要乘sigma才能得到目标信噪比。rx_sampled的核心是确定采样相位使用码元中点还是起点取决于仿真里是否有发送滤波和接收滤波器。矩形脉冲波形时码元中点离码元边界最远抗噪声最好所以reshape后取end/2比取第一个点更合理。sign把接收值硬判决到±1不做软信息。对双极性信号在AWGN下的理论误码率通常用PeQ(√(2Eb/N0))。如果仿真结果与理论曲线差异大于0.5dB往往就是采样相位不对或者噪声功率公式里忘了除以sps。下表给出了常见参数和含义。参数推荐范围说明numBits1e31e6比特数越多误码率统计越稳但仿真时间长sps8128每个码元采样点数决定时域分辨率和内存EbN0dB015双极性信号通常在这个区间从10^-2降到10^-6sigma按EbN0计算不要手动指定固定噪声幅度项目里exe2.m、exe3.m基本就是这类流程的变体exe2.m生成双极性波形exe3.m做噪声叠加和误码率统计。如果你拿到的exe1.m是主程序它多半在循环里调用这两个脚本并把EbN0从0扫到10dB最后画出一张SER曲线图。这里要提醒的是循环里每次都要重新生成随机数否则多次调用的噪声序列完全一样得出的误码率会沿一条固定曲线跳动而不是在理论值附近波动。3. 正交信号的构造从正交性判据到I/Q调制仿真正交信号在通信系统里扮演的角色和双极性信号完全不同。双极性信号解决的是“符号怎么映射”正交信号解决的是“多路信号怎么同时传输而不互相干扰”。在MATLAB仿真中最常见做法是先验证两路信号的内积为零然后把零中频的I/Q两路信号送到Simulink载波上。3.1 正交与正交频分复用的联系两个信号正交数学定义是它们在某个区间上的内积为零也就是∫s1(t)·s2(t)dt0。对频域而言这意味着两路信号的频谱没有重叠的非零成分。OFDM之所以能利用子载波间的正交性正是因为在码元周期内各子载波频率间隔为1/T时不同子载波的乘积积分恰好为零。但在一个数字仿真的基带系统里做正交调制未必需要真的搭OFDM只需要构造一对正弦和余弦载波分别乘以I路和Q路数据再把两路相加。正交信号的好处是频谱利用率翻倍。同样的带宽内IQ两路可以各传各的数据接收端用本地载波做相干解调就能分开。这就是为什么大多数现代调制系统QAM、PSK在仿真时都要先生成双极性或PAM基带波形再搬到正交载波上。3.2 用fft/ifft构造正交载波并验证正交性MATLAB里构造正交信号最直接的方式是生成一个exp(j*2*pi*f*t)复指数因为它的实部和虚部天然正交。但如果你要做的是实信号正交验证下面的代码更直观% orthog_check.m fs 10000; t (0:999) / fs; f1 100; f2 150; x1 cos(2*pi*f1*t); x2 sin(2*pi*f1*t); % 与x1相差90度 corr12 dot(x1, x2); % 数字内积 corr11 dot(x1, x1); % 参考自相关值 % 用FFT观察两根谱线是否分离 X1 fft(x1); X2 fft(x2); f (0:999) * fs / 1000 - fs/2; stem(f, fftshift(abs(X1) .* abs(X2)), filled); xlabel(频率 (Hz)); ylabel(|X1(k)|*|X2(k)|); title(两个正交载波的谱乘积);dot(x1,x2)在整周期采样时接近0非整周期时会有泄漏所以验证正交性时最好让采样点数对应整数个载波周期。上面的fs10000t0:999f1100Hz正好10个周期内积结果在浮点误差范围内。谱乘积的stem图在所有频率点上都接近0就代表谱域正交。实际OFDM仿真里ifft的作用是把频域符号映射到时域而fft则用于接收端解调。不要混淆“用fft看频谱”和“用ifft生成时域OFDM符号”前者是分析工具后者是把子载波叠加成正交信号的生成方式。如果要生成一个带I/Q的正交调制信号常见做法是% iq_modulator.m fcarrier 1000; Ts 1 / fsamp; t 0 : Ts : 100*Tb - Ts; % 100个码元时长 I cos(2*pi*fcarrier*t); Q sin(2*pi*fcarrier*t); s data_I .* I data_Q .* Q;这里data_I和data_Q是已经展开成波形的基带信号。如果省略载波而直接用复数基带信号表示则为s_complex data_I 1j*data_Q这是Simulink中AWGN信道模块和星座图仪最常用的输入格式。3.3 Simulink中实现正交调制exe4.mdl的结构猜测与参数压缩包里的exe4.mdl、exe5.mdl、exe7.mdl都是Simulink模型。虽然只有.mdl文件看不到内部截图但从命名看exe4.mdl大概率是正交调制加噪声信道exe5.mdl可能是PAM或基带成型滤波exe7.mdl可能是完整解调链路。打开.mdl文件的方法是直接在MATLAB命令窗口输入open_system(exe4.mdl)。若提示模块库版本过低在模型窗口按CtrlD更新诊断即可。Simulink里搭正交调制器时最常用的模块包括Sine Wave设置Sample time和Bias实现正弦/余弦、Product、Add、AWGN Channel。AWGN Channel的SNR参数有两种设定模式Symbol period和Signal to noise ratio。如果设成Symbol period需要把符号周期填成Tb否则噪声功率会按每个采样点计算最终误码率偏大。另一处容易错的是载波频率的选择Simulink是离散时间系统载波频率必须满足采样定理同时要避免载波频率与采样率的比值接近0.5否则会出现频谱混叠。我一般把载波设在采样率的1/20到1/4之间。正交性的验证在Simulink里同样能做。在接收端用Product和Integrator或Discrete Time Integrator计算I路与本地正弦载波的乘积积分再与Q路乘积积分对比。若I路对Q路本地载波的积分远小于对I路本地载波的积分说明两条支路分离成功。下面是一个常见的参数配置表。参数项建议值说明Carrier frequency (fc)fsamp/10太接近fsamp/2会混叠接收滤波阶数32~64成形滤波器和匹配滤波器各一AWGN Channel的SNR modeSymbol period按码元速率计算噪声功率Solver typeFixed-step离散模型避免变步长带来的采样点抖动Stop time10/Tb或更长至少包含10个以上码元便于观察眼图这个模型的输出通常是解调后的基带数据流需要经过判决和误码统计。如果直接用Scope看波形看起来像一团正弦波可以用Reshape和Selector把每个码元末端的采样点取出来再与发射端的码元对比。4. PAM通信系统仿真从pammod到误码率曲线PAM信号经常被误写成PWM信号其实两者本质不同PAM是脉冲的幅度携带信息PWM是脉冲的宽度携带信息。这个压缩包的关键词虽然出现了PWM但摘要和文件名都指向PAM调制。在MATLAB里实现PAM非常简单但要把误码率曲线做准确仍需要理解电平映射和能量归一化。4.1 PAM调制的电平映射与星座图M进制PAM将log2(M)个比特映射成一个电平电平集合是等间隔的通常是{±1, ±3, ..., ±(M-1)}也可以从0开始。二进制PAM就是双极性信号所以第2章里的双极性NRZ其实就是2-PAM。M越大每个符号携带的比特越多但相邻电平的距离变小抗噪声能力下降。MATLAB的pammod函数生成的符号默认是0到M-1的实数映射并不严格落在{±1, ±3}它默认的是1:M映射到-M1:2:M-1具体要看版本。因此使用pammod后最好做一次能量归一化让每个符号平均能量为1否则后续加噪声时EbN0的设置会偏。下面是标准的两行映射M 4; x randi([0 M-1], 1000, 1); sym pammod(x, M); % 默认电平仍在±1,±3附近 sym sym / sqrt(mean(abs(sym).^2)); % 归一化到平均能量1sqrt(mean(abs(sym).^2))是计算平均幅度除完后平均能量变成1。这样加噪时每个符号能量E_s1再折算E_bN0每比特时只需除以log2(M)即可。对于pamdemod它的判决边界在相邻电平的中点所以只要接收值处于两个电平之间就会判成对应的整数符号。4.2 用pammod/pamdemod搭一条完整链路完整链路包括符号生成、调制、加噪、解调、误码率统计。最可靠的方式是写成一个循环扫描多个SNR点。% pam_ber_curve.m M 4; k log2(M); numSym 100000; data randi([0 M-1], numSym, 1); EbN0dB 0:2:12; BER zeros(size(EbN0dB)); for idx 1:length(EbN0dB) EbN0 10^(EbN0dB(idx)/10); N0 1 / k / EbN0; % 归一化符号能量下噪声单边谱密度 noise sqrt(N0/2) * randn(numSym, 1); sym pammod(data, M); sym sym / sqrt(mean(abs(sym).^2)); rx sym noise; demod pamdemod(rx, M); BER(idx) sum(demod ~ data) / numSym; end semilogy(EbN0dB, BER, o-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER); title(sprintf(%d-PAM AWGN信道误码率, M));逻辑说明N01/k/EbN0是因为符号能量归一化为1每个符号携带k比特所以每比特能量Eb1/k噪声方差N0/2。sqrt(N0/2)是实高斯噪声的标准差。对PAM信号方差公式是N0/2而不是N0因为信号是实的噪声功率谱密度在[-N0/2,N0/2]上积分。pamdemod会自动计算判决边界但若使用了非对称电平映射需要在解调前做相同的归一化。BER(idx)在numSym较大时能稳定到三位小数想要更平滑可以改为Monte Carlo方式在误码数小于20时继续增加符号数。这里有一个常见的坑randn每次循环的噪声序列是独立生成的所以BER曲线不平滑但这也是真实蒙特卡洛结果的体现。如果希望曲线平滑就在外层循环前设置rng(42)但这样每个SNR点用的数据相同会带来相关性。更专业的做法是固定数据序列只重新生成噪声并在每个SNR点统计足够多的错误比特。4.3 多进制PAM的代价M增大与信噪比需求从2-PAM到4-PAM一个码元能传2比特带宽利用率翻倍。但星座点之间的欧氏距离减少到原来的约1/√3所以达到相同误码率需要更高的Eb/N0。理论误码率可以近似为Pb ≈ ((M−1)/(M·log2M))·erfc(√(3·log2M·EbN0/(M²−1)))这个公式在M2时退化为Q(√(2EbN0))的等价形式。仿真中如果M超过8曲线会迅速右移0dB时的误码率可能已经很高需要把SNR范围扩大到20dB。下面表格展示了不同M值下要达到10⁻⁴的BER大致需要的Eb/N0在AWGN理想相干解调下M所需Eb/N0 (dB)每个符号比特数带宽效率28.411 bit/s/Hz411.722 bit/s/Hz814.933 bit/s/Hz1618.344 bit/s/Hz这些数值来自理论公式不完全等同于实际pammod默认映射的结果但足够用来判断仿真曲线是否合理。如果仿真得到的曲线比表中数值差了1dB以上通常是能量归一化或噪声方差计算出了偏差。压缩包里的exe5.m、exe5sim.m和exe6.m很可能就是围绕这一组曲线做的exe5.mdl负责图形化模型exe5sim.m负责调用sim指令跑批处理exe6.m则可能把不同M的结果画在同一张图上。多进制PAM另一种常见实现是不用pammod而是自己定义电平映射比如用qammod把复数信号改为实数。此时需要特别注意编码顺序比如Gray编码和自然二进制编码在相临判决区域错误时产生不同的比特错误数。没有Gray编码的PAM在高SNR下误码率会比理论值略微偏高因为误命中的符号可能影响到不止1位比特。5. 把仿真结果跑稳模块参数、随机数种子和仿真发散的处理技巧5.1 用随机数种子和批量脚本控制重复性MATLAB仿真的一个隐藏陷阱是随机数流不可控。同一个exe5sim.m两次运行结果可能有微小差异这在调试时非常讨厌。我会在每个脚本开头加一行rng(shuffle)用于正式实验但调试阶段改成rng(2024)。批量做误码率扫描时把rng放在主脚本里子函数只接收数据不修改全局随机流否则每次调用都不一致。Simulink里同样可以通过set_param(mdl,RandomNumberGlobalSeed,2024)控制随机数生成模块的种子。5.2 仿真发散先查这三处Simulink模型仿真发散是.mdl模型最常见的故障现象是Scope里波形跑到±10³⁰或者求解器报错“Failed to converge”。我一般按顺序查这三处第一代数环。如果模型中存在输入直接经过Gain反馈回自身的环路步长再小也无法收敛需要在反馈路径插入Unit Delay或用Memory模块断开代数环。第二Solver步长。使用变步长求解器时由于通信信号是矩形波可能在跳变处强行减小步长导致发散把Solver改成Fixed-step并让步长等于采样周期的整数分之一比如1/(fsamp)。第三增益是否过大。AWGN信道模块的SNR若小于0dB噪声方差远大于信号幅度Scope纵坐标范围不够会看起来像发散实际只是信号被噪声淹没。下面是一个可用的模块检查列表现象检查对象处理波形瞬间到1e10代数环插入Unit Delay断开环路仿真时间走不动变步长求解器改Fixed-step步长取1/fs误码率接近0.5随机数种子重复更换rng种子或shuffle误码率比理论低采样点位置改为码元中点而非起点这些检查项基本涵盖了从.mdl模型到脚本的所有发散来源。处理完发散后用同一份随机数跑一次完整链路记录最终误码率数值再改成另一份种子跑一次两者差异如果超过10%说明仿真长度不足需要增大numBits或使用误差累计停止条件而不是急着调最终结果。最后再补充一个实用技巧exe7.mdl和exe7sim.m如果用于完整系统验证可以在模型里加一个Display模块直接观察解调符号并用To Workspace把接收符号导出到MATLAB变量这样就不用在Simulink里手动数点了。设置To Workspace的Save format为Timeseries然后在命令行用rx_sym out.y.signals.values提取与发射符号对比即可。这个做法能省去大量截图和人工核对适合课程设计最后验收。本文还有配套的精品资源点击获取
网站建设高端定制企业官网