L03: First-Order Dynamics¶
Prerequisites: L02 | Effort: 45 min | Seborg: Chapter 5
Learning Objectives¶
By the end of this lesson you will:
- ✅ Understand first-order system behavior (exponential response)
- ✅ Implement first-order dynamics using
prev()andema() - ✅ Calculate time constants from data
- ✅ Use exponential moving averages (EMA) for filtering
- ✅ Generate KPIs from time-series data (settling time, rise time)
Theory Recap: First-Order Systems (Seborg Ch. 5)¶
What is a First-Order System?¶
Definition: A system whose behavior is described by a single time constant τ (tau)
Transfer function:
Where: - K = Process gain (steady-state output/input ratio) - τ = Time constant (time to reach 63.2% of final value)
Step response:
Key properties: - At t = τ: reaches 63.2% of final value - At t = 3τ: reaches 95% of final value - At t = 5τ: reaches 99.3% of final value (considered "settled")
Discrete-Time Implementation:¶
Continuous ODE:
Discrete form (Euler):
This is what we implement with prev() in Odibi!
Odibi Hands-On¶
Example 1: Tank Temperature (First-Order Response)¶
Process: Steam-heated tank - Input: Steam flow rate (step change) - Output: Tank temperature (first-order response) - Time constant τ = 10 minutes
# tank_temperature_fo.yaml
name: first_order_tank
engine: pandas
connections:
output:
type: local
path: ./output/first_order_tank.parquet
format: parquet
pipelines:
- name: fo_tank_pipeline
nodes:
- name: generate_temperature_response
read:
connection: null
format: simulation
options:
simulation:
scope:
start_time: "2024-01-01T00:00:00Z"
timestep: "1min"
row_count: 600 # 10 hours
seed: 42
entities:
count: 1
id_prefix: "TK-"
columns:
- name: entity_id
data_type: string
generator:
type: constant
value: "{entity_id}"
- name: timestamp
data_type: timestamp
generator:
type: timestamp
# ──────────────────────────────────
# PROCESS PARAMETERS
# ──────────────────────────────────
- name: time_constant_min
data_type: float
generator:
type: constant
value: 10.0
- name: process_gain
data_type: float
generator:
type: constant
value: 2.0
# ──────────────────────────────────
# INPUT (step change at t=60 min)
# ──────────────────────────────────
- name: minutes_elapsed
data_type: float
generator:
type: sequential
start: 0
step: 1
- name: steam_flow_lb_hr
data_type: float
generator:
type: derived
expression: "150.0 if minutes_elapsed >= 60.0 else 100.0"
# ──────────────────────────────────
# OUTPUT (first-order response)
# ──────────────────────────────────
- name: tank_temp_f
data_type: float
generator:
type: derived
expression: >
prev('tank_temp_f', 200.0) +
(1.0 / time_constant_min) *
(process_gain * steam_flow_lb_hr - prev('tank_temp_f', 200.0))
# ──────────────────────────────────
# SENSOR (with measurement noise)
# ──────────────────────────────────
- name: noise
data_type: float
generator:
type: range
min: -0.5
max: 0.5
distribution: normal
- name: temp_sensor_f
data_type: float
generator:
type: derived
expression: "tank_temp_f + noise"
# ──────────────────────────────────
# KPIs (calculated)
# ──────────────────────────────────
- name: percent_of_final_value
data_type: float
generator:
type: derived
expression: >
0.0 if minutes_elapsed < 60.0 else
((tank_temp_f - 200.0) / 100.0) * 100.0
write:
connection: output
Working example: /examples/cheme_course/L03_first_order/tank_temperature_fo.yaml
Expected output: - At t=60: step input occurs - At t=70 (τ later): reached 63.2% of new value - At t=90 (3τ later): reached 95% - At t=110 (5τ later): essentially settled
Example 2: Using ema() for Filtering¶
Use case: Noisy sensor data → smooth with exponential moving average
EMA formula:
Where α = smoothing factor (0 to 1): - α = 1.0: No filtering (raw data) - α = 0.1: Heavy filtering (slow response) - α relates to time constant: α ≈ Δt/τ
Working example: /examples/cheme_course/L03_first_order/ema_filtering.yaml
Trade-off: - More filtering (lower α) → Less noise BUT more lag - Less filtering (higher α) → More responsive BUT noisier
Exercises¶
See ../solutions/L03.md for full solutions.
All YAML files: /examples/cheme_course/L03_first_order/
Next Steps¶
You now know:
- ✅ First-order system theory and discrete implementation
- ✅ prev() and ema() stateful functions
- ✅ Exponential response characteristics (63.2%, 95%, settling)
- ✅ KPI calculations from time-series
Next lesson: 👉 L04: FOPTD Transfer Functions
We'll add process gain (K) and dead time (θ) to create realistic FOPTD models with parameterized YAML.
Lesson L03 complete!