Monday, November 17, 2025

Mengurai Error Instrumentasi: Solusi Cerdas Saat Indikasi Dipertanyakan

 

Mengurai Error Instrumentasi: Solusi Cerdas Saat Indikasi Dipertanyakan

Dalam dunia instrumentasi, istilah error adalah sesuatu yang nyaris tidak pernah lepas dari pekerjaan kita. Error berhubungan langsung dengan seberapa dapat dipercaya sebuah indikasi yang disajikan kepada pengguna—baik itu operator, engineer, maupun sistem kontrol.

Sering kali, meskipun kita merasa alat atau sensor bekerja dengan baik, tetap saja muncul tuduhan “indikasi salah” dari pihak operasional. Situasi seperti ini umum terjadi, dan di sinilah pemahaman tentang jenis-jenis error menjadi sangat penting.

Dengan menganalisis error secara benar dan menggabungkannya dengan pemahaman proses, kita dapat menjelaskan apa yang sebenarnya terjadi, melakukan cross-check antar sensor, dan memastikan bahwa alat yang kita pasang memang akurat. Tujuannya bukan untuk berdebat atau mencari siapa yang salah, tetapi untuk menemukan solusi teknis yang tepat atas permasalahan yang dihadapi di lapangan.

saya beri contoh environment error yang mudah – mudahan sudah tidak terjadi dengan modul – modul dijaman sekarang, thermocouple adalah salah satu sensor temperatur paling populer karena ketahanannya, harga yang terjangkau, dan kemampuannya bekerja di temperatur tinggi. Namun, di balik keunggulannya, thermocouple juga memiliki satu kelemahan mendasar: sensor ini sangat sensitif terhadap lingkungan, terutama pada area tempat sambungan kabel berada. Salah satu masalah yang paling sering terjadi adalah environmental error yang muncul akibat kondisi temperatur ruangan yang tidak sesuai, seperti ketika AC di CCR atau panel room mengalami kerusakan.

Kasus seperti ini dapat menyebabkan pembacaan thermocouple meleset cukup besar, bahkan mencapai ±30°C atau lebih. Hal ini bukan kejadian langka—justru sangat sering terjadi pada plant industri yang menggunakan thermocouple dan kabel kompensasi jarak jauh menuju ruang kontrol. Penyebab utamanya adalah gangguan pada Cold Junction Compensation (CJC), yaitu titik referensi temperatur yang berada di ujung kabel kompensasi, biasanya di dalam modul analog input DCS atau panel marshalling. Jika ruangan tempat CJC berada menjadi panas—misalnya karena AC rusak dan suhu ruangan naik hingga 30–40°C—maka kompensasi tidak lagi akurat dan seluruh pembacaan sensor akan bergeser.

Pergeseran ini sangat masuk akal secara teknis. Thermocouple bekerja berdasarkan perbedaan tegangan akibat perbedaan temperatur antara hot junction di lapangan dan cold junction di panel. Ketika temperatur cold junction meningkat secara signifikan, sistem DCS menghitung kompensasi yang salah, sehingga seluruh sinyal temperatur terlihat lebih tinggi atau lebih rendah dari nilai sebenarnya. Jika banyak loop thermocouple mengalami error yang mirip pada waktu yang sama, ini adalah indikasi kuat bahwa masalah bukan pada sensornya, melainkan pada kondisi lingkungan di CCR.

Selain itu, penggunaan kabel kompensasi juga berkontribusi terhadap sensitivitas ini. Kabel kompensasi dirancang hanya untuk mentransmisikan karakteristik tegangan thermocouple pada kondisi temperatur yang stabil. Jika kabel melewati area panas atau banyak sambungan berada di tempat yang suhunya berubah-ubah, pembacaan akan semakin melenceng. Kombinasi antara kabel panjang, junction box panas, dan ruangan CCR yang overheat menjadikan offset pembacaan ±30°C bukan hanya mungkin, tetapi sangat wajar terjadi.

