본문 바로가기
Python

Visualize STFT

by YJHTPII 2024. 11. 27.
반응형

fft_size가 frame_size( = 25) 이상인 가장 작은 2제곱 값

따라서 fft_size는 32

frame_shift = 10

 

 

 

# -*- coding: utf-8 -*-

import wave
import numpy as np
import matplotlib.pyplot as plt

if __name__ == "__main__":
    wav_file = './data/wav/xxx.wav'

    frame_size = 25
    frame_shift = 10

    out_plot = './spectrogram.png'

    with wave.open(wav_file) as wav:
        sample_frequency = wav.getframerate()
        num_samples = wav.getnframes()
        waveform = wav.readframes(num_samples)
        waveform = np.frombuffer(waveform, dtype=np.int16)

    frame_size = int(sample_frequency \
                     * frame_size * 0.001)

    frame_shift = int(sample_frequency * frame_shift * 0.001)

    fft_size = 1
    while fft_size < frame_size:
        fft_size *= 2

    num_frames = (num_samples - frame_size) // frame_shift + 1
    spectrogram = np.zeros((num_frames, int(fft_size/2)+1))

    for frame_idx in range(num_frames):
        start_index = frame_idx * frame_shift
        frame = waveform[start_index : \
                         start_index + frame_size].copy()
        frame = frame * np.hamming(frame_size)      
        spectrum = np.fft.fft(frame, n=fft_size)
        absolute = np.abs(spectrum)
        absolute = absolute[:int(fft_size/2) + 1]
        log_absolute = np.log(absolute + 1E-7)
        spectrogram[frame_idx, :] = log_absolute

    plt.figure(figsize=(10,10))
    plt.subplot(2, 1, 1)
    time_axis = np.arange(num_samples) / sample_frequency    
    plt.plot(time_axis, waveform)
    plt.title('waveform')
    plt.xlabel('Time [sec]')
    plt.ylabel('Value')
    plt.xlim([0, num_samples / sample_frequency])
    plt.subplot(2, 1, 2)
    spectrogram -= np.max(spectrogram)
    vmax = np.abs(np.min(spectrogram)) * 0.0
    vmin = - np.abs(np.min(spectrogram)) * 0.7

    plt.imshow(spectrogram.T[-1::-1,:], 
               extent=[0, num_samples / sample_frequency, 
                       0, sample_frequency / 2],
               cmap = 'gray',
               vmax = vmax,
               vmin = vmin,
               aspect = 'auto')

    plt.title('spectrogram')
    plt.xlabel('Time [sec]')
    plt.ylabel('Frequency [Hz]')

    plt.savefig(out_plot)

 

컬러맵 종류

  1. 연속적인(Sequential) 컬러맵:
  • 'viridis': 파이썬 데이터 시각화에서 가장 인기 있는 컬러맵
  • 'plasma': 밝은 노란색부터 진한 자주색까지 색상 변화
  • 'inferno': 어두운 보라에서 밝은 노란색으로 변화
  • 'magma': 검은색에서 밝은 핑크/자주색으로 변화
  1. 발산형(Diverging) 컬러맵:
  • 'coolwarm': 파란색에서 빨간색으로 변화
  • 'RdBu': 빨간색-파란색 조합
  • 'seismic': 지진학에서 많이 사용되는 컬러맵

 

 

FFT 이전에 프레임별로 해밍 윈도우 함수를 적용(windowing)하지 않는다고 가정(아래 코드 참조)

#frame = frame * np.hamming(frame_size)

 

FFT 시작과 끝부분의 불연속으로 인해 발생하는 노이즈 영향 때문에 흐리게 출력됨(아래 그림 참조)

반응형

'Python' 카테고리의 다른 글

Introducing Positron (data science)  (0) 2024.12.10
Visualize FFT  (0) 2024.11.25
Visualize Speech Wave  (0) 2024.11.25
Python Task Scheduler  (0) 2024.11.20
[Python]파이썬 출력 화면 지우기  (0) 2024.05.10

댓글