如何用Python实现信号频谱畸变:将尖锐频率峰展宽?
实现信号频率峰的模糊畸变并导出音频文件
要把带有尖锐频率峰的信号处理成频谱宽泛模糊的效果,用Python可以通过几种不同的方法实现,下面是具体的实操方案,都能最终导出WAV音频文件:
方法1:随机频率调制(模拟自然频率波动)
这种方法通过缓慢改变信号的瞬时频率,让原本固定的单频率峰变成一个波动的频带,适合模拟类似乐器颤音的自然模糊效果。
代码实现
import numpy as np import soundfile as sf from scipy.signal import butter, filtfilt # 1. 生成/读取原始信号(这里以1kHz正弦波为例,带尖锐频率峰) sample_rate = 44100 duration = 2.0 t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False) original_freq = 1000.0 original_signal = np.sin(2 * np.pi * original_freq * t) # 2. 实现频率调制模糊 freq_dev = 50.0 # 最大频率偏移,控制模糊宽度(值越大模糊越宽) noise = np.random.normal(0, 1, len(t)) # 低通滤波平滑噪声,让频率变化更平缓 def butter_lowpass_filter(data, cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = butter(order, normal_cutoff, btype='low', analog=False) return filtfilt(b, a, data) smoothed_noise = butter_lowpass_filter(noise, 5, sample_rate) freq_offset = freq_dev * smoothed_noise # 计算累积相位,生成调制后的信号 instantaneous_freq = original_freq + freq_offset phase = np.cumsum(2 * np.pi * instantaneous_freq / sample_rate) distorted_signal = np.sin(phase) # 3. 归一化并保存音频 distorted_signal = distorted_signal / np.max(np.abs(distorted_signal)) sf.write('distorted_fm.wav', distorted_signal, sample_rate)
关键参数说明
freq_dev:控制频率波动的最大范围,比如设为50表示频率在950-1050Hz之间波动- 低通滤波的截止频率设为5Hz,确保频率变化足够缓慢,避免信号出现刺耳的突变
方法2:频域频谱平滑(精准控制模糊程度)
直接对信号的频谱进行傅里叶变换,用高斯核卷积平滑尖锐的频率峰,再逆变换回时域,这种方法不会引入额外噪声,效果更干净。
代码实现
import numpy as np import soundfile as sf from scipy.fft import rfft, irfft, rfftfreq # 1. 生成/读取原始信号 sample_rate = 44100 duration = 2.0 t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False) original_freq = 1000.0 original_signal = np.sin(2 * np.pi * original_freq * t) # 2. 频域平滑处理 freqs = rfftfreq(len(original_signal), 1/sample_rate) signal_fft = rfft(original_signal) # 生成高斯平滑核,控制模糊宽度 sigma = 20.0 # 高斯核标准差,值越大平滑效果越强(模糊越宽) # 针对特定频率峰的高斯核,若要平滑所有峰可改为全局高斯核 gaussian_kernel = np.exp(-(freqs - original_freq)**2 / (2 * sigma**2)) # 频域相乘等价于时域卷积,实现频谱平滑 smoothed_fft = signal_fft * gaussian_kernel distorted_signal = irfft(smoothed_fft) # 3. 归一化保存 distorted_signal = distorted_signal / np.max(np.abs(distorted_signal)) sf.write('distorted_spectrum_smooth.wav', distorted_signal, sample_rate)
关键参数说明
sigma:控制频谱平滑的程度,值越大,尖锐峰被抹开的范围越宽- 如果原始信号有多个尖锐频率峰,可以叠加多个对应不同频率的高斯核来处理
方法3:叠加窄带噪声(带噪感的模糊效果)
给原始信号叠加目标频率附近的窄带噪声,让尖锐的频率峰被噪声覆盖成宽峰,适合需要带有“嘈杂感”的模糊效果。
代码实现
import numpy as np import soundfile as sf from scipy.signal import butter, filtfilt # 1. 生成/读取原始信号 sample_rate = 44100 duration = 2.0 t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False) original_freq = 1000.0 original_signal = np.sin(2 * np.pi * original_freq * t) # 2. 生成并叠加窄带噪声 noise_amplitude = 0.3 # 噪声幅度,控制模糊的强度 noise = np.random.normal(0, noise_amplitude, len(t)) # 带通滤波保留目标频率附近的噪声 def butter_bandpass_filter(data, lowcut, highcut, fs, order=5): nyq = 0.5 * fs low = lowcut / nyq high = highcut / nyq b, a = butter(order, [low, high], btype='band') return filtfilt(b, a, data) # 保留950-1050Hz的噪声,带宽控制模糊宽度 band_noise = butter_bandpass_filter(noise, original_freq-50, original_freq+50, sample_rate) distorted_signal = original_signal + band_noise # 3. 归一化保存 distorted_signal = distorted_signal / np.max(np.abs(distorted_signal)) sf.write('distorted_noise.wav', distorted_signal, sample_rate)
关键参数说明
noise_amplitude:控制噪声的强度,值越大噪声越明显,模糊效果越强- 带通滤波的上下限决定了噪声的带宽,也就是频谱峰被模糊的宽度
内容的提问来源于stack exchange,提问作者Sonne
相关产品推荐
相关产品推荐