Kasus seperti ini merupakan contoh klasik environmental error, salah satu jenis error yang sering terjadi pada instalasi instrumentasi namun sering kali diabaikan. Kesalahan ini tidak berasal dari sensor, tidak berasal dari proses, dan bukan pula kegagalan perangkat keras, melainkan dipicu oleh kondisi lingkungan yang tidak ideal. Oleh karena itu, memastikan suhu ruangan kontrol tetap stabil—biasanya sekitar 20–25°C—adalah bagian penting dari menjaga akurasi sensor thermocouple.

Pada akhirnya, memahami prinsip kerja thermocouple dan mengenali sumber kesalahan seperti environmental error dapat membantu tim instrumentasi menjelaskan masalah ini secara teknis kepada pihak operasional. Pendekatan ini bukan untuk mencari siapa yang salah, tetapi untuk memastikan akurasi alat, mempercepat pemecahan masalah, dan menjaga keandalan proses secara keseluruhan. Dengan analisis yang tepat, error pembacaan dapat dikoreksi, lingkungan diperbaiki, dan sistem kembali memberikan indikasi yang akurat seperti seharusnya.

 


1. Error Berdasarkan Sumber Terjadinya

Ini adalah klasifikasi terpenting karena memberi gambaran mengapa suatu kesalahan muncul.

a. Systematic Error – Kesalahan yang Terprediksi

Systematic error adalah kesalahan yang muncul secara konsisten dan memiliki pola. Artinya, jika Anda melakukan pengukuran berulang, nilai yang salah itu akan terus muncul dalam arah yang sama.

Penyebabnya antara lain:

  • Instrumental error → alat tidak terkalibrasi, ada zero offset, non-linearity.
  • Environmental error → suhu ruangan, kelembaban, radiasi, dan getaran memengaruhi alat ukur.
  • Observational error → paralaks, kesalahan membaca skala, keterlambatan respon operator.

Karena sifatnya yang dapat diprediksi, systematic error biasanya bisa diperbaiki dengan kalibrasi atau metode pengukuran yang lebih baik.


b. Random Error – Kesalahan Acak Tanpa Pola

Tidak seperti systematic error, random error bersifat acak dan muncul karena fluktuasi kecil yang tidak bisa dikendalikan.

Contoh:

  • noise elektronik,
  • gangguan mekanis mikro,
  • variasi kecil respon sensor,
  • ketidakkonsistenan operator.

Random error dianalisis menggunakan statistik, seperti standar deviasi, variansi, atau analisis rata-rata. Walaupun tidak bisa dihilangkan sepenuhnya, error jenis ini dapat dikurangi dengan melakukan pengukuran berulang.


c. Gross Error/Human error – Kesalahan Besar karena Manusia

Gross error adalah kesalahan paling mudah dikenali: muncul karena kelalaian manusia.

Contoh:

  • salah membaca angka (misalnya 3.5 dibaca 3.8),
  • salah memasang kabel instrumen,
  • menulis data yang tidak sesuai,
  • salah memilih mode pada alat ukur.

Jenis error ini dapat dihindari dengan prosedur yang lebih teliti, pelatihan operator, dan sistem verifikasi data.


2. Error Berdasarkan Perbandingan dengan Nilai Sebenarnya

Ini adalah cara paling umum digunakan untuk mengukur tingkat ketidaktepatan hasil pengukuran.



Tiga jenis error ini penting digunakan dalam laporan laboratorium, troubleshooting instrumen, dan validasi sensor.


3. Error Berdasarkan Perilaku Alat Ukur

Jenis error ini berkaitan langsung dengan karakter fisik alat ukur. Penting dipahami terutama pada dunia instrumentasi dan kontrol.

a. Zero Error

Terjadi ketika alat tidak menunjukkan angka nol saat tidak ada input.
Contoh: multimeter analog yang jarumnya tidak tepat di posisi 0.

b. Span Error

Kesalahan ketika alat tidak memberikan pembacaan yang benar pada nilai penuhnya (full-scale).

c. Linearity Error

Ketika grafik input–output alat tidak mengikuti garis lurus ideal. Ini sering terjadi pada sensor tekanan, sensor suhu, strain gauge, dan lain-lain.

