Rekaman sensor jarang sekali bersih. Sensor getaran pada bantalan mesin pabrik, misalnya, merekam komponen 10 Hz yang kita minati bercampur derau yang menyebar di semua frekuensi. Cara paling terarah menyaringnya adalah di domain frekuensi: sinyal yang dicari terkonsentrasi pada beberapa bin, sedangkan derau terbagi tipis ke seluruh bin.
Pola kerjanya tiga langkah: transformasikan rekaman dengan np.fft.fft, nolkan koefisien pada bin yang tidak diinginkan, lalu kembalikan sinyalnya dengan np.fft.ifft. Sumbu frekuensinya dari np.fft.fftfreq seperti pada fftfreq dan Spektrum Frekuensi, mekanisme inversnya dari Dari DFT ke FFT; yang baru di sini hanya langkah tengahnya — menyunting spektrum sebelum di-invers.
Yang kita kerjakan pada chapter ini:
- Membaca sebaran derau lebar-band pada magnitude spektrum
- Menyaring derau dengan mask low-pass lalu mengembalikan sinyal via
np.fft.ifft - Menakar trade-off ambang batas dan mengenali artefact pemotongan tajam
- Alur yang sama dengan
rfft/irfftuntuk sinyal riil
Membaca Derau di Spektrum #
Kita siapkan rekaman latihan: sinus murni 10 Hz beramplitudo 1 — komponen getaran yang ingin dipertahankan — ditambah derau normal ber-standar deviasi 0.3 dari generator ber-seed 42. Sinyal murninya disimpan terpisah sebagai acuan; RMS selisih terhadap acuan itu menjadi patokan mutu hasil filtering.
import numpy as np
fs = 1000
t = np.arange(1000) / fs
murni = np.sin(2 * np.pi * 10 * t) # komponen yang diinginkan
rng = np.random.default_rng(42)
rekam = murni + rng.normal(0, 0.3, t.size) # rekaman sensor berderau
spec = np.fft.fft(rekam)
mag = np.abs(spec)
print("mag[10] =", mag[10].round(1), "(bin sinyal 10 Hz)")
print("mag[300] =", mag[300].round(1), "(bin derau)")
print("mag[450] =", mag[450].round(1), "(bin derau)")
print("RMS derau:", np.sqrt(np.mean((rekam - murni) ** 2)).round(4))Output yang Dihasilkan:
mag[10] = 500.1 (bin sinyal 10 Hz)
mag[300] = 1.3 (bin derau)
mag[450] = 3.8 (bin derau)
RMS derau: 0.2967Penjelasan blok di atas:
- Baris 4–6:
murnimenjadi acuan penilaian;rekamadalah input yang akan difilter. - Baris 7–10: derau menyebar ke semua bin — bin 10 memuat sinyal dengan magnitude ~500 (skala (N/2) × amplitudo), bin derau hanya 1–4.
- Baris 11: RMS = akar rata-rata kuadrat selisih;
0.2967mendekati standar deviasi derau 0.3 — inilah error yang ingin ditekan.
Komponen yang dicari ratusan kali lebih besar daripada isi bin derau. Derau seperti ini disebut derau lebar-band (broadband noise): energinya tersebar tipis di seluruh bin, sehingga saringan di domain frekuensi sangat cocok untuknya.
Menolkan Bin dan Mengembalikan dengan np.fft.ifft #
Sinyal menumpuk di bin 10 dan cerminnya di bin 990, sedangkan derau tersebar. Ide saringan low-pass: pertahankan hanya bin dengan |freq| ≤ 50 Hz, nolkan sisanya — mengalikan spektrum dengan mask boolean melakukan persis itu. Sebelum menyaring, pastikan rekaman bebas np.nan: satu sampel NaN membuat seluruh koefisien FFT menjadi NaN dan sinyal hasil ikut NaN semuanya — kondisi yang dibahas di NaN dan Infinity.
import numpy as np
fs = 1000
t = np.arange(1000) / fs
murni = np.sin(2 * np.pi * 10 * t)
rng = np.random.default_rng(42)
rekam = murni + rng.normal(0, 0.3, t.size)
spec = np.fft.fft(rekam)
freq = np.fft.fftfreq(t.size, d=1 / fs)
mask = np.abs(freq) <= 50 # low-pass: lewatkan |f| <= 50 Hz
bersih = np.real(np.fft.ifft(spec * mask))
rms_sebelum = np.sqrt(np.mean((rekam - murni) ** 2))
rms_sesudah = np.sqrt(np.mean((bersih - murni) ** 2))
print("RMS sebelum:", rms_sebelum.round(4))
print("RMS sesudah:", rms_sesudah.round(4))Output yang Dihasilkan:
RMS sebelum: 0.2967
RMS sesudah: 0.0982Mari kita bedah bagian pentingnya:
- Baris 9 (
freq = np.fft.fftfreq(t.size, d=1 / fs)): sumbu frekuensi selaras dengan susunan binspec;d = 1/fsmembuat satuannya hertz. - Baris 10 (
mask = np.abs(freq) <= 50): mask boolean atas sumbu frekuensi.np.abskrusial karenafftfreqmemuat frekuensi negatif. - Baris 11 (
bersih = np.real(np.fft.ifft(spec * mask))): perkalian broadcast menolkan 899 bin di luar mask;ifftmengembalikan sinyal, dannp.realmengambil bagiannya yang riil — residu imajiner ~10⁻¹⁶ dibuang, kehati-hatian yang sama seperti pada Dari DFT ke FFT. - Baris 14–15: RMS turun dari
0.2967ke0.0982— error menyusut sekitar tiga kali lipat.
Angka 0.0982 bukan nol karena derau di bawah ambang ikut lolos: dari 1.000 bin, 101 bin berada pada |freq| ≤ 50, dan derau pada bin-bin itu tetap tersimpan dalam sinyal hasil.
Memilih Ambang Batas #
Ambang 50 Hz tadi pilihan, bukan keharusan: ambang kecil menekan lebih banyak derau tetapi berisiko memotong komponen sinyal di dekatnya, ambang besar sebaliknya. Kita uji beberapa nilai pada rekaman yang sama:
import numpy as np
fs = 1000
t = np.arange(1000) / fs
murni = np.sin(2 * np.pi * 10 * t)
rng = np.random.default_rng(42)
rekam = murni + rng.normal(0, 0.3, t.size)
spec = np.fft.fft(rekam)
freq = np.fft.fftfreq(t.size, d=1 / fs)
for ambang in [15, 50, 150, 300]:
bersih = np.real(np.fft.ifft(spec * (np.abs(freq) <= ambang)))
rms = np.sqrt(np.mean((bersih - murni) ** 2))
print(f"ambang {ambang:>3} Hz -> RMS sesudah {rms.round(4)}")Output yang Dihasilkan:
ambang 15 Hz -> RMS sesudah 0.0507
ambang 50 Hz -> RMS sesudah 0.0982
ambang 150 Hz -> RMS sesudah 0.1732
ambang 300 Hz -> RMS sesudah 0.2403Penjelasan blok di atas:
- Baris 8–9:
specdanfreqdihitung sekali di luar loop; yang diulang hanya mask danifft— semua variasi memakai rekaman identik. - Baris 10–11: tiap ambang menghasilkan sinyal bersih yang berbeda, dan RMS-nya dihitung terhadap
murniyang sama. - Baris 12: format
{ambang:>3}meratakan angka ambang ke kanan agar kolomnya lurus.
Polanya: makin kecil ambang, makin banyak bin derau yang dinolkan, makin kecil RMS-nya — 15 Hz paling bersih dan komponen 10 Hz tetap utuh di dalam rentangnya. Namun ambang tidak boleh dipilih dari angka RMS saja; sifat pemotongannya juga menentukan mutu hasil.
Alur yang Sama dengan rfft dan irfft #
Rekaman sensor adalah sinyal riil, jadi setengah spektrum sudah cukup — penghematannya seperti dibahas pada rfft untuk Sinyal Riil. Alur filteringnya identik; yang berubah hanya sumbunya: np.fft.rfftfreq menyediakan frekuensi tak-negatif sehingga mask tidak perlu menangani sisi negatif.
import numpy as np
fs = 1000
t = np.arange(1000) / fs
murni = np.sin(2 * np.pi * 10 * t)
rng = np.random.default_rng(42)
rekam = murni + rng.normal(0, 0.3, t.size)
spek = np.fft.rfft(rekam)
freq_r = np.fft.rfftfreq(t.size, d=1 / fs) # hanya frekuensi >= 0
bersih = np.fft.irfft(spek * (freq_r <= 50), n=t.size)
rms = np.sqrt(np.mean((bersih - murni) ** 2))
print("RMS sesudah (rfft/irfft):", rms.round(4))Output yang Dihasilkan:
RMS sesudah (rfft/irfft): 0.0982Uraian singkatnya:
- Baris 7–8:
rfftmenghasilkan 501 koefisien danrfftfreqmenyediakan sumbunya yang sama panjang — 0 sampai 500 Hz. - Baris 9: mask tinggal satu kondisi positif;
irfftmenyusun sisi cermin secara internal dan mengembalikanfloat64langsung, tanpa perlunp.real. - RMS-nya
0.0982— persis sama dengan alurifftpada ambang 50 Hz karena bin yang dipertahankan sama.
Filter nol-kan-bin ini saringan paling sederhana; aplikasi serius memakai filter digital yang respons frekuensinya dirancang khusus (misalnya lewat modul scipy.signal). Tetapi pola tiga langkahnya — transformasi, sunting spektrum, invers — tetap sama.