K_ACCUM: Solusi Presisi dan Efisien untuk Drift Akumulator di Modbus Controller
K_ACCUM adalah function block custom untuk mengatasi drift akumulasi dan keterbatasan alamat komunikasi antar controller. Dengan akumulasi tipe data LONG dengan nilai desimal dalam SFLOAT, solusi ini lebih presisi, hemat alamat, dan mudah ditangani.
Photo by Towfiqu barbhuiya / Unsplash
Ditulis oleh Ketut Kumajaya | 25 September 2025
Latar Belakang
Dalam sistem industri berbasis DCS/SCADA, akumulasi data flow adalah fondasi penting untuk perhitungan energi, OEE, hour meter, maupun audit produksi. Supcon menyediakan function block bawaan TOTAL_ACCUM untuk fungsi ini. Namun, ketika block tersebut dijalankan di Modbus controller, muncul masalah serius: drift akumulasi akibat keterbatasan clock internal dan jitter eksekusi.
Selain itu, terdapat keterbatasan komunikasi: hanya tersedia 128 alamat 32‑bit untuk transfer data dari main controller ke Modbus controller. Sinyal analog SFLOAT 12‑bit hanya menempati 16‑bit, sehingga satu alamat 32‑bit dapat menampung dua sinyal. Sebaliknya, satu akumulator penuh menempati seluruh 32‑bit, sehingga konsumsi alamat menjadi dua kali lebih besar. Jika seluruh akumulasi dipusatkan di main controller, alokasi alamat akan cepat habis. Oleh karena itu, diperlukan solusi yang tidak hanya hemat alamat, tetapi juga tetap menjaga presisi.
Tantangan Teknis
- Drift akumulasi:
TOTAL_ACCUMbawaan bergantung pada clock internal Modbus controller yang tidak sinkron dengan main controller. - Keterbatasan alamat komunikasi: hanya tersedia 128 alamat 32‑bit untuk transfer data.
- Perbedaan kebutuhan ruang data: sinyal flow 12‑bit disimpan dalam 16‑bit word, sehingga satu alamat 32‑bit dapat menampung dua sinyal. Sebaliknya, satu akumulator penuh menempati seluruh 32‑bit, membuat konsumsi alamat dua kali lebih besar.
- Kebutuhan auditabilitas: operator membutuhkan hasil akumulasi yang transparan, dapat ditelusuri, dan mudah dipahami lintas shift.
Analisis Akar Masalah
- Drift akumulasi terjadi karena clock internal Modbus controller berbasis 16‑bit tidak disiplin dan tidak sinkron dengan main controller, sehingga perhitungan delta waktu rawan melompat atau melambat.
- Alamat cepat habis disebabkan oleh perbedaan kebutuhan ruang: sinyal analog bisa dipadatkan (2 sinyal per alamat 32‑bit), sedangkan akumulator selalu menghabiskan satu alamat penuh.
- Kurangnya visibilitas audit muncul karena block bawaan
TOTAL_ACCUMtidak mengekspos delta waktu. Operator hanya melihat nilai total, tanpa jejak perhitungan detail.
Solusi: K_ACCUM
Saya merancang function block custom bernama K_ACCUM, dengan fitur utama:
- Clock referensi dari main controller → bebas drift, sinkron lintas device.
- Integrasi wrap‑aware → rollover 16‑bit ditangani aman.
- Proteksi delta & RATE → delta negatif atau terlalu besar diabaikan, RATE anomali difilter.
- Kompatibilitas penuh → menyediakan output FLOAT yang bisa dikonversi ke structAccum menggunakan function block CONVERT_TO_ACCUM
- Audit‑friendly → komentar inline, reserved field dapat digunakan untuk logging delta atau flag anomali.
Diagram Alur (Mermaid)
Detail Teknis
- Rekonstruksi nilai total: akumulasi
accumdanremainder. - Perhitungan delta waktu: wrap‑aware 16‑bit, dengan proteksi >60 detik.
- Integrasi:
AccReal := AccReal + (RATE * DeltaSec)dilakukan dalam FLOAT penuh. - Fragmentasi kembali: meskipun struktur data berbeda dengan structAccum, konversi bisa dilakukan menggunakan block bawaan.
- Konversi ke SFLOAT di tahap akhir: akumulasi dijaga dalam FLOAT untuk presisi maksimum, lalu dipadatkan ke SFLOAT pada bagian akhir.
Catatan Teknis: structKAccum dan Horizon Overflow
Selain presisi integrasi, salah satu aspek penting dari kompatibilitas K_ACCUM adalah bisa dikonversi ke structAccum bawaan Supcon, sehingga tidak ada masalah jika hasilnya ditampilkan ke HMI. Struktur data terdiri dari 2 field:
- accum → long (32‑bit)
- remainder → pecahan (SFLOAT)
Sedangkan struktur structAccum terdiri dari empat field:
- accum1 → low word (16‑bit)
- accum2 → high word (16‑bit)
- remainder → pecahan (SFLOAT)
- reserved → dapat digunakan untuk logging atau flag anomali
Dengan keduanya adalah kombinasi integer 32‑bit dan pecahan SFLOAT, baik structKAccum maupun structAccum memiliki karakteristik unik:
-
Horizon overflow ±136 tahun
Integer 32‑bit mampu menampung hingga 4,29 miliar detik. Overflow baru terjadi setelah lebih dari satu abad operasi kontinu. Praktis, operator tidak perlu melakukan reset manual untuk menghindari overflow. -
Independen dari skala input
Berapapun range engineering unit (misalnya 0–10.000 Nm³/h), sinyal tetap dipadatkan ke SFLOAT 0–1 sebelum diakumulasi, lalu di-back scaling ke unit aslinya. -
Audit‑friendly
Nilai total dapat direkonstruksi dengan cara yang sama lintas block, sehingga konsistensi audit tetap terjaga.
Beralih dari K_ACCUMULATOR ke K_ACCUM
Salah satu alasan utama transisi dari K_ACCUMULATOR ke K_ACCUM adalah karena struktur structAccum bawaan Supcon menggunakan dua word 16‑bit (accum1 dan accum2). Urutan bit/word ini ternyata tidak selalu konsisten (tergantung endianness, yaitu cara sistem menyusun byte dalam memori), sehingga hasil akumulasi bisa mendadak jatuh atau menurun. Untuk aplikasi audit jangka panjang, kondisi ini tidak bisa diterima karena membuat hasil akumulasi sulit diprediksi, dan kesalahan akumulasi tidak dapat ditoleransi.
Sebagai solusi, K_ACCUM dirancang menggunakan LONG 32‑bit tunggal yang bebas dari ambiguitas bit order. Struktur ini tetap dilengkapi dengan remainder (SFLOAT) untuk menjaga presisi pecahan.
Dengan desain ini, K_ACCUM lebih stabil, tetap presisi, dan audit‑friendly.
Konversi ke structAccum masih dimungkinkan jika diperlukan untuk kompatibilitas HMI, tetapi logika inti tetap aman di structKAccum.
Dependensi dan Ekstensi Modular K_ACCUM
-
K_DELTA (Dependensi Waktu)
Menyediakan delta waktu wrap‑aware dari timer utama 16‑bit.
→ Digunakan oleh K_ACCUM dan seluruh block turunan agar konsisten, presisi, dan audit‑friendly. -
K_ADD_ACCUM (Aggregator)
Menjumlahkan dua accumulatorstructKAccummenjadi satu total konsolidasi.
Cocok untuk agregasi OEE lintas line, penggabungan energi dari beberapa sumber, atau chaining modular (shift → harian → bulanan). -
K_SUB_ACCUM (Differentiator)
Mengurangkan dua accumulatorstructKAccumuntuk menyingkap selisih.
Cocok untuk audit energi (supply–demand), neraca massa (inlet–outlet), atau analisis delta OEE. Jika dua accumulator yang sama dikurangkan, block ini berfungsi sebagai reset.
Karakteristik Bersama
- Presisi terjaga dengan kombinasi LONG + SFLOAT.
- Output utama tetap
structKAccum, dengan ALT_OUT (FLOAT) sebagai alternatif cepat. - Audit‑friendly: hasil dapat direkonstruksi dengan cara yang sama seperti K_ACCUM.
- Modular: operator cukup drag‑and‑drop block tanpa scripting manual.
Dengan K_DELTA sebagai time backbone dan K_ADD_ACCUM/K_SUB_ACCUM sebagai ekstensi, keluarga K_ACCUM membentuk arsitektur akumulasi modular yang presisi, efisien, dan siap audit lintas plant.
Implikasi Operasional
- Tidak perlu reset → operator terbebas dari prosedur reset akumulator yang berisiko menghapus histori.
- Data kontinu → histori akumulasi dapat berjalan tanpa interupsi, memudahkan analisis jangka panjang.
- Sederhana untuk transfer knowledge → operator baru cukup memahami bahwa akumulator akan terus bertambah, tanpa perlu menghafal SOP reset.
Dengan horizon overflow ±136 tahun, structKAccum praktis tidak memerlukan reset manual. Hal ini menghilangkan risiko kehilangan data akibat reset, sekaligus menyederhanakan SOP operator. Akumulator dapat berjalan kontinu, audit tetap konsisten, dan transfer knowledge lintas shift menjadi lebih mudah.
Potensi Ekstensi Fungsi
| Aplikasi | Konfigurasi RATE | Hasil |
|---|---|---|
| Hour Meter | RATE = 1.0 saat equipment ON | Akumulasi detik operasi → jam |
| Runtime Counter | RATE = 1 saat ON, 0 saat OFF | Total waktu ON untuk PM |
| Event Duration Logger | RATE = 1 saat kondisi tertentu | Total durasi kondisi aktif |
| Audit Energi | RATE = konsumsi energi per detik | Total energi (kWh) |
Validasi Independen dengan Rapid SCADA
Untuk memastikan hasil tidak bias, pengujian dilakukan menggunakan Rapid SCADA sebagai sistem eksternal yang independen dari DCS.
- Metode: flow statis 2500 diberikan secara identik ke K_ACCUM dan TOTAL_ACCUM dari variabel yang sama, lalu hasil ditrend di Rapid SCADA.
- Hasil:
- K_ACCUM: 2499,3 (deviasi −0,03%)
- TOTAL_ACCUM: 2450 (deviasi −2%)
- Makna: bahkan dengan pengujian eksternal, in‑house FB terbukti lebih presisi dibanding block bawaan vendor.
Dampak dan Nilai Tambah
- Efisiensi komunikasi → alamat 128 tidak cepat habis.
- Presisi akumulasi → hasil konsisten, bebas drift jangka panjang.
- Auditabilitas → operator dapat menelusuri delta waktu.
- Fleksibilitas → block dapat digunakan sebagai accumulator, hour meter, runtime counter, maupun logger.
- Kredibilitas eksternal → hasil diverifikasi oleh sistem independen (Rapid SCADA).
Kesimpulan
K_ACCUM berhasil menurunkan deviasi dibanding block bawaan Supcon. Hasilnya memang tidak harus sempurna—karena faktor eksternal seperti jitter komunikasi dan keterbatasan representasi data tetap ada—tetapi penurunan deviasi dari 2% menjadi 0,03% adalah pencapaian nyata.
Solusi ini bukan sekadar “membuat block baru”, melainkan membangun arsitektur yang efisien, presisi, audit‑friendly, dan terbukti lebih baik bahkan saat diuji dengan sistem independen. Pencapaian ini menjadi basis kuat untuk benchmark jangka panjang, di mana performa K_ACCUM dapat diuji lebih lama (jam, hari, hingga minggu) untuk membuktikan stabilitasnya dalam kondisi operasi nyata.
Catatan kontributor: Artikel ini disusun oleh Ketut Kumajaya dengan dukungan editorial dari Copilot (Microsoft AI) dalam penyusunan narasi, struktur, dan dokumentasi teknis.
Appendix A — Listing Kode Lengkap
Klik untuk membuka kode Function Block K_ACCUM
(*==============================================================================
FB Name : K_ACCUM
Purpose : Akumulator modular berbasis LONG + SFLOAT, menerima DELTA dari K_DELTA
Author : Ketut Kumajaya
Contributor : Copilot (Microsoft AI)
Version : 1.1 (tanpa RESET, dependensi ke K_DELTA)
Date : 01/10/2025
Input : ENABLE (BOOL) - aktivasi akumulasi
RATE (SFLOAT) - laju akumulasi per detik
DELTA (UINT) - selisih waktu antar siklus dari K_DELTA
ACC_IN (structKAccum) - nilai akumulasi sebelumnya
Output : ACC_OUT (structKAccum) - hasil akumulasi modular
ALT_OUT (FLOAT) - total nilai akumulasi sebagai alternatif
Notes : - Input waktu TIMER telah digantikan oleh DELTA dari FB K_DELTA
- K_ACCUM tidak menyimpan LAST_IN/OUT, sehingga lebih ringan
- RATE dijaga dalam domain ±16 untuk stabilitas dan audit modular
- Cocok untuk runtime, hour meter, OEE timer, dan akumulasi energi
- Pairing waktu dan nilai dilakukan di artefak audit terpisah
Use-case : Digunakan bersama K_DELTA untuk runtime modular lintas FB dan plant
==============================================================================*)
FUNCTION_BLOCK K_ACCUM
VAR_INPUT
ENABLE : BOOL;
RATE : SFLOAT;
DELTA : UINT;
ACC_IN : structKAccum;
END_VAR
VAR_OUTPUT
ACC_OUT : structKAccum;
ALT_OUT : FLOAT;
END_VAR
VAR
AccReal : FLOAT;
RateF : FLOAT;
END_VAR
(* STEP 1: Rekonstruksi total dari input *)
AccReal := LONG_TO_FLOAT(ACC_IN.accum) + SFLOAT_TO_FLOAT(ACC_IN.remainder);
(* STEP 2: Integrasi normal *)
RateF := SFLOAT_TO_FLOAT(RATE);
IF ENABLE THEN
IF (RateF > -16.0) AND (RateF < 16.0) THEN
IF DELTA > 0 THEN
AccReal := AccReal + (RateF * UINT_TO_FLOAT(DELTA));
END_IF;
END_IF;
END_IF;
(* STEP 3: Pisahkan kembali ke integer + pecahan *)
ACC_OUT.accum := FLOAT_TO_LONG(AccReal);
ACC_OUT.remainder := FLOAT_TO_SFLOAT(AccReal - LONG_TO_FLOAT(ACC_OUT.accum));
(* STEP 4: Output alternatif total *)
ALT_OUT := AccReal;
END_FUNCTION_BLOCK
Klik untuk membuka kode Function Block K_DELTA
(*==============================================================================
FB Name : K_DELTA
Purpose : Menghitung delta waktu wrap-aware dari timer utama (UINT 16-bit)
Author : Ketut Kumajaya
Version : 1.2 (IF-THEN-ELSE, no MOD)
Date : 07/10/2025
Input : TIMER_IN (UINT), LAST_IN (UINT)
Output : DELTA_OUT (UINT), LAST_OUT (UINT), ALARM_OUT (BOOL)
Notes : - IF-THEN-ELSE untuk hindari loncatan MOD
- Cutoff 60 detik; LONG untuk Supcon-safe
- Persisten global LAST_IN/OUT
==============================================================================*)
FUNCTION_BLOCK K_DELTA
VAR_INPUT
TIMER_IN : UINT;
LAST_IN : UINT;
END_VAR
VAR_OUTPUT
DELTA_OUT : UINT;
LAST_OUT : UINT;
ALARM_OUT : BOOL;
END_VAR
VAR
Delta : LONG;
StartupFlag : BOOL;
END_VAR
StartupFlag := g_bColdStartup OR g_bHotStartup OR g_bDownUsrPrgFlag OR g_bDownCfgFlag;
IF StartupFlag THEN
Delta := 0;
ALARM_OUT := FALSE;
g_bColdStartup := FALSE;
g_bHotStartup := FALSE;
g_bDownUsrPrgFlag := FALSE;
g_bDownCfgFlag := FALSE;
ELSE
IF TIMER_IN >= LAST_IN THEN
Delta := ULONG_TO_LONG(UINT_TO_ULONG(TIMER_IN)) - ULONG_TO_LONG(UINT_TO_ULONG(LAST_IN));
ELSE
Delta := ULONG_TO_LONG(UINT_TO_ULONG(65535 - LAST_IN)) + ULONG_TO_LONG(UINT_TO_ULONG(TIMER_IN)) + 1;
END_IF;
IF Delta > 60 THEN
Delta := 0;
ALARM_OUT := TRUE;
ELSE
ALARM_OUT := FALSE;
END_IF;
END_IF;
DELTA_OUT := ULONG_TO_UINT(LONG_TO_ULONG(Delta));
LAST_OUT := TIMER_IN;
END_FUNCTION_BLOCK
Klik untuk membuka kode Function Block K_ADD_ACCUM
(*==============================================================================
FB Name : K_ADD_ACCUM
Purpose : Menjumlahkan dua accumulator (structKAccum) secara modular
Author : Ketut Kumajaya
Contributor : Copilot (Microsoft AI)
Version : 1.0 (initial release)
Date : 28/09/2025
Input : ACC1 (structKAccum), ACC2 (structKAccum)
Output : ACC_OUT (structKAccum), ALT_OUT (FLOAT total)
Notes : - Presisi dijaga dengan LONG + SFLOAT
- ALT_OUT = total float alternatif
- Cocok untuk merge runtime, energy, atau counter modular
Use-case : Penjumlahan antar accumulator, agregasi OEE, chaining modular
==============================================================================*)
FUNCTION_BLOCK K_ADD_ACCUM
VAR_INPUT
ACC1 : structKAccum;
ACC2 : structKAccum;
END_VAR
VAR_OUTPUT
ACC_OUT : structKAccum;
ALT_OUT : FLOAT;
END_VAR
VAR
SumReal : FLOAT;
END_VAR
(* STEP 1: Rekonstruksi total dari masing-masing input *)
SumReal := LONG_TO_FLOAT(ACC1.accum) + SFLOAT_TO_FLOAT(ACC1.remainder)
+ LONG_TO_FLOAT(ACC2.accum) + SFLOAT_TO_FLOAT(ACC2.remainder);
(* STEP 2: Pisahkan kembali ke integer + pecahan *)
ACC_OUT.accum := FLOAT_TO_LONG(SumReal);
ACC_OUT.remainder := FLOAT_TO_SFLOAT(SumReal - LONG_TO_FLOAT(ACC_OUT.accum));
(* STEP 3: Output alternatif total *)
ALT_OUT := SumReal;
END_FUNCTION_BLOCK
Klik untuk membuka kode Function Block K_SUB_ACCUM
(*==============================================================================
FB Name : K_SUB_ACCUM
Purpose : Mengurangkan dua accumulator (structKAccum) secara modular
Author : Ketut Kumajaya
Contributor : Copilot (Microsoft AI)
Version : 1.0 (initial release)
Date : 28/09/2025
Input : ACC1 (structKAccum), ACC2 (structKAccum)
Output : ACC_OUT (structKAccum), ALT_OUT (FLOAT total)
Notes : - Presisi dijaga dengan LONG + SFLOAT
- ALT_OUT = total float alternatif
- Cocok untuk selisih runtime, energy, atau counter modular
Use-case : Pengurangan antar accumulator, analisis delta OEE, chaining modular
==============================================================================*)
FUNCTION_BLOCK K_SUB_ACCUM
VAR_INPUT
ACC1 : structKAccum;
ACC2 : structKAccum;
END_VAR
VAR_OUTPUT
ACC_OUT : structKAccum;
ALT_OUT : FLOAT;
END_VAR
VAR
DiffReal : FLOAT;
END_VAR
(* STEP 1: Rekonstruksi total dari masing-masing input *)
DiffReal := (LONG_TO_FLOAT(ACC1.accum) + SFLOAT_TO_FLOAT(ACC1.remainder))
- (LONG_TO_FLOAT(ACC2.accum) + SFLOAT_TO_FLOAT(ACC2.remainder));
(* STEP 2: Pisahkan kembali ke integer + pecahan *)
ACC_OUT.accum := FLOAT_TO_LONG(DiffReal);
ACC_OUT.remainder := FLOAT_TO_SFLOAT(DiffReal - LONG_TO_FLOAT(ACC_OUT.accum));
(* STEP 3: Output alternatif total *)
ALT_OUT := DiffReal;
END_FUNCTION_BLOCK
Klik untuk membuka kode Function Block legacy K_ACCUMULATOR
(*
==============================================================================
Function Block : K_ACCUMULATOR
Deskripsi : Integrator berbasis laju per detik (SFLOAT) dan free-running
timer 16-bit, kompatibel Supcon structAccum
Penulis : Ketut Kumajaya
Kontributor : Copilot (Microsoft AI)
Versi : 1.1
Tanggal : 25/09/2025
==============================================================================
Fungsi:
- Mengakumulasi nilai = RATE * DeltaSec setiap scan.
- Menggunakan external clock T_IN (0..65535 detik, wrap-aware).
- Reset penuh ditangani oleh built-in FB Supcon melalui structAccum.
- Proteksi delta waktu: delta negatif atau terlalu besar (>60 detik) diabaikan.
- Guard RATE: nilai anomali (-16 > RATE > 16) diabaikan.
- Struktur kompatibel dengan accumulator built-in Supcon.
Versi 1.1 (26/09/2025)
- AccInt diganti ke tipe LONG → konversi lebih sederhana dan mendukung nilai negatif
- Validasi remainder selalu dinormalisasi ke [0,1)
- Patch encoding low word → dipaksa unsigned (0..65535) agar kompatibel penuh dengan structAccum
- Eliminasi bug “accum1 = –32768” yang menyebabkan akumulasi tampak menurun
==============================================================================
*)
FUNCTION_BLOCK K_ACCUMULATOR
VAR_INPUT
RATE : SFLOAT; (* Laju per detik (unit/s) *)
T_IN : UINT; (* Free-running timer (0..65535 detik) *)
ACC_IN : structAccum; (* Akumulator persisten input *)
LAST_IN : UINT; (* Snapshot timer sebelumnya *)
END_VAR
VAR_OUTPUT
ACC_OUT : structAccum; (* Akumulator hasil update *)
LAST_OUT : UINT; (* Snapshot timer berikutnya *)
END_VAR
VAR
AccReal : FLOAT; (* Rekonstruksi total accumulator *)
AccInt : LONG; (* Bagian integer dari AccReal *)
AccFrac : FLOAT; (* Bagian pecahan dari AccReal *)
DeltaSec : UINT; (* Selisih detik antar scan *)
RateF : FLOAT; (* RATE dalam FLOAT *)
LowWord : WORD;
HighWord : INT;
END_VAR
(* NOTE: accum1 = low word, accum2 = high word, remainder = fractional part *)
(* EVENT: Rekonstruksi nilai total dari ACC_IN *)
AccInt := INT_TO_LONG(WORD_TO_INT(INT_TO_WORD(ACC_IN.accum1)))
+ DWORD_TO_LONG(
SHL_DWORD(LONG_TO_DWORD(INT_TO_LONG(ACC_IN.accum2)),
16)); (* shift high word 16 bit *)
AccFrac := SFLOAT_TO_FLOAT(ACC_IN.remainder); (* fractional part *)
AccReal := LONG_TO_FLOAT(AccInt) + AccFrac; (* total accumulator *)
(* PROTEKSI: hitung delta dengan wrap 16-bit (modular, no-branch) *)
DeltaSec := (T_IN + 65536 - LAST_IN) MOD 65536;
(* PROTEKSI: guard delta anomali *)
IF DeltaSec > 60 THEN
DeltaSec := 0;
END_IF;
(* PROTEKSI: guard RATE anomali sesuai domain SFLOAT 12-bit: -16..+16 *)
RateF := SFLOAT_TO_FLOAT(RATE);
IF (RateF < 16) AND (RateF > -16) THEN
IF DeltaSec > 0 THEN
AccReal := AccReal + (RateF * UINT_TO_FLOAT(DeltaSec));
END_IF;
END_IF;
(* EVENT: Pisahkan kembali ke structAccum *)
AccInt := FLOAT_TO_LONG(AccReal);
AccFrac := AccReal - LONG_TO_FLOAT(AccInt);
(* Normalisasi remainder ke [0,1) *)
IF AccFrac < 0.0 THEN
AccInt := AccInt - 1;
AccFrac := AccFrac + 1.0;
ELSE
IF AccFrac >= 1.0 THEN
AccInt := AccInt + 1;
AccFrac := AccFrac - 1.0;
END_IF;
END_IF;
(* NOTE: LowWord dipaksa unsigned (0..65535) agar kompatibel dengan structAccum.
HighWord tetap signed. Total AccInt = HighWord*65536 + LowWord. *)
LowWord := INT_TO_WORD(LONG_TO_INT(AccInt MOD 65536)); (* selalu 0..65535 *)
HighWord := LONG_TO_INT(AccInt / 65536); (* high word bisa signed *)
ACC_OUT.accum1 := WORD_TO_INT(LowWord); (* low word aman, tidak pernah -32768 *)
ACC_OUT.accum2 := HighWord; (* high word signed *)
ACC_OUT.remainder := FLOAT_TO_SFLOAT(AccFrac);
ACC_OUT.reserved := 0.0;
(* Persist snapshot untuk scan berikutnya *)
LAST_OUT := T_IN;
END_FUNCTION_BLOCK
Appendix B — Extended Validation Runtime (1–6 Jam)
Pengujian runtime lebih panjang dilakukan dengan flow statis 2500 untuk melihat pola drift akumulasi secara progresif.
Hasil Pengujian Runtime
| Runtime | Ideal | K_ACCUM | Deviasi Absolut | Deviasi Relatif | TOTAL_ACCUM | Deviasi Absolut | Deviasi Relatif |
|---|---|---|---|---|---|---|---|
| 1 jam | 2500 | 2499.31 | −0.694 | −0.028% | 2450.69 | −49.306 | −1.972% |
| 2 jam | 5000 | 5002.08 | +2.083 | +0.042% | 4905.56 | −94.444 | −1.898% |
| 3 jam | 7500 | 7500.69 | +0.694 | +0.009% | 7355.56 | −144.445 | −1.926% |
| 4 jam | 10000 | 10000.69 | +0.694 | +0.007% | 9806.94 | −193.056 | −1.931% |
| 5 jam | 12500 | 12500.00 | +0.000 | +0.000% | 12258.33 | −241.667 | −1.933% |
| 6 jam | 15000 | 14998.61 | −1.389 | −0.009% | 14708.33 | −291.666 | −1.944% |
Interpretasi
- K_ACCUM: deviasi relatif tetap <0.05% bahkan hingga 6 jam, menunjukkan presisi tinggi dan stabilitas jangka panjang.
- TOTAL_ACCUM: drift konsisten di sekitar −1.9% sejak awal hingga 6 jam, menegaskan bias bawaan block vendor.
- Makna audit: tren progresif ini memperkuat klaim bahwa K_ACCUM bukan hanya presisi sesaat, tetapi juga tahan drift dalam runtime panjang.