d. Hysteresis Error

Alat memberikan nilai yang berbeda untuk input yang sama ketika kondisi meningkat (rising) dan menurun (falling).
Sering terjadi pada sistem mekanis dan sensor berbasis logam.

e. Drift

Kesalahan yang muncul secara perlahan seiring waktu karena:

  • umur komponen,
  • perubahan suhu,
  • kelembaban,
  • penuaan elektronik.

f. Dead Zone (Threshold Error)

Rentang kecil di mana perubahan input tidak terdeteksi oleh alat.
Contoh: joystick lama yang sedikit digerakkan tapi tidak terdeteksi oleh sistem.

g. Resolution Error

Kesalahan yang muncul karena keterbatasan kemampuan alat untuk membedakan perubahan kecil nilai input.
Misalnya termometer digital dengan resolusi 0.1°C tidak bisa membaca perubahan 0.02°C.


Kesimpulan: Error Adalah Kawan, Bukan Lawan

Setiap alat ukur memiliki keterbatasan—dan memahami berbagai jenis error membantu kita:

  • memilih instrumen yang tepat,
  • meningkatkan akurasi,
  • memperbaiki metode pengukuran,
  • membuat keputusan teknik yang lebih baik.

Dengan mengenali sumber error, karakter error, dan cara menghitungnya, Anda akan mampu membuat data yang lebih akurat, terpercaya, dan siap dipakai untuk analisis profesional.

READ MORE

Tuesday, November 11, 2025

Sinkronisasi Generator: Menyatukan Irama Dua Jantung Listrik

 

Sinkronisasi Generator: Menyatukan Irama Dua Jantung Listrik

Dalam dunia pembangkitan listrik, sinkronisasi generator adalah momen krusial — proses ketika generator dihubungkan ke sistem tenaga (grid) yang sudah beroperasi.
Sedikit saja kesalahan dalam tahap ini bisa berakibat fatal: dari lonjakan arus hingga kerusakan mekanik pada generator.

Sebelum membahas apa yang bisa salah, mari kita pahami dulu apa yang terjadi jika semuanya berjalan sempurna.

Syarat Utama Sinkronisasi Generator

Agar generator dapat tersinkron dengan baik, harus dipenuhi tiga syarat utama:

1.      Tegangan sama (|V|)

2.      Frekuensi sama (f)

3.      Sudut fasa sama (φ)

Kadang ditambahkan satu lagi, yaitu urutan fasa sama (R–S–T), yang biasanya dicek sekali saja di awal proyek karena sifatnya tetap.

Ketika ketiga syarat utama terpenuhi, tidak ada beda potensial antara terminal generator dan jaringan.
Akibatnya:

·         Arus yang mengalir hampir nol,

·         Tidak terjadi hentakan mekanik atau lonjakan arus,

·         Generator langsung menyatu dengan sistem dan berbagi daya sesuai torsi penggeraknya.

Dengan kata lain, medan magnet generator terkunci secara halus pada medan magnet jaringan — inilah kondisi sinkron sempurna.

Dulu, proses sinkronisasi dilakukan secara manual menggunakan indikator lampu.
Ketika lampu-lampu padam bersamaan, artinya tidak ada beda potensial — operator pun menutup breaker dengan cepat.
Cara sederhana ini mengajarkan prinsip penting:

Lampu padam = sinkron sempurna.


Rangkaian simulasi


Apa yang Terjadi Jika Syarat Sinkron Tidak Terpenuhi?

Setiap penyimpangan dari syarat sinkronisasi ideal menimbulkan dampak berbeda pada generator maupun sistem.

1. Tegangan Tidak Sama

Ketika tegangan generator sedikit meleset dari tegangan sistem, bentuk gelombangnya masih seirama — frekuensi dan fasanya sama, tetapi amplitudonya berbeda.
Akibatnya muncul beda potensial sesaat saat breaker ditutup, menimbulkan arus sirkulasi singkat di antara keduanya.

