别再傻傻分不清FM和PM了!用Python+Matplotlib手把手带你画波形、看频谱
用Python可视化FM与PM的本质差异从时域波形到频谱分析通信工程领域最令人困惑的概念之一莫过于频率调制(FM)与相位调制(PM)的本质区别。教科书上的数学公式虽然严谨但缺乏直观性。本文将带你用Python和Matplotlib通过代码生成信号并绘制图形从视觉角度揭示这两种调制方式的根本差异。1. 环境准备与基础概念在开始编码前我们需要明确几个核心概念。FM和PM都属于角度调制技术它们通过改变载波信号的相位角度来传递信息。但改变方式有本质不同FM频率调制瞬时频率随调制信号变化PM相位调制瞬时相位随调制信号变化安装必要的Python库pip install numpy matplotlib scipy基础参数设置后续所有示例都将使用这些参数import numpy as np import matplotlib.pyplot as plt # 通用参数 sample_rate 44100 # 采样率(Hz) duration 1.0 # 信号时长(s) t np.linspace(0, duration, int(sample_rate * duration), endpointFalse) # 载波信号 fc 1000 # 载波频率(Hz) Ac 1.0 # 载波振幅 # 调制信号 fm 100 # 调制频率(Hz) Am 1.0 # 调制信号振幅2. 单频调制信号的生成与可视化2.1 生成调制信号我们先创建一个简单的单频正弦波作为调制信号def generate_modulating_signal(t, fm, Am): return Am * np.sin(2 * np.pi * fm * t) mod_signal generate_modulating_signal(t, fm, Am)2.2 PM信号生成相位调制信号的数学表达式为 sₚₘ(t) A_c cos[ω_c t K_pm f(t)]Python实现def generate_pm_signal(t, fc, Ac, mod_signal, Kpm): carrier_phase 2 * np.pi * fc * t modulated_phase Kpm * mod_signal return Ac * np.cos(carrier_phase modulated_phase) Kpm 5 # 相位调制系数 pm_signal generate_pm_signal(t, fc, Ac, mod_signal, Kpm)2.3 FM信号生成频率调制信号的数学表达式为 s_fm(t) A_c cos[ω_c t K_fm ∫f(t)dt]Python实现def generate_fm_signal(t, fc, Ac, mod_signal, Kfm): carrier_phase 2 * np.pi * fc * t # 对调制信号积分 integrated_mod np.cumsum(mod_signal) * (1/sample_rate) modulated_phase Kfm * integrated_mod return Ac * np.cos(carrier_phase modulated_phase) Kfm 5000 # 频率调制系数 fm_signal generate_fm_signal(t, fc, Ac, mod_signal, Kfm)2.4 时域波形对比让我们绘制三种信号的时域波形plt.figure(figsize(12, 8)) # 调制信号 plt.subplot(3, 1, 1) plt.plot(t, mod_signal) plt.title(调制信号 ({}Hz).format(fm)) plt.xlabel(时间(s)) plt.ylabel(幅度) # PM信号 plt.subplot(3, 1, 2) plt.plot(t, pm_signal) plt.title(PM信号 (载波{}Hz).format(fc)) plt.xlabel(时间(s)) plt.ylabel(幅度) # FM信号 plt.subplot(3, 1, 3) plt.plot(t, fm_signal) plt.title(FM信号 (载波{}Hz).format(fc)) plt.xlabel(时间(s)) plt.ylabel(幅度) plt.tight_layout() plt.show()观察波形图可以发现PM信号的相位变化与调制信号同步FM信号的频率变化与调制信号同步当调制信号达到峰值时PM信号的相位偏移最大当调制信号变化率最大时FM信号的频率偏移最大3. 频谱分析与NBFM特性3.1 计算频谱使用快速傅里叶变换(FFT)分析信号频谱def plot_spectrum(signal, sample_rate, title): n len(signal) fft_result np.fft.fft(signal) freq np.fft.fftfreq(n, d1/sample_rate) plt.figure(figsize(10, 4)) plt.plot(freq[:n//2], np.abs(fft_result[:n//2])) plt.title(title) plt.xlabel(频率(Hz)) plt.ylabel(幅度) plt.grid() plt.show() plot_spectrum(pm_signal, sample_rate, PM信号频谱) plot_spectrum(fm_signal, sample_rate, FM信号频谱)3.2 NBFM窄带调频分析窄带调频(NBFM)是调频指数β ≪ 1的特殊情况。此时FM信号的带宽约为2fm# 窄带FM参数 Kfm_narrow 100 # 较小的调制系数 fm_signal_narrow generate_fm_signal(t, fc, Ac, mod_signal, Kfm_narrow) plot_spectrum(fm_signal_narrow, sample_rate, NBFM信号频谱 (β 1))从频谱图中可以观察到NBFM频谱确实集中在载波频率±fm范围内主要能量集中在fc±fm处带宽约为2fm这与AM信号的带宽特性相似但产生机制完全不同4. 调制指数的影响与实验对比4.1 调制指数的定义调制指数是描述角度调制深度的重要参数PM调制指数β_pm K_pm × A_mFM调制指数β_fm K_fm × A_m / ω_m其中ω_m 2πf_m是调制信号的角频率。4.2 不同调制指数的对比实验让我们观察不同调制指数下FM信号的频谱变化mod_indices [0.5, 1.0, 2.0, 5.0] # 不同的调制指数 plt.figure(figsize(12, 8)) for i, beta in enumerate(mod_indices): Kfm beta * (2 * np.pi * fm) / Am # 根据β计算Kfm fm_signal generate_fm_signal(t, fc, Ac, mod_signal, Kfm) # 计算频谱 fft_result np.fft.fft(fm_signal) freq np.fft.fftfreq(len(fm_signal), d1/sample_rate) plt.subplot(2, 2, i1) plt.plot(freq[:len(fm_signal)//2], np.abs(fft_result[:len(fm_signal)//2])) plt.title(FM频谱 (β{}).format(beta)) plt.xlabel(频率(Hz)) plt.ylabel(幅度) plt.xlim(fc - 500, fc 500) plt.tight_layout() plt.show()实验结果展示了β0.5时频谱与NBFM相似带宽约2fmβ增大时出现更多边频分量带宽扩展β5时频谱明显展宽出现多个明显的边带4.3 卡森带宽规则对于宽带FM经验法则给出的带宽估计为 B ≈ 2(Δf f_m) 2f_m(1 β)其中Δf βf_m是最大频率偏移。5. 实际应用中的选择建议在工程实践中选择FM或PM时考虑以下因素特性FMPM抗噪声性能优秀广泛用于广播良好带宽需求较大特别是宽带FM相对较小实现复杂度需要积分器直接调制典型应用广播、模拟电视伴音数字通信、卫星通信几点实用建议对音频信号FM通常能提供更好的音质在带宽受限的场景考虑PM或NBFM数字通信中PM的变种如QPSK更为常见系统设计时要考虑调制解调的复杂度平衡