K_FTL: Solusi First Trip Logic Deterministik
First Trip Logic (FTL) membantu menentukan mesin pertama yang mengalami trip di antara banyak unit yang berjalan paralel. Artikel ini membahas desain, implementasi, dan validasi logika FTL menggunakan Structured Text dan Python di lingkungan Jupyter Notebook.
Photo by Joshua Golde / Unsplash
First Trip Logic Deterministik untuk Deteksi Trip Pertama Secara Akurat
Ditulis oleh Ketut Kumajaya — 2 November 2025
Pendahuluan
Dalam pengoperasian beberapa unit mesin secara bersamaan, seringkali terjadi trip yang tidak terduga. Yang paling krusial bagi operator dan engineer adalah mesin pertama yang mengalami trip, karena ini biasanya menjadi indikator awal masalah yang memerlukan tindakan cepat.
Logika standar yang hanya mencatat semua trip tanpa urutan seringkali membuat analisis menjadi lambat dan membingungkan. Untuk mengatasi hal ini, kita dapat menggunakan First Trip Logic (FTL) berbasis array dengan fitur rising edge detection, trip latching, dan pencatatan timestamp. Operator tetap bisa memantau status masing-masing mesin melalui pin input/output individual di diagram HMI.
Desain Arsitektur FTL
Solusi FTL terdiri dari dua bagian:
-
Core Function Block (K_FTL)
- Mendeteksi trip pertama dari sejumlah mesin (default 8 channel).
- Array-based input (
RunInputs[1..8]). - Rising edge detection per channel untuk menghindari false trip.
TripLatched[]menandai mesin yang sudah trip sampai reset manual.FirstTripIndexmenunjukkan mesin pertama yang trip.TripTime[]mencatat timestamp trip untuk audit trail.- Deterministik: prioritas indeks mesin dijaga.
-
Wrapper Function Block (K_FTLW)
- Memetakan 8 input/output individual (
In1..In8→RunInputs[1..8],TripLatched[1..8]→Out1..Out8). - Operator tetap dapat memantau status masing-masing mesin di diagram HMI.
- Reset diteruskan ke core FB, dengan edge-hold untuk mencegah false first trip.
- Memetakan 8 input/output individual (
Alur Logika:
- Reset → inisialisasi semua trip latched & timestamp → monitoring RunInputs → deteksi rising edge → latching → pencatatan FirstTripIndex & TripTime.
Kode Implementasi
Berikut implementasi dalam Structured Text (ST) berdasarkan standar IEC 61131-3, dapat digunakan langsung pada PLC atau DCS yang kompatibel.
Core Function Block – K_FTL
(*
===========================================================
K_FTL : Ketut - First Trip Logic
Versi : 1.0
Author : Ketut Kumajaya
Scope : Function block untuk mendeteksi trip pertama
dari sekumpulan mesin (default 8 input).
Fitur :
- Array-based input (RunInputs[1..8])
- Rising edge detection per channel
- TripLatched[] → status trip latched sampai reset manual
- FirstTripIndex → menunjukkan mesin pertama yang trip
- TripTime[] → timestamp absolut untuk audit trail
- Reset manual menghapus semua status
Catatan :
- Deterministik dengan prioritas indeks array
- Nama mengikuti istilah industri: First Trip Logic
- **Input RunInputs[i] harus aktif HIGH saat trip terjadi**
Jika sinyal asli aktif LOW, lakukan inversi sebelum masuk FB:
RunInputs[i] := NOT OriginalSignal[i]
===========================================================
*)
FUNCTION_BLOCK K_FTL
VAR_INPUT
RunInputs : ARRAY[1..8] OF BOOL;
Reset : BOOL;
END_VAR
VAR_OUTPUT
FirstTripIndex : INT;
TripLatched : ARRAY[1..8] OF BOOL;
TripTime : ARRAY[1..8] OF DT;
END_VAR
VAR
PrevInputs : ARRAY[1..8] OF BOOL;
TripLocked : BOOL;
ResetLatch : BOOL;
i : INT;
END_VAR
IF Reset THEN
FirstTripIndex := 0;
TripLocked := FALSE;
ResetLatch := TRUE;
FOR i := 1 TO 8 DO
TripLatched[i] := FALSE;
TripTime[i] := DT#1970-01-01-00:00:00;
PrevInputs[i] := RunInputs[i];
END_FOR;
ELSE
ResetLatch := FALSE;
FOR i := 1 TO 8 DO
IF (NOT ResetLatch) AND (RunInputs[i] = TRUE) AND (PrevInputs[i] = FALSE) THEN
TripLatched[i] := TRUE;
TripTime[i] := SYSTIME();
IF NOT TripLocked THEN
FirstTripIndex := i;
TripLocked := TRUE;
END_IF;
END_IF;
PrevInputs[i] := RunInputs[i];
END_FOR;
END_IF;
END_FUNCTION_BLOCK
Wrapper Function Block – K_FTLW
(*===========================================================
K_FTLW : Ketut - First Trip Logic Wrapper
Versi : 1.0
Author : Ketut Kumajaya
Scope : Wrapper untuk K_FTL agar operator melihat
8 pin input/output individual di diagram.
Fitur :
- Memanggil K_FTL (array-based) di dalamnya
- Memetakan In1..In8 → RunInputs[1..8]
- Memetakan Out1..Out8 ← TripLatched[1..8]
- Reset manual diteruskan ke core FB
Catatan :
- Operator tetap bisa memantau status individual
- Deterministik dengan prioritas indeks array
===========================================================*)
FUNCTION_BLOCK K_FTLW
VAR_INPUT
In1, In2, In3, In4, In5, In6, In7, In8 : BOOL;
Reset : BOOL;
END_VAR
VAR_OUTPUT
FirstTripIndex : INT;
Out1, Out2, Out3, Out4, Out5, Out6, Out7, Out8 : BOOL;
END_VAR
VAR
Core : K_FTL;
RunArray : ARRAY[1..8] OF BOOL;
i : INT;
END_VAR
(* Map inputs *)
RunArray[1] := In1;
RunArray[2] := In2;
RunArray[3] := In3;
RunArray[4] := In4;
RunArray[5] := In5;
RunArray[6] := In6;
RunArray[7] := In7;
RunArray[8] := In8;
(* Call core FB *)
Core(RunInputs := RunArray, Reset := Reset);
(* Map outputs *)
FirstTripIndex := Core.FirstTripIndex;
Out1 := Core.TripLatched[1];
Out2 := Core.TripLatched[2];
Out3 := Core.TripLatched[3];
Out4 := Core.TripLatched[4];
Out5 := Core.TripLatched[5];
Out6 := Core.TripLatched[6];
Out7 := Core.TripLatched[7];
Out8 := Core.TripLatched[8];
Verifikasi melalui Simulasi
Untuk memvalidasi logika K_FTL, simulasi dilakukan menggunakan Python (mengadaptasi kode Structured Text ke class sederhana). Test case mencakup reset, no-trip, single trip, multiple trip, dan reset ulang. Timestamp menggunakan waktu real (mirip SYSTIME() di PLC).
Untuk memastikan reprodusibilitas hasil dan mempercepat validasi, simulasi dilakukan di lingkungan Jupyter Notebook, yang memungkinkan eksekusi kode Python dan visualisasi hasil dalam satu lingkungan interaktif. Pendekatan ini memudahkan verifikasi logika
First Trip Logicsecara real-time, karena setiap perubahan nilai input dapat langsung diamati melalui output dan grafik timeline tanpa perlu kompilasi ulang atau deploy ke PLC.
| Test Case | Deskripsi | Input (RunInputs, Channel 1-8) | Reset Input | Hasil Utama |
|---|---|---|---|---|
| 1: Reset Awal | Inisialisasi semua status | [False x8] | True | FirstTripIndex=0 TripLatched=[False x8] TripTime=[1970-01-01 x8] |
| 2: No Trip | Monitoring tanpa perubahan | [False x8] | False | FirstTripIndex=0 TripLatched=[False x8] TripTime=[1970-01-01 x8] |
| 3: Single Trip (Channel 4) | Rising edge di channel 4 | [False, False, False, True x4] | False | FirstTripIndex=4 TripLatched=[False, False, False, True x4] TripTime=[1970-01-01 x6, T1 untuk ch4] |
| 4: Multiple Trip | Tambah rising edge di semua channel | [True x8] | False | FirstTripIndex=4 (tetap locked!) TripLatched=[True x8] TripTime=[T2 x7, T1 untuk ch4] |
| 5: Reset Ulang | Reset setelah multiple trip | [False x8] | True | FirstTripIndex=0 TripLatched=[False x8] TripTime=[1970-01-01 x8] |
Catatan Simulasi: Rising edge detection dan prioritas indeks terjaga. Timestamp T1/T2 adalah waktu real saat trip.
Klik untuk Lihat Script Python Lengkap (Simulasi Real-Time)
import time, random
from datetime import datetime
class K_FTL:
"""
K_FTL — First Trip Logic Deterministik
Simulasi Function Block (FB) untuk mendeteksi sinyal trip pertama
di antara beberapa input digital, lalu mengunci (lock) hasilnya
agar tetap konsisten sampai di-reset.
"""
def __init__(self):
# --- Variabel internal ---
self.FirstTripIndex = 0 # Channel pertama yang trip (1-based)
self.TripLatched = [False] * 8 # Status latched tiap channel
self.TripTime = [None] * 8 # Timestamp trip per channel
self.PrevInputs = [False] * 8 # Nilai input sebelumnya
self.TripLocked = False # Lock ketika first trip sudah ditentukan
self.ResetLatch = False # Status reset terakhir
def execute(self, RunInputs, Reset):
"""
Jalankan logika FTL.
RunInputs: list[bool] panjang 8 — status input digital
Reset: bool — sinyal reset latch
"""
current_real_time = time.time()
if Reset:
# Reset semua status internal
self.FirstTripIndex = 0
self.TripLocked = False
self.ResetLatch = True
for i in range(8):
self.TripLatched[i] = False
self.TripTime[i] = None
self.PrevInputs[i] = RunInputs[i]
else:
self.ResetLatch = False
for i in range(8):
# Deteksi rising edge: FALSE → TRUE
if not self.ResetLatch and RunInputs[i] and not self.PrevInputs[i]:
self.TripLatched[i] = True
self.TripTime[i] = current_real_time
# Catat trip pertama hanya sekali
if not self.TripLocked:
self.FirstTripIndex = i + 1
self.TripLocked = True
self.PrevInputs[i] = RunInputs[i]
def print_status(ftl, test_name):
"""
Print status internal FB dengan format waktu yang mudah dibaca.
"""
print(f"\n{test_name}:")
print(f" FirstTripIndex: {ftl.FirstTripIndex}")
print(f" TripLatched : {ftl.TripLatched}")
formatted_times = [
datetime.fromtimestamp(t).strftime('%Y-%m-%d %H:%M:%S')
if t else '1970-01-01' for t in ftl.TripTime
]
print(f" TripTime : {formatted_times}")
# --- Simulasi FTL ---
ftl = K_FTL()
# Test 1: Reset Awal
RunInputs = [False] * 8
ftl.execute(RunInputs, True)
print_status(ftl, "Test 1 - Reset Awal")
# Test 2: No Trip
ftl.execute(RunInputs, False)
print_status(ftl, "Test 2 - No Trip")
# Test 3: Single Trip (ubah channel sesuai kebutuhan)
trip_channel = 4
RunInputs[trip_channel - 1] = True
ftl.execute(RunInputs, False)
print_status(ftl, f"Test 3 - Single Trip Channel {trip_channel}")
# Test 4: Multiple Trip dengan delay acak 0.3–1.5s dan channel acak
channels = list(range(8))
random.shuffle(channels) # urutan channel diacak
delays = [random.uniform(0.3, 1.5) for _ in range(8)]
print("\nTest 4 - Multiple Trip dengan delay acak dan channel acak:")
for ch, delay in zip(channels, delays):
if not ftl.TripLatched[ch]:
RunInputs[ch] = True
time.sleep(delay)
ftl.execute(RunInputs, False)
print(f" Tripped ch{ch+1} after {delay:.2f}s at {datetime.now().strftime('%H:%M:%S.%f')[:-3]}")
print_status(ftl, "Test 4 - Multiple Trip (random delay & channel acak)")
# Test 5: Reset Ulang
ftl.execute(RunInputs, True)
print_status(ftl, "Test 5 - Reset Ulang")
Visualisasi Hasil Simulasi
Script berikut untuk membuat visualisasi timeline terjadinya trip pada masing-masing channel berdasarkan hasil eksekusi class K_FTL di cell Jupyter Notebook sebelumnya. Setiap batang horizontal merepresentasikan waktu relatif terhadap trip pertama, sementara warna menunjukkan identitas channel yang mengalami trip.
Catatan: Pastikan bagian
Test 5: Reset Ulangpada cell simulasi sebelumnya dihapus atau tidak dijalankan sebelum melakukan visualisasi, agar hasil grafik tetap merepresentasikan kondisi trip terakhir dengan benar.
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import seaborn as sns
# --- Plotting ---
rel_times = [max(0.1, (ftl.TripTime[i] - ftl.TripTime[ftl.FirstTripIndex-1] if ftl.TripTime[i] else 0.1))
for i in range(8)]
plt.rcParams['svg.fonttype'] = 'none' # simpan teks sebagai teks, bukan path
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'Arial']
plt.rcParams['font.size'] = 9 # basis font size lebih kecil
sns.set_style("whitegrid")
plt.style.use('seaborn-v0_8-darkgrid')
fig, ax = plt.subplots(figsize=(10,5))
colors = sns.color_palette("Spectral", 8)
colors[ftl.FirstTripIndex-1] = 'red'
for i in range(8):
ax.barh(i, rel_times[i], color=colors[i],
edgecolor='darkred' if i==ftl.FirstTripIndex-1 else 'navy',
linewidth=1.5 if i==ftl.FirstTripIndex-1 else 1)
if ftl.TripTime[i]:
ax.text(rel_times[i]+0.05, i,
datetime.fromtimestamp(ftl.TripTime[i]).strftime('%H:%M:%S'),
va='center', ha='left', fontsize=8)
# Annotasi First Trip
ax.annotate(f'First Trip (Ch {ftl.FirstTripIndex})',
xy=(rel_times[ftl.FirstTripIndex-1]+0.4, ftl.FirstTripIndex-1),
xytext=(rel_times[ftl.FirstTripIndex-1]+1, ftl.FirstTripIndex-1+0.05),
arrowprops=dict(facecolor='black', shrink=0.05, width=1.5, headwidth=6),
fontsize=9, color='red')
ax.set_yticks(range(8))
ax.set_yticklabels(range(1,9))
ax.invert_yaxis()
ax.set_xlabel('Detik dari Trip Pertama')
ax.set_title(f'Timeline Trip per Channel (First Trip: Ch {ftl.FirstTripIndex})')
ax.grid(axis='x', linestyle='--', alpha=0.45, color='gray')
ax.set_xlim(0, max(rel_times)+1)
# Legend lebih ringkas
legend_elements = [Line2D([0],[0], color=colors[i], lw=3, label=f'Ch {i+1}') for i in range(8)]
ax.legend(handles=legend_elements, loc='upper right', fontsize=8)
# Simpan dan tampilkan plot
plt.tight_layout()
plt.savefig('ftl_trip_timeline.svg', format='svg')
plt.savefig('ftl_trip_timeline.png', format='png', dpi=300)
plt.show()
Visualisasi Timeline Trip per Channel
Setelah logika First Trip Logic disimulasikan dan diverifikasi di Jupyter Notebook, hasilnya divisualisasikan dalam bentuk diagram waktu agar memudahkan interpretasi urutan trip secara visual. Grafik ini juga berfungsi sebagai bukti deterministik bahwa FirstTripIndex selalu konsisten dengan urutan aktual terjadinya trip.
Manfaat dan Kelebihan
- Human‑friendly: status mesin ditampilkan per pin di diagram HMI.
- Audit-ready: timestamp tiap trip memudahkan analisis root-cause.
- Deterministik: prioritas indeks terjaga; mesin pertama tercatat dengan benar.
- Scalable: core FB bisa diperluas dari 8 ke 16 channel dengan minimal modifikasi.
- Integrasi mudah: langsung bisa dipasang di DCS/PLC tanpa board tambahan.
Tips & Best Practices
- Pastikan RunInputs aktif sebelum monitoring untuk menghindari false trip saat startup.
- Lakukan reset saat kondisi aman agar first trip logika tidak salah deteksi.
- Periksa fungsi timestamp di DCS Anda (SYSTIME atau CURRENT_DATE_TIME).
- Simulasikan beberapa mesin trip secara bersamaan untuk memastikan FirstTripIndex berfungsi sesuai harapan.
Catatan:
- FB ini menentukan first trip secara deterministik berdasarkan indeks array input.
- Jika beberapa mesin trip hampir bersamaan, prioritas dipengaruhi posisi di array.
- Untuk kondisi kritis, bisa menggunakan dual FB parallel:
• Jika kedua FB menghasilkan FirstTripIndex sama → trip pertama valid.
• Jika berbeda → kondisi perlu dianalisis lebih lanjut.
Penutup
Dengan menggunakan K_FTL, Anda dapat membuat monitoring mesin lebih aman, terstruktur, dan human‑friendly. Logika deterministik ini memastikan mesin pertama yang trip selalu tercatat dengan tepat, mempermudah troubleshooting dan audit. Logika sederhana seperti ini bisa menjadi pembeda antara sistem yang hanya menunjukkan gejala dan sistem yang benar-benar memberi tahu akar masalah.