Arus ini tetap berbentuk sinus, namun dapat cukup besar untuk menimbulkan hentakan torsi kecil pada rotor atau pemanasan lokal di stator bila selisihnya berlebihan.

Efek utama:

·         Pemanasan lokal pada stator,

·         Getaran torsi sesaat (terutama jika ΔV > 5%),

·         Ketidakseimbangan beban antar fasa jika AVR tidak stabil.

Toleransi yang diizinkan:

·         Maksimum ±10%,

·         Disarankan ±5% atau kurang untuk operasi aman.

Standar rujukan:

·         IEEE Std 1547 & IEEE C50.12 → ≤10% dari tegangan nominal,

·         IEC 60034-3 & panduan PLN → ±5% untuk sistem paralel generator-grid.

Walau di osiloskop gelombangnya tampak hampir sama, perbedaan kecil di puncak tegangan bisa menjadi sentuhan halus yang menentukan apakah sinkronisasi berjalan mulus atau menimbulkan kejutan sesaat.

Tegangan Berbeda


2. Frekuensi Tidak Sama

Ketika frekuensi generator tidak identik dengan frekuensi sistem, dua gelombang tidak lagi seirama — satu berlari lebih cepat atau lebih lambat.
Pada osiloskop, puncaknya tampak tergeser perlahan, membentuk pola “beat” atau ayunan amplitudo.

Jika breaker ditutup dalam kondisi ini, perbedaan frekuensi menyebabkan sudut fasa terus berubah, memicu arus dan torsi osilasi yang berulang.
Akibatnya, rotor bergetar karena terus “dikejar” oleh medan magnet sistem.

Efek utama:

·         Getaran mekanik periodik pada rotor,

·         Peningkatan arus transien di stator,

·         Risiko kerusakan kopling atau rotor lepas sinkron jika selisih besar.

Toleransi yang diizinkan:

·         Maksimum ±0,1 Hz,

·         Ideal ±0,05 Hz untuk sistem besar atau sinkronisasi otomatis.

Standar rujukan:

·         IEEE Std 1547 dan ANSI C50.12 → deviasi ≤0,1 Hz,

·         IEC 60034-3 → batas yang sama untuk menjaga torsi sinkronisasi tetap aman.

Frekuensi Berbeda


Jadi, jika generator sedikit saja berlari lebih cepat atau lambat, medan magnetnya akan “mengejar” atau “tertinggal”, menimbulkan hentakan periodik yang bisa berujung pada gangguan mekanis.
Sinkronisasi sempurna artinya dua gelombang bernapas dalam satu ritme — tidak lebih cepat, tidak lebih lambat.

3. Sudut Fasa Tidak Sama

Bila sudut fasa generator berbeda dengan sistem, tegangan dan frekuensinya sama, tetapi puncak gelombangnya bergeser — satu mendahului atau tertinggal beberapa derajat listrik.
Saat breaker ditutup, muncul impuls arus dan torsi sinkronisasi akibat perbedaan energi sesaat antara kedua medan magnet.

Jika perbedaan kecil (<10°), proses masih halus.
Namun bila sudut fasa melewati 20–30°, hentakan mekaniknya menjadi kuat.
Dan bila di atas 45°, lonjakan arus dapat merusak breaker atau membuat rotor kehilangan sinkron.

Efek utama:

·         Hentakan mekanik pada poros dan kopling,

·         Lonjakan arus singkat di stator,

·         Osilasi torsi sebelum sistem stabil kembali.

Toleransi yang diizinkan:

·         Maksimum ±10°,

·         Ideal ±5° atau kurang untuk sistem otomatis besar.

Standar rujukan:

·         IEEE C50.12 & IEC 60034-3 → batas sekitar ±10°,

·         Praktik PLN → breaker ditutup saat lampu sinkron padam atau redup (beda fasa ≈ 0°).

Sudut fasa berbeda

Melihat simulasi lengkapnya :

                    


Simulasi ini dibuat menggunakan multisim, file projectnya bisa di download disini 


