为什么没有绘制 FFT?

问题描述 投票:0回答:1

我正在研究频谱分析仪。我已经绘制了信号的时域图,但没有得到 FFT 结果。我添加了打印语句来检查我是否真正获得了预期范围内的真实值,并且看起来我得到了真实的结果。频率图似乎只是绘制了零。我真的不知道我做错了什么有人可以帮助我吗?

代码:

import pyaudio
import struct
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.fftpack import fft

CHUNK = 1024 * 2  # Defines the chunk size, i.e., the number of audio samples per frame that will be displayed.
FORMAT = pyaudio.paInt16 # Defines the audio format as 16-bit integers.
CHANNELS = 1  #  Defines the number of audio channels (mono sound).
RATE = 44100  #  Defines the sampling rate, i.e., the number of samples per second.

p = pyaudio.PyAudio()  # Creates a PyAudio object, which serves as the main interface for accessing audio I/O functionalities.

# Opens an audio stream for both input and output, specifying the format, channels, 
# sampling rate, and chunk size.
stream = p.open(
    format=FORMAT,
    channels=CHANNELS,
    rate=RATE,
    input=True,
    output=True,
    frames_per_buffer=CHUNK
)

# Creates a figure with two subplots (ax and ax2) for plotting the audio waveform and its FFT. 
# The figsize parameter sets the size of the figure.
fig, (ax, ax2) = plt.subplots(2, figsize=(15,8))

x = np.arange(0, 2 * CHUNK, 2) # Creates an array of x-values for plotting the audio waveform.
x_fft = np.linspace(0, RATE, CHUNK) # Creates an array of frequency values for plotting the FFT.

line, = ax.plot(x, np.random.rand(CHUNK)) # Initializes a line object for plotting the audio waveform in the first subplot (ax).
line_fft, = ax2.plot(x_fft, np.random.rand(CHUNK), '-', lw=2) # Initializes a line object for plotting the FFT in the second subplot (ax2).

ax.set_title('AUDIO WAVEFORM')
ax.set_xlabel('samples')
ax.set_ylabel('volume')
ax.set_ylim(0, 255) #Sets the y-axis limits for the first subplot.
ax.set_xlim(0, 2 * CHUNK) #Sets the x-axis limits for the first subplot.
plt.setp(ax, xticks=[0, CHUNK, 2 * CHUNK], yticks=[0, 128, 255]) #Sets the x and y-axis tick marks for the first subplot.

ax2.set_xlim(20, RATE / 2) # Sets the x-axis limits for the second subplot (FFT plot).


def animate(i):

    data = stream.read(CHUNK) #Reads a chunk of audio data from the audio stream (stream) with a size defined by CHUNK.
    
    # Unpacks the binary data (data) into an array of 8-bit unsigned integers (dtype=np.uint8). 
    # The ::2 slicing selects every other element, effectively downsampling the data to half its
    # original size. It then adds 127 to each element, likely to shift the signal to be centered 
    # around zero.
    data_int = np.array(struct.unpack(str(2 * CHUNK) + 'B', data), dtype=np.uint8)[::2] + 127
    #print("Data before FFT:", data_int[:10]) # Test line
    
    # Computes the Fast Fourier Transform (FFT) of the downsampled audio data (data_int), 
    # resulting in the frequency domain representation of the signal.
    y_fft = fft(data_int)
    print("FFT result:", y_fft[:10]) # Test line
    
    # Updates the y-data of the line object (line) representing the waveform plot to the 
    # downsampled audio data (data_int)
    line.set_ydata(data_int)

    # Normalize FFT data appropriately for plotting
    fft_scaled = np.abs(y_fft[:CHUNK]) * 2 / (256 * CHUNK)

    # Ensure that FFT data is within the expected range
    print("Scaled FFT data:", fft_scaled[:10])

    # Updates the y-data of the line object (line_fft) representing the FFT plot to the 
    # absolute values of the FFT of the first CHUNK elements of y_fft,
    # multiplied by 2 / (256 * CHUNK). 
    # This line is performing scaling and normalization of the FFT data.
    line_fft.set_ydata(fft_scaled)

    # Dynamically adjust y-axis limits of FFT plot
    # Computes the maximum value of the scaled and normalized 
    # FFT data for the first CHUNK elements of y_fft.
    max_fft_value = np.max(np.abs(y_fft[:CHUNK]) * 2 / (256 * CHUNK))
    print("FFT max value: ", max_fft_value)

    # Dynamically adjusts the y-axis limits of the FFT plot (ax2) to 
    # ensure that the highest peak of the FFT is still visible, with some additional padding.
    ax2.set_ylim(0, max_fft_value * 1.2)  # Add some padding

    return line,


