NumPy 快速傅立叶变换 (FFT) 不适用于 Audacity 中生成的正弦波
NumPy Fast Fourier transform (FFT) does not work on sine wave generated in Audacity
我正在尝试使用 Python 的 NumPy 库来进行一些频率分析。我有两个 .wav 文件,它们都包含 440 Hz 正弦波。其中一个是我使用 NumPy 正弦函数生成的,另一个是我在 Audacity 中生成的。 FFT 适用于 Python 生成的,但对 Audacity 没有任何作用。
以下是两个文件的链接:
非工作文件:440_audacity.wav
工作文件:440_gen.wav
这是我用来进行傅里叶变换的代码:
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
infile = "440_gen.wav"
rate, data = wave.read(infile)
data = np.array(data)
data_fft = np.fft.fft(data)
frequencies = np.abs(data_fft)
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(frequencies)
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()
我有两个 16 位 PCM .wav 文件,一个来自 Audacity,一个使用 NumPy 正弦函数创建。 NumPy 生成的结果给出了以下(正确的)结果,尖峰频率为 440Hz:
我用 Audacity 创建的那个,虽然波形看起来相同,但没有给出傅立叶变换的任何结果:
我承认我在这里不知所措。这两个文件实际上应该包含相同的数据。它们的编码方式相同,波形在上图中显示相同。
这是用于生成工作文件的代码:
import numpy as np
import wave
import struct
import matplotlib.pyplot as plt
from operator import add
freq_one = 440.0
num_samples = 44100
sample_rate = 44100.0
amplitude = 12800
file = "440_gen.wav"
s1 = [np.sin(2 * np.pi * freq_one * x/sample_rate) * amplitude for x in range(num_samples)]
sine_one = np.array(s1)
nframes = num_samples
comptype = "NONE"
compname="not compressed"
nchannels = 1
sampwidth = 2
wav_file = wave.open(file, 'w')
wav_file.setparams((nchannels, sampwidth, int(sample_rate), nframes, comptype, compname))
for s in sine_one:
wav_file.writeframes(struct.pack('h', int(s)))
自从@Konyukh Fyodorov 回答了这个问题后,便能够提供更好且合理的解决方案(如下)。
以下对我有用,并按预期生成了图。不幸的是,我无法完全理解为什么会这样,但我分享这个解决方案是希望它能帮助其他人实现这一飞跃。
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
infile = "440_gen.wav"
rate, data = wave.read(infile)
data = np.array(data)
# Use first 44100 datapoints in transform
data_fft = np.fft.fft(data[:44100])
frequencies = np.abs(data_fft)
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(frequencies)
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()
让我解释一下为什么您的代码不起作用。以及为什么它适用于 [:44100]
.
首先,你有不同的文件:
440_gen.wav = 1 sec and 44100 samples (counts)
440_audacity.wav = 5 sec and 220500 samples (counts)
由于 FFT 中的 440_gen.wav
您使用参考点数 N=44100 和采样率 44100,您的频率分辨率为 1 Hz(bin 以 1 Hz 的增量跟随)。
因此,在图表上,每个 FFT 样本对应于等于 1 Hz 的增量。
plt.xlim(0, 1000)
刚好对应范围0-1000Hz。
但是,对于 FFT 中的 440_audacity.wav
,您使用参考点数 N=220500 和采样率 44100。您的频率分辨率为 0.2 Hz(区间以 0.2 Hz 的增量跟随)- 在图表上,每个 FFT 样本对应于 0.2 Hz 增量的频率(最小-最大 = +(-) 22500 Hz)。
plt.xlim(0, 1000)
正好对应范围 1000x0.2 = 0-200 Hz.
这就是结果不可见的原因 - 它不在此范围内。
plt.xlim (0, 5000)
将更正您的情况并将范围扩展到 0-1000 Hz。
jwalton引入的解决方案[:44100]
实际上只强制FFT使用N = 44100。这重复了计算[=46=的情况]
您的问题更正确的解决方案是在代码中使用 N (Windows Size)
参数和 np.fft.fftfreq()
函数。
示例代码如下。
我也推荐一篇优秀的文章https://realpython.com/python-scipy-fft/
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
N = 44100 # added
infile = "440_audacity.wav"
rate, data = wave.read(infile)
data = np.array(data)
data_fft = np.fft.fft(data, N) # added N
frequencies = np.abs(data_fft)
x_freq = np.fft.fftfreq(N, 1/44100) # added
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(x_freq, frequencies) # added x_freq
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()
我正在尝试使用 Python 的 NumPy 库来进行一些频率分析。我有两个 .wav 文件,它们都包含 440 Hz 正弦波。其中一个是我使用 NumPy 正弦函数生成的,另一个是我在 Audacity 中生成的。 FFT 适用于 Python 生成的,但对 Audacity 没有任何作用。
以下是两个文件的链接:
非工作文件:440_audacity.wav
工作文件:440_gen.wav
这是我用来进行傅里叶变换的代码:
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
infile = "440_gen.wav"
rate, data = wave.read(infile)
data = np.array(data)
data_fft = np.fft.fft(data)
frequencies = np.abs(data_fft)
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(frequencies)
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()
我有两个 16 位 PCM .wav 文件,一个来自 Audacity,一个使用 NumPy 正弦函数创建。 NumPy 生成的结果给出了以下(正确的)结果,尖峰频率为 440Hz:
我用 Audacity 创建的那个,虽然波形看起来相同,但没有给出傅立叶变换的任何结果:
我承认我在这里不知所措。这两个文件实际上应该包含相同的数据。它们的编码方式相同,波形在上图中显示相同。
这是用于生成工作文件的代码:
import numpy as np
import wave
import struct
import matplotlib.pyplot as plt
from operator import add
freq_one = 440.0
num_samples = 44100
sample_rate = 44100.0
amplitude = 12800
file = "440_gen.wav"
s1 = [np.sin(2 * np.pi * freq_one * x/sample_rate) * amplitude for x in range(num_samples)]
sine_one = np.array(s1)
nframes = num_samples
comptype = "NONE"
compname="not compressed"
nchannels = 1
sampwidth = 2
wav_file = wave.open(file, 'w')
wav_file.setparams((nchannels, sampwidth, int(sample_rate), nframes, comptype, compname))
for s in sine_one:
wav_file.writeframes(struct.pack('h', int(s)))
自从@Konyukh Fyodorov 回答了这个问题后,便能够提供更好且合理的解决方案(如下)。
以下对我有用,并按预期生成了图。不幸的是,我无法完全理解为什么会这样,但我分享这个解决方案是希望它能帮助其他人实现这一飞跃。
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
infile = "440_gen.wav"
rate, data = wave.read(infile)
data = np.array(data)
# Use first 44100 datapoints in transform
data_fft = np.fft.fft(data[:44100])
frequencies = np.abs(data_fft)
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(frequencies)
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()
让我解释一下为什么您的代码不起作用。以及为什么它适用于 [:44100]
.
首先,你有不同的文件:
440_gen.wav = 1 sec and 44100 samples (counts)
440_audacity.wav = 5 sec and 220500 samples (counts)
由于 FFT 中的 440_gen.wav
您使用参考点数 N=44100 和采样率 44100,您的频率分辨率为 1 Hz(bin 以 1 Hz 的增量跟随)。
因此,在图表上,每个 FFT 样本对应于等于 1 Hz 的增量。
plt.xlim(0, 1000)
刚好对应范围0-1000Hz。
但是,对于 FFT 中的 440_audacity.wav
,您使用参考点数 N=220500 和采样率 44100。您的频率分辨率为 0.2 Hz(区间以 0.2 Hz 的增量跟随)- 在图表上,每个 FFT 样本对应于 0.2 Hz 增量的频率(最小-最大 = +(-) 22500 Hz)。
plt.xlim(0, 1000)
正好对应范围 1000x0.2 = 0-200 Hz.
这就是结果不可见的原因 - 它不在此范围内。
plt.xlim (0, 5000)
将更正您的情况并将范围扩展到 0-1000 Hz。
jwalton引入的解决方案[:44100]
实际上只强制FFT使用N = 44100。这重复了计算[=46=的情况]
您的问题更正确的解决方案是在代码中使用 N (Windows Size)
参数和 np.fft.fftfreq()
函数。
示例代码如下。
我也推荐一篇优秀的文章https://realpython.com/python-scipy-fft/
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
N = 44100 # added
infile = "440_audacity.wav"
rate, data = wave.read(infile)
data = np.array(data)
data_fft = np.fft.fft(data, N) # added N
frequencies = np.abs(data_fft)
x_freq = np.fft.fftfreq(N, 1/44100) # added
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(x_freq, frequencies) # added x_freq
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()