Sinkronisasi bisa diibaratkan menyatukan dua jantung listrik.

Jika denyutnya tidak seirama, satu akan memaksa yang lain mengikuti — dan hentakannya bisa terasa sangat keras.

Sinkronisasi generator bukan sekadar menyalakan lampu indikator atau menekan tombol “connect”.
Ia adalah tari presisi antara tegangan, frekuensi, dan sudut fasa.
Ketika ketiganya selaras, energi berpadu lembut tanpa benturan; tetapi jika salah satu meleset, sistem akan merespons dengan hentakan.

Maka, setiap keberhasilan sinkronisasi bukan hanya hasil dari teknologi, tapi juga ketepatan, kesabaran, dan rasa irama listrik
karena pada akhirnya, dua sumber daya hanya bisa bekerja bersama jika berdenyut dalam harmoni yang sama.

 



READ MORE

Sunday, November 2, 2025

Langkah-Langkah Praktis Menentukan Kapasitor Koreksi Faktor Daya Berdasarkan Daya Aktif dan Tegangan

Langkah-Langkah Praktis Menentukan Kapasitor Koreksi Faktor Daya Berdasarkan Daya Aktif dan Tegangan

[catatan pribadi] 

Pemasangan kapasitor untuk perbaikan kualitas daya merupakan langkah penting dalam sistem kelistrikan industri maupun komersial, terutama untuk meningkatkan faktor daya (cos φ) agar mendekati nilai ideal, yaitu 1. Dengan memperbaiki cos φ, energi listrik dapat digunakan lebih efisien, rugi daya berkurang, dan biaya akibat penalti dari PLN bisa dihindari. Dalam wawancara kerja, pertanyaan seperti “Apa fungsi kapasitor dalam panel listrik?” atau “Bagaimana hubungan antara kapasitor dan power factor?” sering diajukan untuk menguji pemahaman teknis kandidat. Pada pembahasan ini, kita tidak hanya akan memahami konsep perbaikan faktor daya, tetapi juga akan membahas cara menghitung kapasitas kapasitor yang dibutuhkan untuk mencapai cos φ yang diinginkan secara praktis dan akurat.

 

Untuk menghitung kita membutuhkan beberapa hal,

1.       Daya aktif  (KW)

2.       Factor daya awal (cosθ1)

3.       Factor daya target (cosθ2)  biasa target 0.9 – 0.95

 

Step 1 Hitung kebutuhan daya reaktif kompensasi (Qc)

Untuk menaikkan factor daya dari cosθ1 ke cosθ2 menggunakan rumus :

                


Dengan:

                


Dengan Qc = KVAR

 

Dalam rangkaian AC, kapasitor tidak menyerap daya nyata (P), tetapi menyimpan dan melepaskan energi — inilah yang disebut daya reaktif (Q).



Untuk Sistem 3 fasa, gunakan tegangan fasa = tegangan line/3 jika capasitor dipasa per-fasa delta, kalua hubung star hanya perlu memasukkan nilai tegangan line.

🔹 Contoh Perhitungan

Diketahui:

·         Daya aktif (P) = 900 W

·         cos φ₁ = 0.75 (faktor daya awal)

·         cos φ₂ = 0.95 (faktor daya yang diinginkan)

·         Tegangan = 220 V

·         Frekuensi = 50 Hz




Untuk Tegangan 3 fasa contoh perhitungannya seperti ini :





 


Contoh soal saya create dengan bantuan chatGPT dan ternyata ada hal yang menarik yang saya tidak pernah sadari kalau nilai capasitansi hubung star dan delta bisa di dapat langsung jika sudah menghitung salah satuya dengan nilai perbandingan 1:3. yah pakai AI punya keuntungannya sendiri

 





READ MORE

Thursday, October 30, 2025

[Share] Buku Tua atau lama radioshack dan radio amatir 80 meter

 [Share] Buku Tua atau lama radioshack dan radio amatir 80 meter

silahkan klik di gambar bukunya







READ MORE

Wednesday, October 29, 2025