ani = animation.FuncAnimation(fig, animate, blit=True, interval=25)

plt.show()

stream.stop_stream()
stream.close()
p.terminate()

打印报表结果:

Scaled FFT data: [1.00190353 0.01003554 0.01135945 0.01593705 0.01859334 0.05648837
 0.06349972 0.0216341  0.00649667 0.01902347]
FFT max value:  1.0019035339355469
FFT result: [259594.            -0.j           -526.89172194  -421.1684541j
   -620.77275816  -974.76759017j   -803.61321306 -1479.30911619j
  -1908.98839495 -3732.42741645j  -1478.50360353-12086.16043664j
   5823.63109812+13748.52907801j    753.9622711  +9723.42842246j
   -357.8251014  +5822.08840664j   2099.72688851  -132.28202223j]
Scaled FFT data: [0.99027252 0.00257315 0.00440846 0.00642202 0.0159923  0.04644874
 0.0569575  0.03720328 0.02225141 0.0080257 ]
FFT max value:  0.9902725219726562
FFT result: [259159.            -0.j           -975.66596305  -425.20673075j
   -983.06941718  -971.38178461j  -1768.07764966 -1830.20543882j
   -886.36585775 -3230.9819737j   -2409.68030269 -9523.59742976j
    385.63081796+13794.22263944j   3455.33296729 +6883.58167695j
  -2077.45964916 +4502.06539853j   3222.38202849 +5060.59360891j]
Scaled FFT data: [0.98861313 0.00405996 0.00527203 0.00970745 0.0127806  0.03747452
 0.05264134 0.02938135 0.0189143  0.02288607]
FFT max value:  0.9886131286621094
FFT result: [259411.            -0.j           -736.2249763   +447.79455155j
   -807.77682732  +996.64275809j  -1392.75785217 +1893.07426144j
  -1578.54125986 +3968.1736517j    -531.62002487+10456.14925378j
   3079.24728492 -9764.78184464j  -2633.51543517 -7173.88405137j
   1036.87065086 -4295.54340412j   2347.80102596 -2927.09220684j]
Scaled FFT data: [0.98957443 0.00328717 0.00489383 0.00896535 0.01629112 0.03993856
 0.03905787 0.02915188 0.01685682 0.01431403]
FFT max value:  0.9895744323730469
FFT result: [ 2.60429000e+05-0.00000000e+00j  3.41807755e+02+1.44032065e+00j
  3.65972625e+02-1.00934295e+02j  1.99752000e+02-3.18183525e+02j
  6.38840407e+02+1.69489471e+02j -4.39205486e+03-1.43940023e+03j
 -1.32905659e+04-1.16747241e+04j  1.27824935e+03+4.06302591e+03j
 -1.99573409e+02-4.31481375e+03j -1.28847938e+03+5.15627542e+03j]
Scaled FFT data: [0.99345779 0.0013039  0.0014482  0.00143314 0.00252129 0.01763117
 0.06748223 0.01624815 0.01647731 0.02027445]
FFT max value:  0.9934577941894531

频率应该与时域图一起更新,但这是result

python signal-processing
1个回答
1
投票

也许一切都在按预期进行。我确信的是,您有非常大的 0 频率(直流分量)值,并且您正在将绘图缩放到它。

您可以为此做几件事:

  • 删除信号的平均值
  • 将 fft 的第一个值归零,即前面提到的直流分量
  • 不要绘制(也不缩放)fft的第一个值
© www.soinside.com 2019 - 2024. All rights reserved.