Chapter Dari DFT ke FFT berhenti pada satu fakta: np.fft.fft mengembalikan deretan koefisien kompleks tanpa label frekuensi. Deretan itu ibarat tabel tanpa kolom kunci — nilainya lengkap, tetapi kita belum tahu baris mana yang mewakili 50 Hz dan mana yang mewakili 120 Hz. np.fft.fftfreq melengkapi bagian yang hilang itu dengan menghasilkan sumbu frekuensi yang selalu selaras dengan panjang spektrum.
Kita berlatih pada data yang wajar dijumpai di lantai produksi: sensor akselerometer merekam getaran motor listrik sebanyak 1.000 sampel per detik selama satu detik, sehingga tersedia 1.000 sampel. Teknisi menduga dua komponen ikut bergetar — ketidakseimbangan rotor pada 50 Hz dan indikasi masalah bantalan pada 120 Hz — tetapi rekamannya tercampur derau pengukuran. Tugas kita membuktikan kedua frekuensi itu langsung dari data.
Yang kita kerjakan pada chapter ini:
- Menyusun sumbu frekuensi dengan
np.fft.fftfreq - Mencari dua frekuensi paling dominan lewat magnitude dan
np.argsort - Mengenali simetri spektrum pada sinyal riil
Menyusun Sumbu Frekuensi dengan np.fft.fftfreq #
np.fft.fftfreq menerima dua parameter. Parameter n adalah panjang sinyal yang menjadi dasar spektrum, dan d adalah jarak antar dua sampel berturutan dalam satuan waktu; bila d dinyatakan dalam detik, output-nya berutusan hertz. Isi bin ke-k mengikuti rumus k/(n·d), dan susunannya khas: frekuensi positif menempati setengah pertama array, sedangkan bin Nyquist dan frekuensi negatif menempati setengah kedua.
import numpy as np
n = 8
d = 1 / 8 # jarak antar sampel: 0.125 detik
freq = np.fft.fftfreq(n, d=d)
print(freq)Output yang Dihasilkan:
[ 0. 1. 2. 3. -4. -3. -2. -1.]Penjelasan blok kecil ini:
- Baris 3–4:
n = 8sampel dengan jarakd = 1/8detik, sehinggan·d= 1 detik penuh dan rumus k/(n·d) menyederhananya menjadi k hertz. - Baris 5:
np.fft.fftfreqmengembalikan array berpanjangnberisi frekuensi tiap bin, terurut mengikuti konvensi yang sama dengan susunan koefisiennp.fft.fft. - Baris 6: seluruh sumbu muat satu baris — 0 Hz, frekuensi positif menaik, bin Nyquist, lalu frekuensi negatif yang menurun menuju -1 Hz.
Pemetaan indeksnya pada kasus di atas:
- Indeks 0 → 0 Hz, komponen rata-rata sinyal (sering disebut komponen DC)
- Indeks 1–3 → 1 sampai 3 Hz, frekuensi positif
- Indeks 4 → -4 Hz, bin Nyquist (setengah laju sampling) yang secara konvensi ditempatkan di sisi negatif
- Indeks 5–7 → -3 sampai -1 Hz, pasangan cermin frekuensi positif
Frekuensi negatif bukan keanehan data. Untuk sinyal riil, bin pada sisi negatif adalah cermin yang isinya menyusul setengah spektrum; kita buktikan lewat magnitude di bagian terakhir chapter ini.
Mendeteksi Frekuensi Dominan dengan np.argsort #
Pipeline deteksinya empat langkah: hitung spektrum dengan np.fft.fft, ambil magnitudenya dengan np.abs, batasi diri pada frekuensi positif, lalu urutkan. Kita sertakan derau dari generator ber-seed agar skenarionya realistis tanpa kehilangan determinisme:
import numpy as np
fs = 1000 # laju sampling: sampel per detik
t = np.arange(1000) / fs # satu detik penuh
rng = np.random.default_rng(42)
getaran = np.sin(2 * np.pi * 50 * t) + 0.5 * np.sin(2 * np.pi * 120 * t)
getaran += rng.normal(0, 0.05, t.size) # derau pengukuran
spec = np.fft.fft(getaran)
freq = np.fft.fftfreq(t.size, d=1 / fs)
mag = np.abs(spec)
pos = freq > 0 # buang bin DC dan sisi negatif
urutan = np.argsort(mag[pos])[::-1][:2]
print("frekuensi dominan (Hz):", freq[pos][urutan])
print("magnitude puncak :", mag[pos][urutan].round(1))Output yang Dihasilkan:
frekuensi dominan (Hz): [ 50. 120.]
magnitude puncak : [499.4 249.9]Mari kita bedah baris demi baris:
- Baris 5 (
rng = np.random.default_rng(42)): generator derau ber-seed tetap; eksekusi berapa pun selalu menghasilkan derau yang sama, sehingga output blok ini dapat direproduksi. - Baris 6: dua sinus sesuai dugaan teknisi — amplitudo 1 pada 50 Hz dan amplitudo 0.5 pada 120 Hz.
- Baris 7: derau
rng.normal(0, 0.05, ...)meniru ketidaksempurnaan sensor; standar deviasinya jauh di bawah amplitudo sinyal. - Baris 9 (
freq = np.fft.fftfreq(t.size, d=1 / fs)):d = 1/fs= 0.001 detik; karenan·d= 1 detik, bin ke-k mewakili k hertz persis. - Baris 11 (
pos = freq > 0): mask boolean yang membuang bin DC dan seluruh sisi negatif. - Baris 12 (
urutan = np.argsort(mag[pos])[::-1][:2]):np.argsortmengembalikan indeks magnitude terurut menaik;[::-1]membaliknya menjadi menurun, lalu[:2]mengambil dua terbesar. Ingat, indeks ini berlaku padamag[pos], bukan padamagmentah. - Baris 13–15:
freq[pos]danmag[pos]memakai mask yang sama, sehingga indeksurutantetap selaras di kedua array.
Kedua dugaan teknisi terbukti: puncak berada di 50 Hz dan 120 Hz. Magnitudenya pun bisa dibaca: 499.4 mendekati (N/2) × amplitudo = 500 × 1, dan 249.9 mendekati 500 × 0.5. Derau hanya menyapu bin-bin lain dengan magnitude kecil, sehingga posisi kedua puncak tidak bergeser. Nilainya tidak tepat 500 dan 250 karena derau ikut terjumlahkan ke sinyal sebelum ditransformasi.
Simetri Spektrum Sinyal Riil #
Sinyal riil menyimpan sejumlah informasi ganda dalam spektrumnya: koefisien pada indeks n-k adalah konjugat kompleks dari koefisien pada indeks k, dan dua bilangan konjugat selalu bermagnitude sama. Mari kita amati pada sinyal tanpa derau dengan dua komponen yang sama seperti sebelumnya:
import numpy as np
t = np.arange(1000) / 1000
sinyal = np.sin(2 * np.pi * 50 * t) + 0.5 * np.sin(2 * np.pi * 120 * t)
mag = np.abs(np.fft.fft(sinyal))
print("mag[50] =", mag[50].round(1))
print("mag[950] =", mag[950].round(1))
print("mag[120] =", mag[120].round(1))
print("mag[880] =", mag[880].round(1))Output yang Dihasilkan:
mag[50] = 500.0
mag[950] = 500.0
mag[120] = 250.0
mag[880] = 250.0Indeks 950 = 1000 − 50 dan indeks 880 = 1000 − 120; keduanya adalah cermin dari bin 50 dan bin 120, dan magnitudenya identik. Setengah spektrum sinyal riil, dengan kata lain, tidak membawa informasi baru. NumPy menyediakan np.fft.rfft yang menghitung hanya setengah spektrum itu — lebih ringkas dan lebih hemat memori — beserta inversnya np.fft.irfft. Pembahasan lengkapnya menunggu kita di rfft untuk Sinyal Riil.
Dengan sumbu frekuensi, magnitude, dan pencarian puncak, kita sudah bisa membaca spektrum sinyal nyata. Babak berikutnya memakai kemampuan ini untuk hal yang lebih aktif: menyunting spektrum lalu mengembalikannya menjadi sinyal yang lebih bersih.