Satu simulasi menjawab satu skenario; pertanyaan nyata justru tentang banyak skenario: apa yang terjadi bila laju tumbuhnya berbeda, tanahnya lebih subur, atau semainya lebih besar? Bagian penutup ini menyapu grid 5 x 4 kombinasi parameter, membaca polanya lewat tabel dan heatmap, lalu merangkai seluruh proyek menjadi satu perintah jalankanStudi yang menghasilkan gambar, laporan teks, dan lulus 17 uji otomatis.
Yang kita bangun pada bagian ini:
sweepParameter.m— sweep grid r x K menjadi tiga matriks hasil,- pembacaan hasil — tabel, heatmap, dan siapa mengendalikan apa,
jalankanStudi.m— orkestrasi lengkap sampailaporan.txt,- ide pengembangan untuk melampaui model logistik dasar.
Sweep Grid Parameter #
Sweep adalah dua loop dan tiga matriks. Berikut inti src/sweepParameter.m:
if nargin < 1 || isempty(daftarR)
daftarR = [0.04 0.06 0.08 0.10 0.12];
end
if nargin < 2 || isempty(daftarK)
daftarK = [60 80 100 120];
end
nR = numel(daftarR);
nK = numel(daftarK);
Pakhir = zeros(nR, nK);
T50 = zeros(nR, nK);
LajuMaks = zeros(nR, nK);
params = struct('r', 0.08, 'K', 100, 'P0', 1);
for i = 1:nR
for j = 1:nK
params.r = daftarR(i);
params.K = daftarK(j);
hasil = jalankanSimulasi(params);
Pakhir(i, j) = hasil.P(end);
T50(i, j) = hasil.waktuSetengahK;
laju = diff(hasil.P) ./ diff(hasil.t);
LajuMaks(i, j) = max(laju);
end
end
sweep = struct('r', daftarR(:), 'K', daftarK(:), 'Pakhir', Pakhir, ...
'T50', T50, 'LajuMaks', LajuMaks);Mari kita bedah baris-baris kode di atas:
- Baris 1-6 (grid default): lima nilai r dan empat nilai K dipilih melintasi rentang wajar Bagian 1. Keduanya bisa diganti lewat argumen — sweep ke stuktur yang sama dengan data lain.
- Baris 8-12 (
zeros(nR, nK)): tiga matriks hasil dialokasikan penuh sebelum loop — matriks hasil sweep selalu persegi panjang nR x nK, bentuk yang nanti diuji otomatis. - Baris 15-25 (loop bersarang): baris luar menjalankan r, kolom dalam menjalankan K — 20 simulasi penuh, masing-masing 121 titik.
- Baris 17-19 (
params.r = ...; hasil = jalankanSimulasi(params);): satu structparamsdipakai ulang; cukup dua field ditimpa per kombinasi karenaP0tetap. Determinisme Bagian 2 terbayar di sini: hasil tiap sel bisa dihitung sekali dan dipercaya selamanya. - Baris 20-23 (tiga metrik per sel): P akhir, t50, dan laju maksimum — biomassa akhir, kecepatan, dan intensitas puncak.
- Baris 27-28 (
sweep = struct(...)): hasil dirangkai dengandaftarR(:)dandaftarK(:)sebagai vektor kolom, sehingga orientasi grid selalu jelas bagi pemanggil.
Fungsi ini juga mencetak ringkasannya sendiri — header sejajar kolom karena tiap sel data diformat 7 karakter (' %6.2f') dan header K diformat sama lebar ('%7s'):
Output yang Dihasilkan:
== Sweep parameter: 5 nilai r x 4 nilai K (P0 = 1, 120 hari) ==
P akhir hari ke-120 (satuan biomassa):
K=60 K=80 K=100 K=120
r=0.04 40.39 48.48 55.10 60.63
r=0.06 57.47 75.54 93.12 110.21
r=0.08 59.76 79.57 99.33 119.04
r=0.10 59.98 79.96 99.94 119.91
r=0.12 60.00 80.00 99.99 119.99
Rentang t50: 33.98 sampai 119.48 hari
Rentang laju maks: 0.60 sampai 3.60 per hariMembaca Hasil: Tabel dan Heatmap #
Tabel P akhir di atas dibaca dua arah. Turun satu kolom (K tetap, r naik): nilai menuju batas kolomnya — di K=100, dari 55.10 ke 99.99. Berjalan satu baris (r tetap, K naik): nilai naik hampir sebesar selisih K — di r=0.12, P akhir praktis menyamai K tiap kolom. Kesimpulan pertamanya: K mengendalikan langit-langit, r mengendalikan seberapa dekat langit-langit itu tercapai dalam 120 hari.
Matriks t50 menceritakan bagian waktu:
| t50 (hari) | K=60 | K=80 | K=100 | K=120 |
|---|---|---|---|---|
| r=0.04 | 101.94 | 109.24 | 114.88 | 119.48 |
| r=0.06 | 67.96 | 72.82 | 76.59 | 79.65 |
| r=0.08 | 50.97 | 54.62 | 57.44 | 59.74 |
| r=0.10 | 40.78 | 43.69 | 45.95 | 47.79 |
| r=0.12 | 33.98 | 36.41 | 38.29 | 39.83 |
Barisnya menyusut tajam saat r naik; kolomnya merambat lambat saat K naik. Laju maksimum lebih patuh lagi: seluruh matriksnya persis r*K/4 (0.60 sampai 3.60) — rumus titik belok yang terbukti ulang di 20 sel.
Heatmap Bagian 3 memvisualkan matriks P akhir: kontur nyaris horizontal di wilayah r besar berarti P akhir peka terhadap K, kontur miring rapat di wilayah r kecil menandai daerah transisi tempat r dan K sama-sama berpengaruh. Membaca heatmap sweep berarti membaca arah kontur, bukan warnanya.
Sensitivitas dan Trade-off #
Rumus analitik menjelaskan polanya. Pertama, t50 = ln(K/P0 - 1)/r berbanding balik lurus dengan r: di kolom K=100, menggandakan r dari 0.04 ke 0.08 memangkas t50 dari 114.88 menjadi 57.44 hari. K hanya masuk lewat logaritma — menggandakan K dari 60 ke 120 hanya menambah t50 dari 50.97 ke 59.74 (17 persen). Kedua, P akhir dibatasi K dari atas dan jaraknya ke K menyusut lewat exp(-r*t): baris r=0.04 yang hanya mencapai 67 persen K di kolom 60 (50.5 persen di kolom 120) membuktikan 120 hari belum cukup untuk rem selonggar itu.
| Keputusan | Akibat pada 120 hari | Keterangan |
|---|---|---|
| r besar (0.12), K kecil (60) | jenuh cepat: P(120) = 60.00, t50 = 33.98 | panen awal, laju puncak 1.80/hari |
| r besar, K besar (120) | P(120) = 119.99, t50 = 39.83 | hasil maksimal, tapi laju puncak 3.60/hari — kebutuhan hara/air puncak paling tinggi |
| r kecil (0.04), K besar | P(120) = 60.63 = 50.5% K | kapasitas nganggur: investasi K tidak terbayar dalam musim |
| r sedang (0.08), K=100 | P(120) = 99.33, t50 = 57.44 | titik seimbang proyek ini |
Trade-off praktisnya: laju tinggi membeli waktu dengan mahalnya puncak kebutuhan, sementara kapasitas besar hanya berarti bila r cukup mengejarnya sebelum musim habis. Simulasi memberi angka pada pergulatan itu; keputusan tetap milik petani.
Orkestrasi Lengkap: jalankanStudi.m #
jalankanStudi(dirOutput) menjalankan seluruh alur Bagian 1 sampai 3 — simulasi dasar, analisis fase, tiga gambar, sweep, heatmap — lalu menuang ringkasannya ke laporan.txt. Menulis laporan berarti fprintf dengan file ID:
% ---- 6. laporan.txt ----
namaLaporan = 'laporan.txt';
fid = fopen(fullfile(dirOutput, namaLaporan), 'w');
fprintf(fid, 'LAPORAN STUDI PERTUMBUHAN TANAMAN\n');
fprintf(fid, '================================\n');
fprintf(fid, 'Model : dP/dt = r*P*(1 - P/K)\n');
fprintf(fid, 'Parameter : r = %.2f per hari, K = %g, P0 = %g\n', ...
hasil.params.r, hasil.params.K, hasil.params.P0);Mari kita bedah baris-baris kode di atas:
- Baris 3 (
fid = fopen(..., 'w');): mode'w'membuka berkas baru — laporan lama tertimpa, laporan selalu konsisten dengan kode terbaru. - Baris 4-8 (
fprintf(fid, ...)): polafprintfke file sama dengan ke layar; bedanya hanya argumen pertamafid. Sisa laporan (P(120), t50, durasi fase, ringkasan sweep) mengikuti pola yang sama hinggafclose(fid);.
Bagian penutup fungsi merangkai struct hasil — dengan satu jebakan yang sengaja diberi komentar:
% Perhatian: field berkas diisi lewat penugasan langsung, bukan
% struct(...), karena struct() memecah nilai cell array menjadi
% struct array 1x5 - jebakan klasik fungsi struct().
laporan = struct();
laporan.hasil = hasil;
laporan.fase = fase;
laporan.sweep = sweep;
laporan.berkas = [berkasGambar, {namaHeatmap, namaLaporan}];Mari kita bedah baris-baris kode di atas:
- Baris 1-3 (komentar peringatan):
struct('berkas', C)dengan C berupa cell array 1x5 tidak menghasilkan satu struct berfield cell — melainkan struct array 1x5. Bug ini ditemukan nyata saat uji pertama proyek (kasus “lima berkas tersimpan” gagal) dan diperbaiki dengan penugasan langsung. - Baris 8 (
laporan.berkas = [berkasGambar, ...]): penggabungan cell[cell, {a, b}]menghasilkan satu daftar datar — lima nama berkas yang bisa di-loop pemanggil.
Menjalankan studi penuh dari folder src/:
% driver: jalankan dari folder src/
jalankanStudi('hasil-studi');Output yang Dihasilkan:
== Studi pertumbuhan tanaman (model logistik) ==
Folder output: hasil-studi
Simulasi dasar: r = 0.08/hari, K = 100, P0 = 1, 120 hari
P(120) = 99.3340 (99.33% dari K), t50 = 57.44 hari
Fase eksponensial: 46.85 hari (P < 30)
Fase transisi : 21.19 hari (30 <= P <= 70)
Fase jenuh : 51.97 hari (P > 70)
Laju maksimum : 1.9997 per hari di t = 57.50 (sekitar K/2)
Gambar 1: kurva-pertumbuhan.png - kurva P, garis K dan K/2, t50 = 57.44 hari
Gambar 2: laju-pertumbuhan.png - laju dP/dt, puncak 1.9997 per hari di t = 57.50 hari
Gambar 3: skenario-r.png - perbandingan r = 0.05, 0.08, 0.12 per hari
== Sweep parameter: 5 nilai r x 4 nilai K (P0 = 1, 120 hari) ==
P akhir hari ke-120 (satuan biomassa):
K=60 K=80 K=100 K=120
r=0.04 40.39 48.48 55.10 60.63
r=0.06 57.47 75.54 93.12 110.21
r=0.08 59.76 79.57 99.33 119.04
r=0.10 59.98 79.96 99.94 119.91
r=0.12 60.00 80.00 99.99 119.99
Rentang t50: 33.98 sampai 119.48 hari
Rentang laju maks: 0.60 sampai 3.60 per hari
Heatmap: heatmap-sweep.png - P akhir pada grid r x K
Laporan : laporan.txtLima berkas tersimpan di hasil-studi/, dan laporan.txt berbunyi:
LAPORAN STUDI PERTUMBUHAN TANAMAN
================================
Model : dP/dt = r*P*(1 - P/K)
Parameter : r = 0.08 per hari, K = 100, P0 = 1
Durasi : 120 hari, output setiap hari
P(120) : 99.3340 satuan (99.33% dari K)
t50 : 57.44 hari
Fase eksponensial : 46.85 hari
Fase transisi : 21.19 hari
Fase jenuh : 51.97 hari
Laju maksimum : 1.9997 per hari di t = 57.50
Sweep parameter: 5 nilai r x 4 nilai K
P akhir minimum : 40.39 (r kecil, K kecil)
P akhir maksimum : 119.99 (r besar, K besar)
t50 tercepat : 33.98 hari
t50 terlama : 119.48 hariUji Otomatis Menyeluruh #
tests/uji_simulasi.m membungkus klaim-klaim proyek dalam 17 kasus assert — validasi analitik, monotonitas, konsistensi t50, bentuk sweep, determinisme dua kali berjalan. Empat kasus sweep misalnya:
LULUS: bentuk matriks sweep: 5 baris r x 4 kolom K
LULUS: sweep: P akhir tidak melebihi K tiap kolom
LULUS: sweep: t50 menurun ketika r naik
LULUS: sweep: t50 menaik ketika K naikKelima belas kasus lain ikut lulus hingga baris penutupnya:
Ringkasan: 17 lulus, 0 gagal (total 17)Keluaran uji ditulis ke folder sementara lalu dihapus, sehingga pengujian tidak meninggalkan residu di folder proyek.
Ide Pengembangan #
Model dan infrastrukturnya kini teruji; tiga arah pengembangan paling alami berikutnya:
- Laju musiman — ganti
rkonstan denganr(t) = r0*(1 + a*sin(2*pi*t/periode)). FungsimodelPertumbuhansudah menerimatsejak Bagian 2, jadi model non-otonom ini hanya mengubah isi fungsi, bukan kerangkanya. - Panen berkala — simulasi berhenti sejenak setiap P melewati ambang (misalnya 0.8K), biomassa dipangkas, lalu dilanjutkan dari nilai sisa. Sweep
sweepParametertinggal menerima ambang baru sebagai argumen. - Pertumbuhan stokastik — tambahkan derau pada laju dan jalankan banyak realisasi dengan
rng(42). Determinisme berganti menjadi uji statistik (rata-rata dan sebaran lintas realisasi), dan klaimisequaldua kali berjalan tidak lagi berlaku — kesadaran penting bahwa tiap jenis model menuntut jenis pengujian sendiri.
Proyek lengkap: persamaan sampai laporan otomatis, tiga gambar, heatmap 5 x 4, dan 17 uji penjaganya. Pola perancangan-model, validasi-analitik, visualisasi, dan sweep ini bukan milik botani — ganti persamaannya, dan kerangkanya siap membawa simulasi Anda berikutnya.