Dunia teknik penuh dengan besaran yang tersimpan rapi sebagai sepasang bilangan: impedansi rangkaian listrik AC ditulis R + jX (hambatan ditambah reaktansi), titik pada bidang dua dimensi disimpan sebagai koordinat x dan y, dan setiap komponen frekuensi hasil Transformasi Fourier membawa besaran sekaligus sudut fase. Matematika menyatukan pola-pola itu sebagai bilangan kompleks, bilangan berbentuk a + bj dengan bagian real a dan bagian imajiner b. Python punya tipe complex bawaan untuk satu nilai; NumPy membawanya ke level array dengan dtype complex64 dan complex128, sehingga seratus ribu nilai kompleks dapat dihitung sekaligus dengan kecepatan vectorization.
Bab ini mencakup empat hal:
- dua tipe kompleks NumPy dan aturan memilihnya;
- atribut
.realdan.imagbesertanp.conj,np.angle, dannp.abs; - aritmetika dasar array kompleks, termasuk trik rotasi vektor;
np.emath.sqrtsebagai cara menghitung akar bilangan negatif tanpaNaN.
Materi ini menjadi fondasi langsung untuk section Transformasi Fourier, karena output np.fft.fft berupa array complex128. Bab ini juga melengkapi deretan anggota keluarga tipe yang telah kita bahas — dari tipe numerik pada Memilih Tipe Data yang Tepat hingga tipe non-numerik pada Tipe Data String dan Object.
complex64 dan complex128 #
Satu elemen bilangan kompleks menyimpan dua float sekaligus: bagian real dan bagian imajiner. NumPy menyediakan tepat dua tipe kompleks, dan keduanya adalah pasangan tipe float yang sudah kita kenal:
| Tipe | Ukuran per elemen | Bagian real | Bagian imajiner |
|---|---|---|---|
complex64 | 8 byte | float32 | float32 |
complex128 | 16 byte | float64 | float64 |
Tanpa argumen dtype, NumPy memilih complex128 setiap kali list berisi literal seperti 3 + 4j, karena pasangan float64 adalah default presisi ganda:
import numpy as np
z = np.array([3 + 4j, 1 - 2j, -2 + 1j])
print(z.dtype)
z32 = z.astype(np.complex64)
print(z32)
print(z.real)
print(z.imag)Output yang Dihasilkan:
complex128
[ 3.+4.j 1.-2.j -2.+1.j]
[ 3. 1. -2.]
[ 4. -2. 1.]Mari kita bedah:
- Baris 3 (
np.array(...)): list berisi tiga literal Python berakhiranj. Interpreter menafsirkan masing-masing sebagaicomplex, dan NumPy menetapkan dtypecomplex128untuk arraynya. - Baris 5 (
z.astype(np.complex64)): konversi memangkas setiap komponen kefloat32; cetakan array tetap memakai notasi.+jdengan bagian real terlebih dahulu. - Baris 6-7 (
z.realdanz.imag): atribut ini mengembalikan array float yang berisi komponen masing-masing. Keduanya adalah view ke data yang sama (prinsipnya dibahas pada Chapter View vs Copy), sehingga mengubahz.real[0]juga mengubahzitu sendiri.
real, imag, conj, angle, dan abs pada impedansi #
Sebagai kasus pembahasan, kita hitung impedansi tiga rangkaian AC. Impedansi ditulis Z = R + jX, dengan R hambatan (bagian real) dan X reaktansi (bagian imajiner). Dari sebuah Z, kita membaca tiga angka yang lazim dipakai teknisi: besaran impedansi |Z| lewat np.abs, sudut fase lewat np.angle (radian secara default; beri deg=True untuk derajat), dan konjugasi lewat np.conj, yang menukar tanda bagian imajiner.
import numpy as np
R = np.array([12.0, 4.0, 8.0]) # hambatan (ohm)
X = np.array([16.0, -3.0, 6.0]) # reaktansi (ohm)
Z = R + 1j * X # impedansi Z = R + jX
print(np.abs(Z).round(1))
print(np.angle(Z, deg=True).round(1))
print(np.conj(Z))
print((Z * np.conj(Z)).real.round(1))Output yang Dihasilkan:
[20. 5. 10.]
[ 53.1 -36.9 36.9]
[12.-16.j 4. +3.j 8. -6.j]
[400. 25. 100.]Bedah baris demi baris:
- Baris 5 (
R + 1j * X):1j * Xmenghasilkan array yang seluruhnya imajiner, lalu penjumlahan array menggabungkannya denganRmenjadi arraycomplex128. - Baris 6 (
np.abs(Z)): menghitungsqrt(R² + X²)per elemen —20,5, dan10ohm. Inilah besaran yang dibaca multimeter. - Baris 7 (
np.angle(Z, deg=True)): sudut fase tiap rangkaian. Nilai positif menandakan sifat induktif (53.1°), negatif menandakan kapasitif (-36.9°). - Baris 9 (
Z * np.conj(Z)): mengalikanZdengan konjugasinya menghilangkan bagian imajiner, sehingga hasilnya tepat|Z|²—400,25, dan100.
Aritmetika array kompleks dan rotasi vektor #
Operator array kompleks mengikuti aljabar kompleks per elemen. Penjumlahan menjumlahkan real dengan real dan imajiner dengan imajiner; perkalian menerapkan rumus (a + bj)(c + dj) = (ac - bd) + (ad + bc)j pada setiap pasang elemen. Dari rumus itulah muncul trik yang sering dipakai pada grafika dan pengolahan sinyal: mengalikan bilangan kompleks dengan exp(1j·θ) sama dengan memutar titik sebesar θ derajat mengelilingi titik asal.
import numpy as np
titik = np.array([2 + 0j, 1 + 1j]) # dua titik pada bidang
rotor = np.exp(1j * np.deg2rad(90)) # faktor rotasi 90 derajat
hasil = titik * rotor
print(hasil.real.round(4))
print(hasil.imag.round(4))Output yang Dihasilkan:
[ 0. -1.]
[2. 1.]- Baris 3 (
titik = ...): titik(2, 0)dan(1, 1)ditulis sebagai bilangan kompleks. - Baris 4 (
rotor = ...):exp(1j·90°)kira-kira6.1e-17 + 1j— hampir murni imajiner. Sisa real berukuran6.1e-17itu bukan galat program, melainkan konsekuensicos(90°)pada aritmetika biner yang tidak tepat nol. - Baris 5-7 (perkalian dan cetak): setelah pembulatan empat desimal,
2 + 0jmenjadi0 + 2jdan1 + 1jmenjadi-1 + 1j. Kedua titik terputar 90° berlawanan arah jarum jam, persis seperti yang dijanjikan rumus.
emath: akar bilangan negatif tanpa NaN #
Fungsi akar kuadrat standar bekerja pada bilangan real, sehingga np.sqrt(-4) tidak punya jawaban real: NumPy mengembalikan nan dan melempar RuntimeWarning. Keluarga fungsi np.emath (extended math) menawarkan domain otomatis (automatic domain): ketika masukan keluar dari domain real, perhitungan diperluas ke bilangan kompleks tanpa NaN.
import numpy as np
import warnings
with warnings.catch_warnings(record=True) as terekam:
warnings.simplefilter("always")
print(np.sqrt(np.array([-4.0, 9.0])))
print("Peringatan:", terekam[0].message)
print(np.emath.sqrt(np.array([-4.0, 9.0])))
print(np.emath.sqrt(-1))Output yang Dihasilkan:
[nan 3.]
Peringatan: invalid value encountered in sqrt
[0.+2.j 3.+0.j]
1j- Baris 5-8 (blok
with): kita menangkapRuntimeWarningmenjadi objek agar pesannya tercetak sebagai output yang terukur. Hasilnp.sqrtuntuk-4.0berupanan, sedangkan9.0tetap3.0. - Baris 9 (
np.emath.sqrt(...)): masukan negatif otomatis dialihkan ke domain kompleks —-4.0menghasilkan0.+2.j, dan masukan positif tetap riil sebagai3.+0.j. - Baris 10 (
np.emath.sqrt(-1)): akar-1menghasilkan satuan imajiner1j, nilai yang tidak pernah bisa diberikannp.sqrtbiasa.
Dengan tipe kompleks, atribut pemisah komponen, dan emath yang menolak menghasilkan NaN secara diam-diam, kita siap membaca output np.fft.fft pada section Transformasi Fourier. Untuk melengkapi strategi pemilihan tipe pada array data nyata, kembali ke Memilih Tipe Data yang Tepat, dan untuk perbandingan dengan keluarga tipe non-numerik, lanjutkan ke Tipe Data String dan Object.