Simulasi Dinamika Tangki Air dengan Lazarus: Cara Mudah Memahami Sistem Kontrol

 Simulasi Dinamika Tangki Air dengan Lazarus: Cara Mudah Memahami Sistem Kontrol


kita akan membaut sebuah sistem pengisian tanki air, kenapa pilih tanki air karena paling simple perhitungannya dan mudah buatnya dan analisanya. tapi meskipun system ini lambat tapi kita bisa aplikasikan nantinya PID buatan kita sehingga kita tau apakah PID aplikatif dan sekalian belajar karakteristik PID pada system lambat.

jadi mari kita mulai dengan membayangkan sebuah tangki dulu :

Volume tangki

jika dengan luas alas 100cm2 dan tinggi tangki 100cm jadi volume tangki full adalah 10.000cm3 itu yang akan mendasari simulasi kita. 

Dalam dunia kontrol sistem, memahami perilaku sistem dinamik adalah langkah penting sebelum menerapkan algoritma seperti PID.
Pada artikel ini, kita akan membangun dan mensimulasikan sistem pengisian tangki air, sebuah model klasik yang sederhana namun kaya makna.
Meski sistem ini tergolong lambat, justru di situlah tantangannya — kita bisa menguji respons dan kestabilan PID pada kondisi nyata sekaligus memahami karakteristik sistem dengan lebih intuitif.

Desain system tangki




Menetapkan FlowIn / FlowOut — kenapa 100 s untuk mengisi / menguras?

Dalam contoh teks kamu disebutkan: FlowIn dan FlowOut masing-masing 100 cm³/s. Dengan parameter tanki di kode:

  • TankArea = 100.0 cm²

  • TankHeightMax = 100.0 cm

maka volume penuh tangki = TankArea * TankHeightMax = 100 cm² * 100 cm = 10.000 cm³.

Jika laju pengisian bersih (net flow) = 100 cm³/s, waktu untuk mengisi dari kosong ke penuh adalah:

  • waktu = volume / laju = 10.000 cm³ / 100 cm³/s = 100 s.

(Itu yang kamu tulis — aritmetika di atas valid digit-by-digit: 10000 ÷ 100 = 100.)

Jadi pernyataan “mengisi dari kosong membutuhkan 100 detik dan untuk menguras dari full membutuhkan 100 detik” benar asalkan FlowIn = 100 dan FlowOut = 0 untuk kasus isi; atau untuk menguras, FlowOut = 100 dan FlowIn = 0. Jika keduanya aktif, yang relevan adalah net flow = FlowIn − FlowOut.


Hubungan langsung dengan kode (baris penting dan maknanya)

Di kode kamu ada fungsi penting:

NetFlow := FlowRate - flow_out; // Net flow (cm^3/s) Level := Level + (NetFlow / TankArea) * DeltaTime;

Penjelasan langkah-per-langkah:

  1. NetFlow dihitung dalam satuan cm³/s.

  2. NetFlow / TankArea → perubahan tinggi per detik (cm/s), karena cm³/s dibagi cm² → cm/s.

  3. Dikali DeltaTime (detik per step, di kode DeltaTime = 0.1 → 100 ms) → perubahan tinggi per step (cm).

  4. Ditambahkan ke Level untuk mendapatkan tinggi baru.

Dengan kata lain formula update tingkat (Level) di kode sama dengan persamaan kontinuitas sederhana:

Δh=QinQoutAΔt\Delta h = \dfrac{Q_{in} - Q_{out}}{A} \cdot \Delta t

di mana hh = tinggi (cm),


Q
Q
= laju aliran (cm³/s),
A
A
= luas penampang (cm²), Δt\Delta t = durasi step (s).



animasi Lazarus



Gambar diatas adalah simulasi yang sudah saya siapkan untuk menggambarkan volume tangki yang nantinya akan di hitung oleh system. untuk membuat ini saya sudah siapkan videonya pada link ini.

sekarang kita membutuhkan mendesain program di lazarusnya :

Inti desain: kenapa butuh 2 procedure + 2 timer

