🎯 Core Idea to Anchor Everything
“A dynamic system is anything where the future depends on the current state.”
Examples:
- temperature
- velocity
- capacitor voltage
- population
Let's explore 1st ODE Dynamics Systems¶
Cooling System Example¶
“Hot object cooling down”
Model:
$\frac{dT}{dt}=−k(T−T_{env})$
same as:
$\frac{dT}{dt}=k(T_{env}-T)$
Analytical Solution:
$T(t)=T_{env}+(T_0−T_{env})e^{−kt}$
👉 Emphasize:
- exponential decay
- time constant
# Plot Analytical Solution
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(0, 10, 100)
T_env = 20
T0 = 80
k = 0.5
T = T_env + (T0 - T_env) * np.exp(-k*t) # solution is given for now
plt.plot(t, T)
plt.title("Analytical Solution (Cooling)")
plt.xlabel("Time")
plt.ylabel("Temperature")
plt.show()
# Numerical Simulation (Euler Method)
dt = 0.1
t_num = np.arange(0, 10, dt)
T_num = np.zeros_like(t_num)
T_num[0] = T0
# Euler Method
for i in range(len(t_num)-1):
dTdt = -k * (T_num[i] - T_env)
T_num[i+1] = T_num[i] + dt * dTdt
plt.plot(t, T, label="Analytical")
plt.plot(t_num, T_num, '--', label="Euler")
plt.legend()
plt.title("Analytical vs Numerical")
plt.show()
🧠 Ask:
- “Why are they slightly different?”
- “What happens if dt is larger?”
Numerical method = approximation
- “We simulate step by step”
Tradeoff
- smaller dt → more accurate, more computation
# Another numerical method option
from scipy.integrate import solve_ivp
def model(t, T):
return -k * (T - T_env)
sol = solve_ivp(model, [0, 10], [T0], t_eval=t)
plt.plot(t, T, label="Analytical")
plt.plot(sol.t, sol.y[0], '--', label="solve_ivp")
plt.legend()
plt.show()
By default solve_ip uses RK45 (Runge-Kutta 4th/5th order):
- smarter than Euler
- takes adaptive step sizes
- balances accuracy vs speed
sol = solve_ivp(rc_model, [0, 5], [0], method='RK45')
Other methods available:
- 'RK23' → lower accuracy
- 'DOP853' → high accuracy
- 'Radau', 'BDF' → stiff systems
RC Circuit Example¶
Model:
$\frac{dV}{dt}=\frac{1}{RC}(V_{in}−V)$
same as:
$\frac{dV}{dt}=-\frac{1}{RC}(V-V_{in})$
Analytical Solution:
$V(t)=V_{in}+(V_0−V_{in})e^{\frac{-t}{\tau}}$
👉 Emphasize:
- exponential decay
- time constant
# Numerical Solution
R = 1000 # ohms
C = 0.001 # farads
Vin = 5 # step input
V0 = 0
t = np.linspace(0, 5, 200)
# Analytical Solution
tau = R*C
V = Vin + (V0 - Vin) * np.exp(-t/(tau)) # solution is given for now
# Numerical Solution
def rc_model(t, V):
return (Vin - V) / (R * C)
from scipy.integrate import solve_ivp
sol = solve_ivp(rc_model, [0, 5], [V0], t_eval=t)
plt.plot(t, V, label="Analytical")
plt.plot(sol.t, sol.y[0], '--', label="solve_ivp")
plt.title("RC Circuit Response")
plt.xlabel("Time")
plt.ylabel("Voltage")
plt.legend()
plt.show()
Velocity (Motion System) Example¶
Model (with drag):
Free Fall with air resistance¶
$\frac{dv}{dt}=-\frac{b}{m} * [v - \frac{m}{b}g]$
same as:
$\frac{dv}{dt}=\frac{b}{m} * [\frac{m}{b}g - v]$
Analytical Solution:
$v(t) = \frac{m}{b}g + (v_0 − \frac{m}{b}g) e^{-\frac{b}{m}t}$
👉 Emphasize:
- exponential decay
- time constant
m = 1.0
b = 0.5
v0 = 0
g = 9.8
# Analytical Solution
v_analytical = (m/b)*g + (v0 - ((m/b)*g)) * np.exp(-(b/m)*t)
# Numerical Solution
def velocity_model(t, v):
return -(b/m) * (v - (m/b)*g)
t = np.linspace(0, 10, 200)
sol = solve_ivp(velocity_model, [0, 10], [0], t_eval=t)
plt.plot(t, v_analytical, label="Analytical")
plt.plot(t, sol.y[0], '--', label="solve_ivp")
plt.title("Velocity with Drag")
plt.xlabel("Time")
plt.ylabel("Velocity")
plt.legend()
plt.show()
🧠 Big Teaching Moment
“Different physical systems—same mathematical model.”
🎯 One-Liner to Close
“If you understand one first-order system, you understand them all.”
Systems that Introduce Inertia and Energy Exchange¶
(aka 2nd ODE)
🧠 Canonical Form (anchor everything here)
Write this once and keep coming back to it:
$\ddot{x} + 2 \xi \omega_n \dot{x} + \omega_n^2 x = \omega_n^2 x_{in}$
👉 This is your “unifying equation”
m = 1.0
c = 0.5 # change values between 0.1 and 2.0
k = 4.0
F = 1.0
t = np.linspace(0, 10, 300)
def msd(t, y):
x, v = y
dxdt = v
dvdt = (1/m)*(F - c*v - k*x) # step force = 1
return [dxdt, dvdt]
sol = solve_ivp(msd, [0, 10], [0, 0], t_eval=t)
plt.plot(sol.t, sol.y[0])
plt.title("Mass-Spring-Damper Response")
plt.xlabel("Time")
plt.ylabel("Position")
plt.grid()
plt.show()
🧠 Teaching Points
- overshoot
- oscillation
- damping
L = 1.0
R = 0.5
C = 0.25
def rlc(t, y):
q, i = y
dqdt = i
didt = (1/L)*(1 - R*i - (1/C)*q)
return [dqdt, didt]
sol = solve_ivp(rlc, [0, 10], [0, 0], t_eval=t)
plt.plot(sol.t, sol.y[0])
plt.title("RLC Circuit Response")
plt.xlabel("Time")
plt.ylabel("Charge")
plt.grid()
plt.show()
🧠 Teaching Points
same behavior as mechanical system
energy stored in:
- inductor
- capacitor
Velocity/Motion¶
Model:
$m\ddot{x} = F - c\dot{x} - kx$
Let:
- velocity = $\dot{x}$
👉 same as mass-spring-damper, but interpreted as motion
def motion(t, y):
x, v = y
dxdt = v
dvdt = (1/m)*(10 - c*v - k*x)
return [dxdt, dvdt]
sol = solve_ivp(motion, [0, 10], [0, 0], t_eval=t)
plt.plot(sol.t, sol.y[0])
plt.title("Position with Force, Drag, and Spring")
plt.xlabel("Time")
plt.ylabel("Position")
plt.grid()
plt.show()
🎯 Unify the Three (VERY IMPORTANT MOMENT)
| System | Equation |
|---|---|
| Mechanical | $m\ddot{x} + c \dot{x} + k x = F $ |
| Electrical | $L\ddot{q} + R \dot{q} + \frac{1}{C} q = V $ |
| Motion | same as mechanical |
🔥 Say This Clearly
“These are the SAME system with different variables.”