Dynamic Models
This example demonstrates dynamic models and state transition matrices used in Kalman filtering and target tracking.
Overview
Dynamic models describe how a target’s state evolves over time. They are fundamental to:
Kalman filtering: Prediction step requires state transition
Target tracking: Motion models for different target types
Navigation: INS mechanization and error propagation
Simulation: Generating realistic target trajectories
Key Concepts
- State Transition Matrix (Phi)
The discrete-time matrix that propagates state from time k to k+1:
x[k+1] = Phi * x[k] + process_noise- Process Noise Covariance (Q)
Captures uncertainty in the motion model due to unknown accelerations or model mismatch.
- Continuous vs Discrete Time
Continuous: differential equations (dx/dt = F*x)
Discrete: difference equations (x[k+1] = Phi*x[k])
Conversion: Phi = exp(F*dt)
State Estimation: The state transition matrix propagates the state estimate and covariance through time, shown as uncertainty ellipses.
Models Demonstrated
- Constant Velocity (CV)
State: [x, vx, y, vy, z, vz]
Assumes constant velocity between updates
Process noise models unknown accelerations
- Drift Functions
Continuous-time rate of change
Position changes at velocity rate
Velocity remains constant (for CV model)
3D Tracking: Dynamic models enable prediction of 3D target trajectories using the state transition matrix.
Code Highlights
The example demonstrates:
State transition matrix computation with
f_constant_velocity()Process noise covariance with
diffusion_constant_velocity()Drift function evaluation with
drift_constant_velocity()Continuous to discrete time conversion
Source Code
1"""
2Demonstration of dynamic models and state transition matrices.
3
4This example shows:
5- Continuous and discrete-time system models
6- State transition matrices (Phi matrices)
7- Process noise covariance (Q matrices)
8- Kalman filter compatibility
9"""
10
11from pathlib import Path
12
13import numpy as np
14import plotly.graph_objects as go
15
16from pytcl.dynamic_models.continuous_time import (
17 diffusion_constant_velocity,
18)
19from pytcl.dynamic_models.discrete_time import f_constant_velocity
20
21SHOW_PLOTS = True
22
23
24def demo_state_transition_matrix() -> None:
25 """Demonstrate state transition matrix properties."""
26 print("\n" + "=" * 60)
27 print("State Transition Matrices")
28 print("=" * 60)
29
30 dt = 0.1 # Time step
31
32 # Get state transition matrix for constant velocity model
33 # Returns 6x6 matrix for 3D position/velocity
34 phi = f_constant_velocity(dt)
35
36 print(f"\nTime step: {dt}s")
37 print(f"State transition matrix (Phi) shape: {phi.shape}")
38 print("Matrix (first 3x3 block):")
39 print(phi[:3, :3])
40
41 # The matrix has a block structure
42 # [I dt*I]
43 # [0 I ]
44 # where I is 3x3 for position and velocity in 3D
45
46
47def demo_process_noise() -> None:
48 """Demonstrate process noise matrices."""
49 print("\n" + "=" * 60)
50 print("Process Noise Covariance Matrices")
51 print("=" * 60)
52
53 dt = 0.1
54 sigma_v = 1.0 # Process noise standard deviation
55
56 # Get process noise covariance matrix
57 q_matrix = diffusion_constant_velocity(dt, sigma_v)
58
59 print(f"\nTime step: {dt}s")
60 print(f"Process noise std: {sigma_v} m/s")
61 print(f"Process noise matrix (Q) shape: {q_matrix.shape}")
62
63 # Properties
64 print(f"\nProcess noise norm: {np.linalg.norm(q_matrix):.6f}")
65
66
67def demo_drift_matrix() -> None:
68 """Demonstrate drift (mean) functions."""
69 print("\n" + "=" * 60)
70 print("Drift Functions")
71 print("=" * 60)
72
73 # Drift function takes a state vector and returns rate of change
74 # For constant velocity, position changes at velocity rate
75 state = np.array([0.0, 1.0, 0.0, 2.0, 0.0, 3.0]) # 3D pos/vel
76
77 from pytcl.dynamic_models.continuous_time.dynamics import (
78 drift_constant_velocity as drift_cv,
79 )
80
81 drift_result = drift_cv(state)
82
83 print(f"\nExample state (3D position + velocity):")
84 print(f" Position: {state[0::2]}")
85 print(f" Velocity: {state[1::2]}")
86 print(f"\nDrift (rate of change) result:")
87 print(f" {drift_result}")
88
89 # Expected: [vel_1, 0, vel_2, 0, vel_3, 0]
90 # showing that position changes at velocity rate and velocity doesn't change
91
92
93def demo_continuous_to_discrete_conversion() -> None:
94 """Demonstrate continuous to discrete time conversion principle."""
95 print("\n" + "=" * 60)
96 print("Continuous to Discrete Conversion")
97 print("=" * 60)
98
99 # For a constant velocity model in 1D:
100 # Continuous: dx/dt = v, dv/dt = 0
101 # Or in matrix form: [dx/dt; dv/dt] = [0 1; 0 0] * [x; v]
102
103 # Discrete approximation: state[k+1] = Phi * state[k]
104 # where Phi = exp(F * dt) ≈ I + F*dt for small dt
105
106 F = np.array([[0.0, 1.0], [0.0, 0.0]]) # Continuous F matrix
107 dts = [0.05, 0.1, 0.2, 0.5]
108
109 print("\nContinuous F matrix (1D constant velocity):")
110 print(F)
111
112 print("\nDiscrete Phi matrices (Phi ≈ I + F*dt):")
113 print("Time Step | Phi[0,1] Value")
114 print("-" * 30)
115
116 phi_values = []
117 for dt_val in dts:
118 # For constant velocity: Phi = [[1, dt], [0, 1]]
119 phi_approx = np.eye(2) + F * dt_val
120 phi_values.append(phi_approx[0, 1])
121 print(f"{dt_val:>8} | {phi_approx[0, 1]:>14.6f}")
122
123 # Plot
124 if SHOW_PLOTS:
125 fig = go.Figure()
126
127 fig.add_trace(
128 go.Scatter(
129 x=dts,
130 y=phi_values,
131 mode="lines+markers",
132 name="Phi[0,1]",
133 line=dict(color="purple", width=2),
134 marker=dict(size=8),
135 )
136 )
137
138 fig.update_layout(
139 title="Discrete State Transition Element vs Time Step",
140 xaxis_title="Time Step (s)",
141 yaxis_title="Phi[0,1] Value",
142 height=400,
143 )
144
145 if SHOW_PLOTS:
146 fig.show()
147 else:
148 fig.write_html(str(OUTPUT_DIR / "dynamic_models_demo.html"))
149
150
151def main() -> None:
152 """Run all demonstrations."""
153 print("\n" + "=" * 60)
154 print("Dynamic Models Demonstration")
155 print("=" * 60)
156
157 demo_state_transition_matrix()
158 demo_process_noise()
159 demo_drift_matrix()
160 demo_continuous_to_discrete_conversion()
161
162 print("\n" + "=" * 60)
163 print("Demonstration Complete")
164 print("=" * 60)
165
166
167OUTPUT_DIR = Path("docs/_static/images/examples")
168OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
169
170if __name__ == "__main__":
171 main()
Running the Example
python examples/dynamic_models_demo.py
See Also
kalman_filter_comparison - Kalman filter implementations
multi_target_tracking - Multi-target tracking
tracking_3d - 3D tracking example