如何用Python均匀化正弦/Chirp信号随时间变化的幅度
正弦/Chirp信号周期幅度归一化实现(Python)
核心思路
先提取信号的每个周期片段,计算整个信号范围内的最大峰峰值,再将每个周期的信号幅度缩放至该最大峰峰值,实现各周期幅度的统一。
步骤实现
1. 依赖库导入
import numpy as np import matplotlib.pyplot as plt from scipy.signal import hilbert, find_peaks
2. 生成测试信号(带幅度波动的正弦/Chirp)
# 采样率 fs = 1000 t = np.linspace(0, 5, int(fs*5)) # 随时间波动的幅度调制因子 amp_modulation = 0.5 + 0.5*np.sin(2*np.pi*0.1*t) # 带幅度波动的正弦信号 signal_sine = amp_modulation * np.sin(2*np.pi*5*t) # 带幅度波动的Chirp信号(扫频5Hz到20Hz) freq_chirp = np.linspace(5, 20, len(t)) signal_chirp = amp_modulation * np.sin(2*np.pi*np.cumsum(freq_chirp)/fs)
3. 周期分割方法
- 正弦信号:通过上升沿过零点检测分割周期
def split_sine_cycles(signal, fs): # 定位信号从负变正的上升沿过零点 crossings = np.where(np.diff(np.sign(signal)) > 0)[0] # 按过零点切割出每个完整周期 cycles = [] for i in range(len(crossings)-1): cycles.append(signal[crossings[i]:crossings[i+1]]) return cycles
- Chirp信号:通过峰值检测分割周期(扫频时过零点间隔不稳定,峰值间隔更可靠)
def split_chirp_cycles(signal, fs): # 定位所有峰值点,设置最小间隔避免误检 peaks, _ = find_peaks(signal, distance=int(fs/np.max(freq_chirp))*0.8) # 按峰值切割出每个完整周期 cycles = [] for i in range(len(peaks)-1): cycles.append(signal[peaks[i]:peaks[i+1]]) return cycles
4. 计算全局最大峰峰值并归一化
def normalize_cycle_amplitude(cycles): # 计算每个周期的峰峰值 cycle_pps = [np.max(cycle) - np.min(cycle) for cycle in cycles] # 取全局最大峰峰值 max_pp = np.max(cycle_pps) # 对每个周期做幅度缩放 normalized_cycles = [] for cycle, pp in zip(cycles, cycle_pps): if pp == 0: normalized_cycles.append(cycle) else: normalized_cycles.append(cycle * (max_pp / pp)) # 拼接回完整信号 return np.concatenate(normalized_cycles), max_pp
5. 测试与可视化
# 处理正弦信号 sine_cycles = split_sine_cycles(signal_sine, fs) normalized_sine, max_pp_sine = normalize_cycle_amplitude(sine_cycles) # 处理Chirp信号 chirp_cycles = split_chirp_cycles(signal_chirp, fs) normalized_chirp, max_pp_chirp = normalize_cycle_amplitude(chirp_cycles) # 绘图对比原始与归一化信号 plt.figure(figsize=(12,8)) plt.subplot(221) plt.plot(t, signal_sine) plt.title('原始正弦信号') plt.subplot(222) plt.plot(t[:len(normalized_sine)], normalized_sine) plt.title(f'归一化正弦信号(最大峰峰值:{max_pp_sine:.2f})') plt.subplot(223) plt.plot(t, signal_chirp) plt.title('原始Chirp信号') plt.subplot(224) plt.plot(t[:len(normalized_chirp)], normalized_chirp) plt.title(f'归一化Chirp信号(最大峰峰值:{max_pp_chirp:.2f})') plt.tight_layout() plt.show()
关键建议
- 噪声预处理:如果信号含噪声,先通过
scipy.signal.wiener或巴特沃斯滤波处理,避免过零点/峰值检测误判。 - Chirp信号优化:快速扫频场景下,可通过Hilbert变换计算瞬时频率,精准预估每个周期的采样点数:
analytic_signal = hilbert(signal_chirp) instantaneous_phase = np.unwrap(np.angle(analytic_signal)) instantaneous_freq = np.diff(instantaneous_phase)/(2*np.pi)*fs - 边界处理:首尾的不完整周期建议直接丢弃,避免拉低归一化效果。
- 实时流处理:针对实时信号,可采用滑动窗口检测周期,每识别出一个完整周期就完成归一化并输出。
内容的提问来源于stack exchange,提问作者VJA
相关产品推荐
相关产品推荐

