如何用Python计算信号处理中频率的标准差?作业代码求助
问题诊断与修正方案
核心错误分析
你计算频率标准差的逻辑完全错误:
- 原代码中
np.sum(f - average_frequency )**2是先对频率与均值的差求和再平方,正负差值会相互抵消,结果毫无意义 - 没有沿用计算均值时的幅值平方加权逻辑,标准差必须和均值使用一致的权重才合理
- 分母误用了FFT数据长度
len(x),而非加权求和的总权重denominator
修正后的完整代码
from scipy.fftpack import fft from scipy.io import wavfile as wav import numpy as np import matplotlib.pyplot as plt import scipy.signal as sig def mean_freq(data, sample_rate): x = fft(data) f = np.linspace(0.0, sample_rate / 2.0, len(x) // 2) abs_x = abs(x)[0:int(len(x) / 2)] x_squared = abs_x ** 2 denominator = np.sum(x_squared) # 加权频率均值(原逻辑正确,保留) average_frequency = np.sum(f * x_squared) / denominator # 加权频率方差与标准差(修正核心逻辑) weighted_variance = np.sum(x_squared * (f - average_frequency)**2) / denominator stdv = np.sqrt(weighted_variance) return round(average_frequency), round(stdv) # 读取音频,若为立体声则转单声道 fs, signal = wav.read('RECORDEDFILE.wav') if len(signal.shape) > 1: signal = signal[:, 0] # 取左声道处理 # 滤波器参数 n = 3 nyquist = fs / 2 # 设计并应用基频带通滤波器 lcf = 85 / nyquist hcf = 155 / nyquist b, a = sig.butter(n, [lcf, hcf], btype='bandpass', analog=False, output='ba') filtered_signal = sig.filtfilt(b, a, signal, axis=0) # 计算并输出结果 mean1, stdv1 = mean_freq(filtered_signal, fs) print(f'基频均值: {mean1} Hz') print(f'基频标准差: {stdv1} Hz')
关键补充说明
- 加权逻辑一致性:频率均值是基于幅值平方加权的(反映各频率成分的能量占比),标准差必须使用相同权重,否则结果不具备物理意义
- 立体声处理:若你的录音是双声道,必须先转为单声道,否则多通道数据会干扰FFT和滤波结果
- 频谱验证:可以添加以下代码绘制滤波后的频谱,确认信号集中在目标频段:
# 绘制滤波后信号频谱 x_fft = fft(filtered_signal) f_fft = np.linspace(0, fs/2, len(x_fft)//2) abs_x_fft = abs(x_fft[:len(x_fft)//2]) plt.plot(f_fft, abs_x_fft) plt.xlabel('频率 (Hz)') plt.ylabel('幅值') plt.xlim(0, 300) # 聚焦基频附近 plt.show()
- 谐波分离:得到基频均值后,二次谐波频段可设为
[2*mean1-35, 2*mean1+35],三次谐波设为[3*mean1-35, 3*mean1+35],用相同的Butterworth带通滤波逻辑即可分离
内容的提问来源于stack exchange,提问作者Matan Shaked
相关产品推荐
相关产品推荐

