Tank Dynamics Simulator
Live DemoA real-time process simulation of a liquid tank with PID level control, running as a web application. A C++ physics engine solves the differential equations on the server and streams results to your browser over a WebSocket at ~1 Hz.
You can change the level setpoint, retune the PID controller, and introduce flow disturbances — then watch the system respond in real time. The interface follows ISA-101 conventions used in industrial control rooms.
No login required. Each browser session runs its own independent simulation instance.
The Interface
The simulator has three tabs along the top: Process, Trends, and Upsets. A connection indicator in the top-right corner shows whether your browser is connected to the simulation engine (green = connected).
Process Tab
The Process tab is the main view. It shows a schematic of the tank system with live instrument readings.
- A tank with animated liquid fill level (blue). Scale markings on the left run from 0 to 5 metres.
- An inlet pipe (top-left) carrying liquid into the tank.
- An outlet pipe (right) with a control valve (shown as the standard ISA bow-tie symbol).
- A dashed control signal line from the controller faceplate to the valve.
Instrument Tags
| Tag | Name | What It Shows | Units |
|---|---|---|---|
| FI-100 | Inlet Flow | Flow rate entering the tank | m³/s |
| LI-100 | Level Indicator | Current liquid level in the tank | m |
| FI-101 | Outlet Flow | Flow rate leaving through the valve | m³/s |
| VP-100 | Valve Position | How far open the control valve is | % |
Controller Faceplate (LIC-100)
The controller faceplate sits to the right of the tank and is the main control interface. It displays four values:
- PV (Process Variable) — the current tank level (measured).
- SP (Setpoint) — the target level. This is editable — click the field, type a value between 0 and 5 metres, and press Enter.
- OP (Output) — the controller output signal driving the valve (0–100%).
- Err (Error) — the difference between PV and SP. Colour-coded:
- Grey: |error| < 0.2 m — system is close to setpoint.
- Yellow: 0.2 ≤ |error| < 0.5 m — moderate deviation.
- Red: |error| ≥ 0.5 m — large deviation, controller is working hard.
Changing the Setpoint
- Click the SP field on the LIC-100 faceplate.
- Type a new value (e.g.
3.0). Range: 0.0 to 5.0 metres. - Press Enter or click away.
The controller will begin adjusting the valve to bring the level to the new setpoint. Watch the error indicator change colour as the system responds.
Tuning the PID Controller
Click the gear icon (⚙) on the LIC-100 faceplate to open the PID tuning panel. Three parameters are available:
| Parameter | Symbol | Description | Default |
|---|---|---|---|
| Proportional Gain | Kc | How aggressively the controller reacts to error | ~1.0 |
| Integral Time | Ti | How quickly past error is corrected (seconds) | ~10.0 s |
| Derivative Time | Td | How much the controller anticipates future error (seconds) | ~1.0 s |
There is also a Reverse Acting checkbox. This should remain checked for this system — opening the outlet valve decreases the tank level, so the controller action is reversed.
Click Apply to send the new gains to the simulation. The effect is immediate.
Trends Tab
The Trends tab shows historical charts of the simulation. Select a time range using the buttons at the top:
1 min · 5 min · 30 min · 1 hr (default) · 2 hr
Chart 1: Tank Level vs Setpoint
Two lines on the same axes (0–5 m):
- Blue solid line — actual tank level (PV).
- Red dashed line — setpoint (SP).
This is the most useful chart for seeing how well the controller tracks the setpoint after a change or disturbance.
Chart 2: Inlet and Outlet Flows
Two lines (0–2 m³/s):
- Cyan line — inlet flow.
- Orange line — outlet flow.
When the system is at steady state, these two flows are approximately equal. During transients, you can see the outlet flow (controlled by the valve) adjusting to match the inlet.
Chart 3: Controller Output (Valve Position)
Single purple line (0–100%). Shows how the controller is manipulating the valve over time. Useful for spotting saturation (valve fully open or fully closed) and oscillatory behaviour from aggressive tuning.
All charts are interactive — hover for tooltips, click legend entries to toggle series on/off.
Upsets Tab
The Upsets tab lets you configure the inlet flow to the tank, simulating process disturbances.
Constant Mode
Sets the inlet flow to a fixed value. Enter a flow rate between 0.0 and 2.0 m³/s and click Apply.
Use this to create a step change: the inlet flow jumps instantly to the new value, and you can switch to the Trends tab to watch the controller respond.
Brownian Mode
Simulates a realistic, continuously varying inlet flow using a random walk (Brownian motion). Configure three parameters:
| Parameter | Description | Default |
|---|---|---|
| Min Flow | Lower bound for the random walk (m³/s) | 0.8 |
| Max Flow | Upper bound for the random walk (m³/s) | 1.2 |
| Variance | How much the flow fluctuates each step | 0.05 |
Click Apply to start. The inlet flow will wander randomly within the bounds, creating a continuous disturbance that the PID controller must reject. This is a more realistic simulation of what happens in a real process — feed flows are never perfectly constant.
The Physics Model
The simulation solves the following system in real time:
Material balance — the rate of change of liquid level depends on the difference between inlet and outlet flow:
Gravity-driven outlet — the outlet flow depends on both the valve opening and the current liquid level (higher level = more head = more flow):
where x is the valve opening (0–1) and kv is a valve coefficient.
PID control — the controller calculates the valve opening based on the error between setpoint and measured level, using proportional, integral, and derivative terms with output saturation (valve cannot go below 0% or above 100%).
The ODEs are integrated using a 4th-order Runge-Kutta method (RK4) via the GNU Scientific Library. The simulation runs in C++ for performance, with Python/FastAPI serving the WebSocket API.
Things to Try
Here are some experiments to explore how the system behaves:
- Step change response — Set the level to 1.0 m, let it settle, then change the setpoint to 3.0 m. Watch how the controller opens the valve less (or closes it) to let the tank fill, then gradually returns to steady state.
- Aggressive tuning — Increase Kc to 5.0 or higher. The system will oscillate — the valve overreacts, the level overshoots, and the cycle repeats. This is what "poorly tuned" looks like.
- Slow integral action — Set Ti to 100 s (or higher). The controller will reach the setpoint eventually, but the offset will persist for a long time. Reduce Ti to 5 s and the offset disappears faster but with more overshoot.
- Remove integral entirely — Set Ti to 0. The controller becomes P-only and will settle at a permanent offset from the setpoint. This demonstrates why integral action exists.
- Brownian disturbance rejection — Switch to Brownian mode on the Upsets tab with default settings. Watch the Trends tab — you'll see the inlet flow wandering and the controller continuously adjusting the valve to keep the level near setpoint.
- Valve saturation — Set a very low setpoint (e.g. 0.5 m) with a high inlet flow (e.g. 1.5 m³/s). The valve may fully open and still not be able to drain fast enough — the controller output hits 100% and the level rises above the setpoint. This is a real operational constraint.
- Derivative action — Set Td to 0 and make a setpoint change. Then set Td to 2.0 and repeat. With derivative action, the initial response is faster and overshoot is reduced — the controller "anticipates" the level approaching the setpoint and backs off early.
Technical Stack
| Layer | Technology | Role |
|---|---|---|
| Physics engine | C++ with GSL | Solves ODEs (RK4) |
| Python bridge | pybind11 | Exposes C++ simulation to Python |
| API server | FastAPI | WebSocket endpoint, REST config |
| Frontend | Next.js + React + Recharts | Real-time UI and charting |
| Deployment | Docker + Traefik on VPS | Containerised with auto-HTTPS |
Each browser session creates an independent simulation instance on the server. Your changes don't affect other users.