調頻(FM)和調幅(AM)信號生成
文章目錄
- 調頻(FM)和調幅(AM)信號生成
- 1. 調頻(FM)和調幅(AM)信號原理與信號生成
- 調幅(AM)原理
- 調頻(FM)原理
- 2. 可配置參數
- 3. C語言實現
- 4. Python驗證代碼
- 5. 驗證結果說明
不依賴任何第三方庫,用C語言生成FM以及AM信號,并使用python進行數據頻譜分析,確認C語言實現的正確性。
話不多說,實戰開始。
1. 調頻(FM)和調幅(AM)信號原理與信號生成
調幅(AM)原理
調幅通過改變載波的振幅來攜帶信息:
- 數學表達式:s(t)=Ac[1+μ?m(t)]?cos?(2πfct)s(t) = A_c[1 + \mu \cdot m(t)] \cdot \cos(2\pi f_c t)s(t)=Ac?[1+μ?m(t)]?cos(2πfc?t)
- AcA_cAc?:載波振幅
- fcf_cfc?:載波頻率
- m(t)m(t)m(t):歸一化的調制信號(?1≤m(t)≤1-1 \leq m(t) \leq 1?1≤m(t)≤1)
- μ\muμ:調制指數(0~1),控制調制深度
調頻(FM)原理
調頻通過改變載波的瞬時頻率來攜帶信息:
- 數學表達式:s(t)=Accos?(2πfct+2πkf∫0tm(τ)dτ)s(t) = A_c \cos\left(2\pi f_c t + 2\pi k_f \int_0^t m(\tau)d\tau\right)s(t)=Ac?cos(2πfc?t+2πkf?∫0t?m(τ)dτ)
- kfk_fkf?:頻率偏移靈敏度(Hz/Volt)
- 最大頻偏:Δf=kf?max?(∣m(t)∣)\Delta f = k_f \cdot \max(|m(t)|)Δf=kf??max(∣m(t)∣)
- 調制指數:β=Δf/fm\beta = \Delta f / f_mβ=Δf/fm?(fmf_mfm?為調制信號頻率)
2. 可配置參數
參數類型 | AM參數 | FM參數 |
---|---|---|
載波參數 | 振幅 AcA_cAc? | 振幅 AcA_cAc? |
頻率 fcf_cfc? | 頻率 fcf_cfc? | |
調制參數 | 調制頻率 fmf_mfm? | 調制頻率 fmf_mfm? |
調制指數 μ\muμ | 最大頻偏 Δf\Delta fΔf | |
采樣參數 | 采樣率 fsf_sfs? | 采樣率 fsf_sfs? |
持續時間 TTT | 持續時間 TTT |
3. C語言實現
#include <stdio.h>
#include <stdlib.h>
#include <math.h>// 通用信號配置
typedef struct {float carrier_amp; // 載波振幅 (A_c)float carrier_freq; // 載波頻率 (f_c)float mod_freq; // 調制信號頻率 (f_m)float mod_index; // AM調制指數 (μ) / FM最大頻偏 (Δf)float duration; // 信號時長 (秒)int sample_rate; // 采樣率 (f_s)
} SignalConfig;// 生成AM信號并保存為bin文件
void generate_am(const SignalConfig *cfg, const char *filename) {const int num_samples = cfg->duration * cfg->sample_rate;float *signal = malloc(num_samples * sizeof(float));for (int i = 0; i < num_samples; i++) {float t = (float)i / cfg->sample_rate;float mod_signal = sin(2 * M_PI * cfg->mod_freq * t); // 調制信號float carrier = cos(2 * M_PI * cfg->carrier_freq * t); // 載波signal[i] = cfg->carrier_amp * (1 + cfg->mod_index * mod_signal) * carrier;}FILE *file = fopen(filename, "wb");fwrite(signal, sizeof(float), num_samples, file);fclose(file);free(signal);
}// 生成FM信號并保存為bin文件
void generate_fm(const SignalConfig *cfg, const char *filename) {const int num_samples = cfg->duration * cfg->sample_rate;float *signal = malloc(num_samples * sizeof(float));float phase_integral = 0.0f;float dt = 1.0f / cfg->sample_rate; // 時間步長for (int i = 0; i < num_samples; i++) {float t = (float)i / cfg->sample_rate;float mod_signal = sin(2 * M_PI * cfg->mod_freq * t); // 調制信號phase_integral += mod_signal * dt; // 積分項float phase = 2 * M_PI * cfg->carrier_freq * t + 2 * M_PI * cfg->mod_index * phase_integral;signal[i] = cfg->carrier_amp * cos(phase);}FILE *file = fopen(filename, "wb");fwrite(signal, sizeof(float), num_samples, file);fclose(file);free(signal);
}int main() {// AM示例配置SignalConfig am_cfg = {.carrier_amp = 1.0f,.carrier_freq = 1000.0f, // 1 kHz.mod_freq = 100.0f, // 100 Hz.mod_index = 0.8f, // μ=0.8.duration = 0.1f, // 100 ms.sample_rate = 48000 // 48 kHz};generate_am(&am_cfg, "am_signal.bin");// FM示例配置SignalConfig fm_cfg = {.carrier_amp = 1.0f,.carrier_freq = 1000.0f, // 1 kHz.mod_freq = 100.0f, // 100 Hz.mod_index = 200.0f, // Δf=200 Hz.duration = 0.1f, // 100 ms.sample_rate = 48000 // 48 kHz};generate_fm(&fm_cfg, "fm_signal.bin");return 0;
}
4. Python驗證代碼
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbertdef read_bin_file(filename):return np.fromfile(filename, dtype=np.float32)def plot_signal_analysis(signal, sample_rate, title):# 時域圖time = np.arange(len(signal)) / sample_rateplt.figure(figsize=(12, 8))plt.subplot(3, 1, 1)plt.plot(time, signal)plt.title(f'{title} - Time Domain')plt.xlabel('Time (s)')plt.ylabel('Amplitude')plt.grid(True)# 頻譜圖plt.subplot(3, 1, 2)spectrum = np.abs(np.fft.rfft(signal))freqs = np.fft.rfftfreq(len(signal), 1/sample_rate)plt.plot(freqs, 20 * np.log10(spectrum + 1e-10)) # dB 刻度plt.title('Frequency Spectrum')plt.xlabel('Frequency (Hz)')plt.ylabel('Magnitude (dB)')plt.grid(True)plt.xlim(0, sample_rate/2)# 瞬時特征 (僅FM)if "FM" in title:plt.subplot(3, 1, 3)analytic_signal = hilbert(signal)instantaneous_phase = np.unwrap(np.angle(analytic_signal))instantaneous_freq = (np.diff(instantaneous_phase) / (2 * np.pi) * sample_rate)plt.plot(time[:-1], instantaneous_freq)plt.title('Instantaneous Frequency')plt.xlabel('Time (s)')plt.ylabel('Frequency (Hz)')plt.grid(True)plt.ylim(0, 2000) # 根據載波頻率調整plt.tight_layout()plt.savefig(f"{title.replace(' ', '_')}.png")plt.show()# 分析AM信號
am_signal = read_bin_file("am_signal.bin")
plot_signal_analysis(am_signal, 48000, "AM Signal")# 分析FM信號
fm_signal = read_bin_file("fm_signal.bin")
plot_signal_analysis(fm_signal, 48000, "FM Signal")# 驗證關鍵參數
def verify_am(signal, sample_rate, fc, fm, mu):spectrum = np.abs(np.fft.rfft(signal))freqs = np.fft.rfftfreq(len(signal), 1/sample_rate)carrier_idx = np.argmin(np.abs(freqs - fc))sideband_idx = np.argmin(np.abs(freqs - (fc + fm)))measured_mu = 2 * spectrum[sideband_idx] / spectrum[carrier_idx]print(f"AM驗證: 設定μ={mu:.2f}, 實測μ={measured_mu:.2f}")def verify_fm(signal, sample_rate, fc, delta_f):analytic_signal = hilbert(signal)instantaneous_freq = (np.diff(np.unwrap(np.angle(analytic_signal))) * sample_rate) / (2 * np.pi)measured_delta_f = (np.max(instantaneous_freq) - np.min(instantaneous_freq)) / 2print(f"FM驗證: 設定Δf={delta_f}Hz, 實測Δf={measured_delta_f:.1f}Hz")verify_am(am_signal, 48000, 1000, 100, 0.8)
verify_fm(fm_signal, 48000, 1000, 200)
5. 驗證結果說明
-
AM信號驗證:
- 時域圖:顯示振幅包絡按100Hz正弦變化
- 頻譜圖:在1kHz載波兩側出現100Hz間隔的邊帶
- 調制深度:通過邊帶與載波幅度比計算μ\muμ
-
FM信號驗證:
- 時域圖:恒定振幅,波形疏密變化
- 頻譜圖:能量分散在fc±Δff_c \pm \Delta ffc?±Δf范圍內
- 瞬時頻率:在fc±Δff_c \pm \Delta ffc?±Δf之間波動(示例:1000-1400Hz)
-
數值驗證:
AM驗證: 設定μ=0.80, 實測μ=0.80FM驗證: 設定Δf=200Hz, 實測Δf=200.3Hz
注:實際運行需安裝Python科學計算庫:
pip install numpy matplotlib scipy
研究學習不易,點贊易。
工作生活不易,收藏易,點收藏不迷茫 :)