公司动态
MATLAB实战:从零构建AM/FM调制解调系统与性能分析
1. 从零理解AM/FM调制原理第一次接触通信调制时我被那些数学公式绕得头晕。直到用MATLAB画出波形图才真正明白调制就是在玩载波变形记。想象载波是个快递小哥调制信号是要送的包裹调制过程就是把包裹绑在小哥身上。AM调幅就像让快递小哥变胖变瘦。假设载波是cos(2πfct)调制信号是m(t)标准AM信号公式就是s_AM (A m(t)) .* cos(2πfct); % A是直流偏置这个公式的妙处在于包络线(Am(t))完全复现了原始信号。我常用来演示的案例是fc 1000; % 载波频率1kHz fm 50; % 音频50Hz t 0:1/48000:0.1; % 48kHz采样率 m 0.8*cos(2*pi*fm*t); % 调制信号 s_AM (1 m) .* cos(2*pi*fc*t);画出来的波形就像被50Hz正弦波捏扁搓圆的载波用envelope函数可以完美提取包络。FM调频则是让快递小哥加速减速。瞬时频率随m(t)变化phi 2*pi*fc*t 2*pi*kf*cumsum(m)*dt; % 相位积分 s_FM cos(phi); % kf是频偏常数这里有个坑cumsum(m)*dt实现了对m(t)的积分运算当初我忘了乘采样间隔dt结果频偏完全不对。FM的频谱更复杂用MATLAB的spectrogram函数能看到频率随时间波动。2. 手把手搭建AM调制系统2.1 标准AM调制实战先看完整代码框架function [s_AM, t] am_modulate(fc, fm, fs, duration) % 参数设置 t 0:1/fs:duration-1/fs; m 0.9*cos(2*pi*fm*t); % 避免过调制 % 调制核心代码 carrier cos(2*pi*fc*t); s_AM (1 m) .* carrier; % 可视化 figure; subplot(2,1,1); plot(t, s_AM); hold on; plot(t, 1m, r--); % 显示包络 title(AM调制波形); % 频谱分析 [f, PSD] my_fft(s_AM, fs); subplot(2,1,2); plot(f, PSD); title(AM信号频谱); end关键点在于调制指数β0.9留10%余量防过调my_fft是自写函数比直接fft多了幅值校准2.2 解调方案对比测试我对比过三种解调方法包络检波最简单envelope abs(hilbert(s_AM)) - 1; % 希尔伯特变换相干解调需载波同步coherent s_AM .* cos(2*pi*fc*t); demod lowpass(coherent, fm, fs);数字正交解调抗频偏最强I s_AM .* cos(2*pi*fc*t); Q -s_AM .* sin(2*pi*fc*t); demod sqrt(I.^2 Q.^2);实测发现当载波存在1%频偏时相干解调信噪比下降20dB而数字正交法仅下降3dB。不过计算量会大3倍这是典型的性能与复杂度权衡。3. FM调制系统实现技巧3.1 窄带FM与宽带FMFM系统有两个工作模式% 窄带FMβ0.3 beta 0.2; s_NBFM cos(2*pi*fc*t beta*sin(2*pi*fm*t)); % 宽带FMβ1 beta 5; s_WBFM cos(2*pi*fc*t beta*sin(2*pi*fm*t));窄带FM频谱类似AM但有相位跳变宽带FM会产生大量边频。用MATLAB的freqdev函数可以测量实际频偏。3.2 解调中的微分陷阱FM解调本质是相位微分但直接数值微分会放大噪声。我的改进方案% 传统微分法 diff_phase diff(unwrap(angle(hilbert(s_FM)))); demod [0 diff_phase]/(2*pi*kf); % 改进的平滑微分 [b,a] butter(4, 2*fm/fs); demod filtfilt(b, a, diff_phase);实测显示平滑微分能使信噪比提升15dB以上。此外锁相环解调在强噪声下表现更好但MATLAB实现较复杂需要phased.PhaseLockedLoop对象。4. 性能分析与实战建议4.1 抗噪声能力实测在相同信道条件下SNR10dBAM系统误码率约1e-2FM系统可达1e-4SSB介于两者之间测试代码框架noisy_signal awgn(s_AM, 10, measured); ber sum(abs(demod - m) 0.5)/length(m);4.2 参数选择经验载波频率至少8倍信号最高频率防混叠采样率建议4倍载频以上滤波器设计% AM解调用的低通滤波器 b fir1(50, 2*fm/fs, low);调试技巧总是先测试单频信号如1kHz正弦波再过渡到实际语音信号。最后分享一个血泪教训曾因没加unwrap函数导致相位解调跳变调试了整整两天。现在我的代码里一定会加上phase unwrap(angle(hilbert(signal))); % 防相位跳变