Desain yang kamu tulis membagi tugas menjadi dua lapis waktu berbeda:

  1. RunSimulationStep (high-rate, mis. tiap 100 ms)

    • Tugas: menghitung dinamika plant secara numerik (perubahan level/volume pada tiap langkah simulasi).

    • Alasan: fisika (perubahan tinggi akibat flow) harus dihitung cukup sering agar simulasi stabil dan numerik akurat. Di kode kamu DeltaTime = 0.1 → 100 ms, dan tmr1 memanggil RunSimulationStep tiap interval itu.

  2. UpdateTank (low-rate / akumulasi, mis. tiap 1 s)

    • Tugas yang kamu maksud: menghitung/menyimpan akumulasi total volume untuk keperluan logging, tampilan yang tidak perlu update tiap-milisekon, atau penyajian nilai per detik.

    • Alasan: operasi UI, penulisan log, atau pembacaan sensor sering cukup tiap 1 s; mempercepat UI tidak memberi manfaat dan malah bisa membuat aplikasi berat. Maka tmr2 dipakai untuk tugas yang lebih lambat (UI / akumulasi) — di desainmu kamu ingin tmr2.Interval := 1000.

Kesimpulan: dua timer ini meng-decouple (memisahkan) perhitungan fisika berkecepatan tinggi dari tugas UI/akumulasi berkecepatan rendah — praktek standar pada simulasi & control realtime.

Dari kode bisa di lihat:

  • tmr1.Interval := round(DeltaTime*1000);tmr1 dipakai untuk memanggil RunSimulationStep (Δt = 0.1 s).
    procedure TForm1.tmr1Timer(Sender: TObject); begin RunSimulationStep; end;

  • RunSimulationStep mengambil nilai trackbar (flow_in := tb1.Position; flow_out := tb2.Position;) lalu memanggil UpdateTank(level_tanki, flow_in); dan mengeset tinggi := round(level_tanki);

  • tmr2Timer saat ini hanya melakukan:

    tinggi := Round(level_tanki); // ambil nilai dari sensor VirtualScreen.RedrawBitmap;

    namun di desain kamu ingin tmr2 menjalankan akumulasi / update per 1 detik (misalnya untuk menambah entri log / menampilkan total volume per detik).

Catatan: di kode UpdateTank sekarang menghitung level tiap kali dipanggil (yaitu saat tmr1 berjalan) — sehingga UpdateTank sesungguhnya adalah update fisika per step, bukan akumulasi per 1 detik.


berikut adalah video aplikasi yang sudah jadi : file project bisa didwonload di






