Detects and confirms when a fluidized bed combustor transitions from a packed state to a sustained fluidized state, using live AVEVA InTouch historian data.
| File | Purpose |
|---|---|
tui.py |
Terminal monitor — queries historian, shows state and sustain timer |
fluidization_detector.py |
Pure detection logic, no UI dependency |
historian_client.py |
AVEVA InTouch pyodbc query wrapper |
fbc_tags.json |
Tag names, thresholds, connection config |
pip install -r requirements.txt
python tui.py
Edit fbc_tags.json to set your historian address, tag names, and detection parameters before first run.
The TUI connects to the AVEVA InTouch SQL historian and polls every 30 seconds. It displays:
- Live values — all seven tags (three dP, four temperatures)
- Total Bed dP trend — ASCII sparkline of the last 90 minutes with a transition marker
- Detection state — PACKED / PULSING / FLUIDIZED / DE-FLUIDIZATION ALARM
- Sustain timer — progress bar filling toward the 5-minute confirmation window
- Auto-calculated baseline and threshold — derived from the trend data on every refresh
| Key | Action |
|---|---|
R |
Manual refresh |
T |
Set lookback window and resolution |
C |
Open fbc_tags.json in default editor |
D |
Toggle debug log panel |
H |
Help screen |
Q |
Quit |
The bed passes through three states during startup:
| State | Total Bed dP | Description |
|---|---|---|
| PACKED | ~40 inWC | Media settled, air below minimum fluidization velocity |
| PULSING | > threshold (brief) | Transient air blast — not sustained |
| FLUIDIZED | > threshold for 5 min | Confirmed fluidization — latched |
Dynamic threshold — on every refresh the detector takes the 10th percentile of all valid Total Bed dP readings in the trend window as the packed-bed baseline, then adds 2.5 inWC. The threshold adapts automatically to changes in bed media weight.
Confirmation — dP must stay above the threshold continuously for sustain_seconds (default 300 s). Any dip below threshold resets the timer. Transient pulses never confirm.
De-fluidization guard — after confirmation, if dP drops below baseline − 2 inWC for more than 120 s a DE-FLUIDIZATION ALARM is raised.
{
"connection": {
"server": "128.1.3.54",
"database": "Runtime",
"uid": "wwUser",
"pwd": "wwUser",
"driver": "SQL Server"
},
"tags": {
"total_bed_dp": "eEI0122PT",
"nozzle_dp": "eEI0123PT",
"bed_media_dp": "eEI0124PT",
"zone1_temp": "eEI0164TE",
"zone2_temp": "eEI0165TE",
"zone3_temp": "eEI0166TE",
"zone4_temp": "eEI0167TE"
},
"detection": {
"sustain_seconds": 300,
"threshold_margin": 2.5,
"packed_baseline_pct": 10,
"defluid_margin": 2.0,
"defluid_seconds": 120,
"valid_low": 5.0,
"valid_high": 150.0
},
"trend": {
"lookback_minutes": 90,
"resolution_seconds": 10,
"chart_width": 60
}
}All changes take effect on the next refresh — no restart required.
- Python 3.9+
textual >= 0.47.0pyodbc >= 5.0.0pandas >= 2.0.0- Microsoft ODBC Driver for SQL Server (or legacy "SQL Server" driver) —
pip install pyodbcalone is not sufficient
fluidized_bed/
├── tui.py Terminal monitor (run this)
├── historian_client.py AVEVA InTouch pyodbc query wrapper
├── fluidization_detector.py Pure detection logic
├── fbc_tags.json Tag names, thresholds, connection config
├── requirements.txt
├── Screenshot.jpg
└── FBC_MONITOR.md Detailed operating guide (also via H key in TUI)
