Sunday, March 30, 2014

Memfilter Sinyal Suara Pada Range Frekuensi Tertentu (Bandpass) dengan Matlab / Octave + Python

Buka - buka file lama di folder kuliah S1 Teknik Fisika, saya menemukan file script matlab yang saat itu dimintai tolong seorang teman untuk mengerjakan Tugas Akhirnya. Script ini untuk memfilter sinyal (suara) pada frekuensi tertentu dengan menggunakan bandpass filter, yakni gabungan antara low pass filter dan high-pass filter.

Misalnya kita mempunyai sinyal suara dengan frekuensi 0 - 20000 Hz, namun karena suatu hal (misalnya noise) kita cuma butuh sinyal di frekuensi 700 - 1400 Hz saja, maka kita bisa menggunakan script matlab / octave ini. Script ini berjalan lancar baik pada Matlab maupun GNU Octave.

Gambar spectrogram di bawah ini membandingkan spectrogram sinyal sebelum difilter dan setelah difilter. Script untuk GNU / Octave ada di bawahnya.

Sinyal Sebelum di filter
Sinyal Setelah di filter

Berikut script kode Octave / Matlab (link Github disini).
  1. % demo program untuk memfilter suara pada range fekuensi oktaf tertentu
  2. % by bagustris bagustris@linuxmail.org
  3. % adopted from somewhere (forget aka lupa)
  4.  
  5. % set general variables
  6. clear all; close all; clc;
  7. sf = 22050; % sample frequency
  8. nf = sf / 2; % nyquist frequency
  9. d = 1.0; % duration, ganti untuk merubah durasi suara
  10. n = sf * d; % number of samples
  11. nh = n / 2; % half number of samples
  12. % set variables for filter
  13. lf = 700; % lowest frequency, ganti dengan batas bawah bandpass
  14. hf = 1400; % highest frequency, ganti dengan batas atas bandpass
  15. lp = lf * d; % ls point in frequency domain
  16. hp = hf * d; % hf point in frequency domain
  17.  
  18. % band pass filter!
  19. filter = zeros(1, n); % initializaiton by 0
  20. filter(1, lp : hp) = 1; % filter design in real number
  21. filter(1, n - hp : n - lp) = 1; % filter design in imaginary number
  22.  
  23. % make noise
  24. rand('state',sum(100 * clock)); % initialize random seed
  25. noise = randn(1, n); % Gausian noise
  26. noise = noise / max(abs(noise)); % -1 to 1 normalization
  27.  
  28. % do filter
  29. s = fft(noise); % FFT
  30. s = s .* filter; % filtering
  31. s = ifft(s); % inverse FFT
  32. s = real(s);
  33.  
  34. %untuk mendengarkan suara asli
  35. sound(noise,sf);
  36. pause(d+0.5);
  37.  
  38. %untuk mendengarkan suara terfilter (bandpass);
  39. sound(s,sf);
  40. pause(d+0.5);
  41.  
  42. %untuk menyimpan file suara dalam format .wav
  43. %ketik perintah berikut dalam command window (tanpa tanda persen%)
  44. % wavwrite(s,sf 'namafile.wav');

Untuk mengecek hasilnya (spectrum yang telah terfilter) bisa menggunakan spectrogram sbb:
figure(1); specgram(noise, 512, sf);
figure(2); specgram(s, 512, sf);

Silakan dicoba. Please note the correctness and accurateness are not guaranteed.

Update 2020/06:
Dengan cara yang serupa, teknik yang sama dapat diterapkan dengan Python Scipy, yakni dengan filter butterworth. Berikut caranya (sumber: stackoverflow).
  1. from scipy.signal import butter, lfilter
  2.  
  3. def butter_bandpass(lowcut, highcut, fs, order=5):
  4. nyq = 0.5 * fs
  5. low = lowcut / nyq
  6. high = highcut / nyq
  7. b, a = butter(order, [low, high], btype='band')
  8. return b, a
  9.  
  10.  
  11. def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
  12. b, a = butter_bandpass(lowcut, highcut, fs, order=order)
  13. y = lfilter(b, a, data)
  14. return y
  15.  
  16.  
  17. def run():
  18. import numpy as np
  19. import matplotlib.pyplot as plt
  20. from scipy.signal import freqz
  21.  
  22. # Sample rate and desired cutoff frequencies (in Hz).
  23. fs = 5000.0
  24. lowcut = 500.0
  25. highcut = 1250.0
  26.  
  27. # Plot the frequency response for a few different orders.
  28. plt.figure(1)
  29. plt.clf()
  30. for order in [3, 6, 9]:
  31. b, a = butter_bandpass(lowcut, highcut, fs, order=order)
  32. w, h = freqz(b, a, worN=2000)
  33. plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)
  34.  
  35. plt.plot([0, 0.5 * fs], [np.sqrt(0.5), np.sqrt(0.5)],
  36. '--', label='sqrt(0.5)')
  37. plt.xlabel('Frequency (Hz)')
  38. plt.ylabel('Gain')
  39. plt.grid(True)
  40. plt.legend(loc='best')
  41.  
  42. # Filter a noisy signal.
  43. T = 0.05
  44. nsamples = int(T * fs)
  45. t = np.linspace(0, T, nsamples, endpoint=False)
  46. a = 0.02
  47. f0 = 600.0
  48. x = 0.1 * np.sin(2 * np.pi * 1.2 * np.sqrt(t))
  49. x += 0.01 * np.cos(2 * np.pi * 312 * t + 0.1)
  50. x += a * np.cos(2 * np.pi * f0 * t + .11)
  51. x += 0.03 * np.cos(2 * np.pi * 2000 * t)
  52. plt.figure(2)
  53. plt.clf()
  54. plt.plot(t, x, label='Noisy signal')
  55.  
  56. y = butter_bandpass_filter(x, lowcut, highcut, fs, order=6)
  57. plt.plot(t, y, label='Filtered signal (%g Hz)' % f0)
  58. plt.xlabel('time (seconds)')
  59. plt.hlines([-a, a], 0, T, linestyles='--')
  60. plt.grid(True)
  61. plt.axis('tight')
  62. plt.legend(loc='upper left')
  63.  
  64. plt.show()
  65.  
  66.  
  67. run()

Hasilnya adalah sebagai berikut.
Waveform sinyal asli (atas/biru) dan setelah terfilter (bawah/oranye)
Spektrum sinyal terfilter dengan beberepa order N yang berbeda; terlihat jeas sinyal terfilter pada frekuensi 600-1250 Hz

Silahkan dicoba!
Related Posts Plugin for WordPress, Blogger...