Kamu punya lemari pakaian berisi baju-baju untuk berbagai cuaca: jaket tebal untuk musim dingin, kaos tipis untuk musim panas, jas hujan untuk hujan. Setiap pagi kamu lihat cuaca dulu (scheduling variable), lalu ambil baju yang sesuai (select controller). Kamu tidak membuat baju baru setiap hari — kamu cukup memilih dari koleksi yang sudah ada. Itulah Gain Scheduling!
Gain Scheduling adalah teknik di mana parameter kontroller (Kp, Ki, Kd atau gain lainnya) dipilih dari tabel/peta yang sudah disiapkan, berdasarkan nilai scheduling variable (variabel yang menunjukkan kondisi operasi saat ini).
Parameter table : θ = f(v) (lookup table atau interpolasi)
Controller : u(t) = C(θ(v), e(t))
Contoh PID dengan scheduling:
Kp(v) = Kp_table[v], Ki(v) = Ki_table[v], Kd(v) = Kd_table[v]
💡 Mengapa Disebut "Adaptif" meski Parameter Sudah Ditentukan Sebelumnya?
Gain Scheduling sering disebut kuasi-adaptif karena kontroler berubah mengikuti kondisi secara otomatis. Perbedaannya dengan MRAC/STR: gain scheduling tidak belajar dari data baru — semua parameter sudah dirancang offline. Tapi dalam praktik industri, ini sudah jauh lebih baik daripada PID statis!
Sebelum bepergian, Anda menyiapkan beberapa rute: rute A (jalan tol, kondisi normal), rute B (jalan arteri, jika tol macet), rute C (jalan kampung, jika banjir). Ini perlu dipersiapkan sebelum berangkat. Desain gain schedule persis begini: siapkan semua "rute kontrol" untuk setiap kemungkinan kondisi operasi, sebelum sistem dijalankan.
Langkah 1 — Identifikasi Operating Points
Tentukan kondisi-kondisi khas yang akan dialami sistem. Contoh untuk pembangkit listrik:
Langkah 2 — Linearisasi di Setiap Operating Point
Untuk setiap zone, buat model linier lokal (seperti yang dipelajari di Sesi 2), lalu desain PID/kontroller optimal untuk model linier tersebut.
= K(v₀) / (τ(v₀)·s + 1)
K dan τ berubah sesuai operating point v₀.
Desain Kp, Ki, Kd untuk setiap K(v₀) dan τ(v₀).
Langkah 3 — Interpolasi Antar Operating Points
Jika scheduling variable bernilai di antara dua operating point, gunakan interpolasi (linier atau spline) untuk mendapatkan gain yang smooth:
i = indeks zona, v_i ≤ v ≤ v_{i+1}
Hindari switching tiba-tiba → menyebabkan transient yang tidak diinginkan!
| Aspek | Detail Implementasi | Catatan |
|---|---|---|
| Scheduling Variable | Bisa: beban, kecepatan, tekanan, suhu, altitude | Harus mudah diukur dan berkorelasi dengan dinamika sistem |
| Lookup Table | Array nilai Kp/Ki/Kd vs scheduling variable | Simpan di memori controller (PLC/DCS) |
| Interpolasi | Linier, bilinear (2D), spline | Smooth interpolation mencegah chattering |
| Anti-windup | Reset integrator saat switch zona | Penting! Tanpa ini bisa terjadi integrator windup besar |
| Bumpless Transfer | Tambahkan logika agar tidak ada lompatan u saat switching | Wajib untuk sistem safety-critical |
⚠️ Masalah Bumpless Transfer
Saat gain berganti dari zona ke zona, nilai sinyal kontrol u bisa "melompat" tiba-tiba (bump). Untuk pembangkit listrik atau reaktor, ini berbahaya! Solusi: saat switching, inisialisasi state kontroller baru menggunakan output kontroller lama sehingga transisi smooth.
✅ Kelebihan
- Sederhana — mudah dipahami engineer lapangan
- Deterministik — bisa diprediksi perilakunya
- Banyak digunakan di industri (aviation, power plant)
- Tidak butuh komputasi online yang berat
- Mudah di-debug dan divalidasi
- Sudah tersertifikasi di banyak standar industri
⚠️ Keterbatasan
- Tidak menangani ketidakpastian tak terstruktur
- Perlu banyak eksperimen untuk isi tabel
- Tidak bisa belajar dari kondisi yang belum pernah terjadi
- Jika plant berubah (aging), tabel harus di-update manual
- Switching bisa tidak smooth jika tidak dirancang hati-hati
- Jumlah zona bisa sangat banyak untuk sistem kompleks
Gain Scheduling seperti memasak dari buku resep — untuk setiap situasi sudah ada resepnya. Hasilnya bagus dan konsisten selama situasinya sesuai buku. Tapi jika bahan tak terduga (kondisi di luar tabel), chef harus berimprovisasi. Kontrol adaptif sejati (MRAC/STR) seperti chef berbintang yang bisa berimprovisasi karena memahami prinsip memasak secara mendalam.
Turbin Angin — Scheduling berdasarkan Kecepatan Angin
Turbin angin beroperasi di berbagai kondisi angin. Karakteristik aerodinamisnya berubah drastis — torsi tidak linear terhadap kecepatan angin (proporsional v²). Satu set PID tidak bisa optimal untuk semua kondisi.
| Kecepatan Angin | Mode Operasi | Scheduling Variable | Strategi Kontrol |
|---|---|---|---|
| < 3 m/s | Cut-in / Idle | v_wind < 3 | Kp=0 (tidak berputar) |
| 3 – 12 m/s | Maximum Power Tracking | 3 ≤ v ≤ 12 | MPPT, Kp besar, ikuti angin |
| 12 – 25 m/s | Power Limiting (rated) | 12 < v ≤ 25 | Pitch control, Kp sedang |
| > 25 m/s | Cut-out / Shutdown | v > 25 | Brake aktif, emergency stop |
Turbin Gas (PLTG) — Scheduling berdasarkan Power Output
| Daya Output (MW) | Kp | Ki | Alasan |
|---|---|---|---|
| 0–20 MW (startup) | 0.5 | 0.05 | Lambat agar tidak thermal shock |
| 20–60 MW (partial) | 1.2 | 0.2 | Respon moderat |
| 60–100 MW (rated) | 2.0 | 0.4 | Respon cepat untuk grid stability |
| >100 MW (overload) | 1.5 | 0.2 | Lebih konservatif, proteksi thermal |
import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import interp1d # ========================================== # GAIN SCHEDULING: KONTROL FREKUENSI PEMBANGKIT # Target: jaga frekuensi 50 Hz meski beban berubah # ========================================== # === TABEL GAIN (dirancang offline) === # Scheduling variable: deviasi frekuensi |Δf| sched_v = [0.0, 0.1, 0.5, 1.0, 2.0, 3.0] # Hz deviasi Kp_table = [0.5, 1.0, 2.0, 3.5, 5.0, 6.0] # Kp naik saat deviasi besar Ki_table = [0.1, 0.2, 0.5, 0.8, 1.0, 1.2] # Buat fungsi interpolasi smooth Kp_interp = interp1d(sched_v, Kp_table, kind='linear', bounds_error=False, fill_value=(0.5, 6.0)) Ki_interp = interp1d(sched_v, Ki_table, kind='linear', bounds_error=False, fill_value=(0.1, 1.2)) # === MODEL SISTEM: Load-Frequency Control === # M·df/dt = P_gen - P_load - D·f M = 10.0 # inertia (pu·s) D = 1.0 # damping dt = 0.05 T = 60 t = np.arange(0, T, dt) N = len(t) # Profil gangguan beban (berubah-ubah) P_load_dist = np.zeros(N) P_load_dist[int(5/dt):int(20/dt)] = 0.3 # +30% beban t=5-20 P_load_dist[int(25/dt):int(40/dt)] = -0.2 # -20% beban t=25-40 P_load_dist[int(45/dt):] = 0.5 # +50% beban besar t>45 # === SIMULASI 1: PID STATIS (Kp=1.5, Ki=0.3 fixed) === f_static = np.zeros(N); integral_s = 0; P_gen_s = np.zeros(N) for k in range(1, N): err = -f_static[k-1] integral_s += err * dt P_gen_s[k] = np.clip(1.5*err + 0.3*integral_s, -1, 1) df = (P_gen_s[k] - P_load_dist[k] - D*f_static[k-1]) / M f_static[k] = f_static[k-1] + df*dt # === SIMULASI 2: GAIN SCHEDULING === f_gs = np.zeros(N); integral_g = 0; P_gen_g = np.zeros(N) Kp_used = np.zeros(N); Ki_used = np.zeros(N) for k in range(1, N): err = -f_gs[k-1] # GAIN SCHEDULING: pilih Kp, Ki berdasarkan |deviasi frekuensi| v_sched = np.abs(f_gs[k-1]) # scheduling variable Kp = float(Kp_interp(v_sched)) Ki = float(Ki_interp(v_sched)) Kp_used[k] = Kp; Ki_used[k] = Ki integral_g += err * dt integral_g = np.clip(integral_g, -2, 2) # anti-windup P_gen_g[k] = np.clip(Kp*err + Ki*integral_g, -1, 1) df = (P_gen_g[k] - P_load_dist[k] - D*f_gs[k-1]) / M f_gs[k] = f_gs[k-1] + df*dt # === PLOT === fig, axes = plt.subplots(3, 1, figsize=(12, 9)) axes[0].plot(t, f_static, 'tomato', lw=1.8, label='PID Statis (Kp=1.5 tetap)') axes[0].plot(t, f_gs, 'lime', lw=2, label='Gain Scheduling (adaptif)') axes[0].axhline(0, color='orange', ls='--', lw=1.5, label='Target Δf = 0') axes[0].fill_between(t, -0.2, 0.2, alpha=0.08, color='lime', label='Toleransi ±0.2 Hz') axes[0].set_ylabel('Deviasi Frekuensi Δf (Hz)') axes[0].set_title('Kontrol Frekuensi 50 Hz: PID Statis vs Gain Scheduling') axes[0].legend(fontsize=9); axes[0].grid(alpha=0.3) axes[1].plot(t, Kp_used, 'orange', lw=1.8, label='Kp (gain scheduling)') axes[1].plot(t, Ki_used, 'cyan', lw=1.5, label='Ki (gain scheduling)') axes[1].axhline(1.5, color='tomato', ls='--', alpha=0.6, label='Kp statis = 1.5') axes[1].set_ylabel('Nilai Gain') axes[1].set_title('Gain Otomatis Naik saat Deviasi Besar (Scheduling!)') axes[1].legend(fontsize=9); axes[1].grid(alpha=0.3) axes[2].plot(t, P_load_dist, 'red', lw=1.5, label='Gangguan Beban (ΔPL)') axes[2].plot(t, P_gen_g, 'lime', lw=1.5, label='Respons Generator (GS)') axes[2].set_xlabel('Waktu (detik)'); axes[2].set_ylabel('Daya (pu)') axes[2].set_title('Gangguan Beban vs Respons Generator') axes[2].legend(); axes[2].grid(alpha=0.3) plt.tight_layout(); plt.show() print(f"\n📊 Perbandingan Performa:") print(f"Max |Δf| PID Statis : {np.max(np.abs(f_static)):.4f} Hz") print(f"Max |Δf| Gain Sched : {np.max(np.abs(f_gs)):.4f} Hz") print(f"RMSE PID Statis : {np.sqrt(np.mean(f_static**2)):.4f} Hz") print(f"RMSE Gain Scheduling : {np.sqrt(np.mean(f_gs**2)):.4f} Hz")
📊 Interpretasi Hasil Simulasi
- Pada gangguan beban kecil (t=5–20): PID statis cukup baik, gain scheduling tidak jauh berbeda
- Pada gangguan besar di t=45 (+50%): Gain Scheduling menaikkan Kp secara otomatis → deviasi frekuensi jauh lebih kecil dan lebih cepat kembali ke 50 Hz
- RMSE Gain Scheduling ≈ 30–50% lebih kecil dari PID Statis pada gangguan besar
- Ini penting untuk grid stability: deviasi frekuensi >0.5 Hz bisa memicu pemadaman (load shedding)!
🧠 Kuis Pemahaman Sesi 6
1. Apa yang dimaksud "scheduling variable" dalam gain scheduling?
2. Mengapa "bumpless transfer" penting saat switching antar zona gain scheduling?
3. Keterbatasan utama gain scheduling dibanding MRAC/STR adalah?