使用 FFT 确定低频信号的幅度
Determine amplitude of low frequency signals using FFT
我对信号处理完全陌生,我正在尝试制作一个程序来显示 PCM (WAV) 文件中低频信号的幅度。
到目前为止,我已经能够读取 WAV 文件并填充一个数组(实际上是一个多维数组,每个通道一个,但我们只考虑逐个通道) float
使用从 WAV 中获取的声音文件的数据点。每个数据点都是一个振幅。 简而言之,我有了声波的时域表示。
我用它来绘制波幅相对于时间的图表,看起来像:
我的目标是完全相同,但只显示低于特定值(例如 350Hz)的频率。需要明确的是,我并不是想在频域中显示图形(即在快速傅里叶变换之后)。我想显示相同的振幅与时间图,但频率在 [0, 350Hz] 范围内。
我正在寻找可以执行以下操作的函数:
// Returns an array of data points that contains
// amplitude data points, after a low pass filter
float[] low_pass_filter(float[] original_data, float low_pass_freq=350.0)
{
...
}
我已经阅读了 FFT,阅读 Chris Lomont's code for the FFT 并理解了低通滤波器背后的 "theory",但我发现很难理解如何实际实现此特定功能(上文)。任何帮助(+解释)将不胜感激!
我最终使用了非常有效的 this 示例。我把它包装得更好一点,最后是:
/// <summary>
/// Returns a low-pass filter of the data
/// </summary>
/// <param name="data">Data to filter</param>
/// <param name="cutoff_freq">The frequency below which data will be preserved</param>
private float[] lowPassFilter(ref float[] data, float cutoff_freq, int sample_rate, float quality_factor=1.0f)
{
// Calculate filter parameters
float O = (float)(2.0 * Math.PI * cutoff_freq / sample_rate);
float C = quality_factor / O;
float L = 1 / quality_factor / O;
// Loop through and apply the filter
float[] output = new float[data.Length];
float V = 0, I = 0, T;
for (int s = 0; s < data.Length; s++)
{
T = (I - V) / C;
I += (data[s] * O - V) / L;
V += T;
output[s] = V / O;
}
return output;
}
常规和低通波形的输出:
并将常规波形与低通波形隔离开来:
我对信号处理完全陌生,我正在尝试制作一个程序来显示 PCM (WAV) 文件中低频信号的幅度。
到目前为止,我已经能够读取 WAV 文件并填充一个数组(实际上是一个多维数组,每个通道一个,但我们只考虑逐个通道) float
使用从 WAV 中获取的声音文件的数据点。每个数据点都是一个振幅。 简而言之,我有了声波的时域表示。
我用它来绘制波幅相对于时间的图表,看起来像:
我的目标是完全相同,但只显示低于特定值(例如 350Hz)的频率。需要明确的是,我并不是想在频域中显示图形(即在快速傅里叶变换之后)。我想显示相同的振幅与时间图,但频率在 [0, 350Hz] 范围内。
我正在寻找可以执行以下操作的函数:
// Returns an array of data points that contains
// amplitude data points, after a low pass filter
float[] low_pass_filter(float[] original_data, float low_pass_freq=350.0)
{
...
}
我已经阅读了 FFT,阅读 Chris Lomont's code for the FFT 并理解了低通滤波器背后的 "theory",但我发现很难理解如何实际实现此特定功能(上文)。任何帮助(+解释)将不胜感激!
我最终使用了非常有效的 this 示例。我把它包装得更好一点,最后是:
/// <summary>
/// Returns a low-pass filter of the data
/// </summary>
/// <param name="data">Data to filter</param>
/// <param name="cutoff_freq">The frequency below which data will be preserved</param>
private float[] lowPassFilter(ref float[] data, float cutoff_freq, int sample_rate, float quality_factor=1.0f)
{
// Calculate filter parameters
float O = (float)(2.0 * Math.PI * cutoff_freq / sample_rate);
float C = quality_factor / O;
float L = 1 / quality_factor / O;
// Loop through and apply the filter
float[] output = new float[data.Length];
float V = 0, I = 0, T;
for (int s = 0; s < data.Length; s++)
{
T = (I - V) / C;
I += (data[s] * O - V) / L;
V += T;
output[s] = V / O;
}
return output;
}
常规和低通波形的输出:
并将常规波形与低通波形隔离开来: