Projects & Technical Apps

Focused tools and simulations demonstrating modeling assumptions, implementation choices, and usable outputs.

Tank Dynamics Simulator

Live Demo

A 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

TagNameWhat It ShowsUnits
FI-100Inlet FlowFlow rate entering the tankm³/s
LI-100Level IndicatorCurrent liquid level in the tankm
FI-101Outlet FlowFlow rate leaving through the valvem³/s
VP-100Valve PositionHow 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

  1. Click the SP field on the LIC-100 faceplate.
  2. Type a new value (e.g. 3.0). Range: 0.0 to 5.0 metres.
  3. 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:

ParameterSymbolDescriptionDefault
Proportional GainKcHow aggressively the controller reacts to error~1.0
Integral TimeTiHow quickly past error is corrected (seconds)~10.0 s
Derivative TimeTdHow 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:

ParameterDescriptionDefault
Min FlowLower bound for the random walk (m³/s)0.8
Max FlowUpper bound for the random walk (m³/s)1.2
VarianceHow much the flow fluctuates each step0.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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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

LayerTechnologyRole
Physics engineC++ with GSLSolves ODEs (RK4)
Python bridgepybind11Exposes C++ simulation to Python
API serverFastAPIWebSocket endpoint, REST config
FrontendNext.js + React + RechartsReal-time UI and charting
DeploymentDocker + Traefik on VPSContainerised with auto-HTTPS

Each browser session creates an independent simulation instance on the server. Your changes don't affect other users.