dan berikut adalah listing lengkapnya :

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  ComCtrls, BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Label1: TLabel;
    Label2: TLabel;
    lbl4: TLabel;
    lbl2: TLabel;
    lbl1: TLabel;
    lbl3: TLabel;
    tmr1: TTimer;
    tmr2: TTimer;
    tb1: TTrackBar;
    tb2: TTrackBar;
    VirtualScreen: TBGRAVirtualScreen;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure tb1Change(Sender: TObject);
    procedure tb2Change(Sender: TObject);
    procedure tmr1Timer(Sender: TObject);
    procedure tmr2Timer(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
    procedure VirtualScreenRedraw(Sender: TObject; Bitmap: TBGRABitmap);
  private
    background: TBGRABitmap;
    x0,y0,tebal,lebar,tinggi : integer;
    garis,isian : TBGRAPixel;

    level_tanki, flow_in, flow_out : double;
    level_tanki_old,level_tanki_new : Double;

    procedure RunSimulationStep;
    procedure UpdateTank(var Level: Double; FlowRate: Double);
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

//kalau mau rubah speck simulasi, rubah disini
const
  DeltaTime = 0.1;         // 100 ms
  TankArea = 100.0;        // cm^2
  MaxFlow = 100;         // cm^3/s
  TankHeightMax = 100.0;   // cm
  DeltaT: Single = 0.5;    // 10 ms

{ TForm1 }

procedure TForm1.RunSimulationStep();
begin

  flow_in :=tb1.Position;
  flow_out := tb2.Position;

  // Update plant
  UpdateTank(level_tanki, flow_in);

  //tampilan ke UI
  tinggi := round(level_tanki);

end;

procedure TForm1.UpdateTank(var Level: Double; FlowRate: Double);
var
  NetFlow: Double;
begin

  NetFlow := FlowRate - flow_out;  // Sekarang ada buangan

  Level := Level + (NetFlow / TankArea) * DeltaTime;

  //pengaman simulasi
  if Level > TankHeightMax then
    Level := TankHeightMax
  else if Level < 0 then
    Level := 0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //buat kotak pada gambar
  x0 := 111; y0 := 320; tebal := 2; lebar := 148; tinggi := 217;
  garis := BGRA(0,0,255,128); isian := BGRA(0,0,255,128);
  // load background sekali saja
  background := TBGRABitmap.Create;
  background.LoadFromFile('test.bmp');

  //kondisi awal simulasi
  level_tanki := 0.0;
  level_tanki_old := 0.0;
  level_tanki_new := 0.0;
  tinggi := 0;
  flow_out := tb2.Position;
  tmr1.Interval := round(DeltaTime*1000);
  tb1.Max:= MaxFlow;
  tb2.Max := MaxFlow;

  VirtualScreen.RedrawBitmap;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  tmr1.Enabled:= true;
  tmr2.Enabled:= true;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  tmr1.Enabled:= false;
  tmr2.Enabled:= false;
  tb1.Position:= 0;
  tb2.Position:= 0;

  //kondisi awal simulasi
  level_tanki := 0.0;
  level_tanki_old := 0.0;
  level_tanki_new := 0.0;
  tinggi := 0;
  flow_out := tb2.Position;
  tmr1.Interval := round(DeltaTime*1000);
  tb1.Max:= MaxFlow;
  tb2.Max := MaxFlow;

  VirtualScreen.RedrawBitmap;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  tmr1.Enabled:= false;
  tmr2.Enabled:= false;
end;

procedure TForm1.tb1Change(Sender: TObject);
begin
  lbl1.Caption:= inttostr(tb1.Position);
  lbl3.Caption:= inttostr(tb1.Position);
end;

procedure TForm1.tb2Change(Sender: TObject);
begin
  lbl2.Caption:= inttostr(tb2.Position);
  lbl4.Caption:= inttostr(tb2.Position);
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  RunSimulationStep;
end;

procedure TForm1.tmr2Timer(Sender: TObject);
begin
  tinggi := Round(level_tanki); // ambil nilai dari sensor
  VirtualScreen.RedrawBitmap;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
end;

procedure TForm1.VirtualScreenRedraw(Sender: TObject; Bitmap: TBGRABitmap);
var
  imgRatio, scrRatio: Double;
  drawWidth, drawHeight, xOff, yOff: Integer;
begin
  // hitung aspect ratio
  imgRatio := background.Width / background.Height;
  scrRatio := Bitmap.Width / Bitmap.Height;

  if imgRatio > scrRatio then
  begin
    // gambar lebih lebar daripada layar → sesuaikan lebar penuh
    drawWidth := Bitmap.Width;
    drawHeight := Round(drawWidth / imgRatio);
    xOff := 0;
    yOff := (Bitmap.Height - drawHeight) div 2;
  end
  else
  begin
    // gambar lebih tinggi daripada layar → sesuaikan tinggi penuh
    drawHeight := Bitmap.Height;
    drawWidth := Round(drawHeight * imgRatio);
    yOff := 0;
    xOff := (Bitmap.Width - drawWidth) div 2;
  end;

  // gambar background dengan stretch proporsional-- jangan lupa urutan menggambarnya
  Bitmap.StretchPutImage(Rect(xOff, yOff, xOff+drawWidth, yOff+drawHeight), background, dmSet);

  //gambar object kotaknya-- jangan lupa urutan menggambarnya
  Bitmap.RectangleAntialias(x0,y0,x0+lebar,y0-tinggi,garis,tebal,isian);
end;

end.


READ MORE