The timestep becomes part of the system
Fixed-step solvers are used when the simulation must update at a known rate. This is common in flight software, digital control, real-time simulation, hardware-in-the-loop testing, and embedded control systems.
The danger is that a fixed-step method does not automatically reduce the timestep when the dynamics become fast, sensitive, or oscillatory. The engineer chooses \(\Delta t\), and that choice affects the behaviour of the simulated system.
One problem, six fixed-step lessons
A discrete update fails when angle is not advanced using angular velocity.
Forward Euler is compared against the analytical rotational response.
A digital controller updates torque only at sampled time instants.
The same gains are tested across \(\Delta t\) to find the stability boundary.
Large timestep creates energy growth even when the model and controller are unchanged.
The same sampled-data issue appears in a simple relative-motion GNC example.
Missing \(\omega\): discrete update error
In rotational motion, angle must be advanced using angular velocity. The fixed-step update is:
A common discrete mistake is to keep the angle unchanged, or to update it without the correct angular velocity term. The simulation may still run, but the physics is broken.
Euler integration vs reality
For constant torque, the rotational dynamics are:
Forward Euler uses straight-line updates. With a small timestep it can look close to the analytical result. With a large timestep, it visibly drifts.
PD controller in discrete time
A digital controller does not react continuously. It samples the state, computes a torque, then holds that torque until the next update.
Stability boundary: same gains, different timestep
This is the key fixed-step lesson. Keep \(K_p\) and \(K_d\) fixed, then sweep \(\Delta t\). The controller did not change, the model did not change, but the sampled simulation can move from stable to oscillatory to unstable.
| Δt sample | Behaviour | Peak |θ| |
|---|
Numerical instability caused by timestep
The equations do not change. The controller does not change. Only the timestep changes. If the coarse-step result grows energy while the fine-step result decays, the instability is numerical rather than physical.
Phase lag due to timestep
A sampled controller waits until the next update before reacting. The torque therefore appears as a stair-step signal. As \(\Delta t\) increases, the control action becomes more delayed. Delay behaves like additional phase lag in a control system.
Aliasing: seeing the wrong dynamics
If a fast oscillation is sampled too slowly, the sampled points can appear to represent a different, slower frequency. This is aliasing. In engineering simulation, aliasing can make the system appear to have dynamics that are not actually present.
Chaser control: discrete GNC example
A chaser approaches a target using a sampled PD-like controller. The relative-motion model is intentionally simple so the timestep effect is easy to see.
Fixed-step code blocks
These snippets mirror the page logic. Keep them short so the reader can connect each code block to one specific engineering idea.
# Fixed-step rotational PD controller
import numpy as np
import matplotlib.pyplot as plt
Kp = 20.0
Kd = 4.0
I = 1.0
dt = 0.05
t_final = 8.0
theta = 1.0
omega = 0.0
T = np.arange(0, t_final + dt, dt)
TH = []
OM = []
TAU = []
for t in T:
tau = -Kp*theta - Kd*omega
TH.append(theta)
OM.append(omega)
TAU.append(tau)
omega = omega + (tau/I)*dt
theta = theta + omega*dt
plt.plot(T, TH, label='theta')
plt.step(T, TAU, where='post', label='sampled torque')
plt.grid(True)
plt.legend()
plt.show()
% Fixed-step Euler simulation for attitude control
Kp = 20;
Kd = 4;
I = 1;
dt = 0.05;
tf = 8;
T = 0:dt:tf;
theta = zeros(size(T));
omega = zeros(size(T));
tau = zeros(size(T));
theta(1) = 1;
omega(1) = 0;
for k = 1:length(T)-1
tau(k) = -Kp*theta(k) - Kd*omega(k);
omega(k+1) = omega(k) + (tau(k)/I)*dt;
theta(k+1) = theta(k) + omega(k+1)*dt;
end
figure;
plot(T, theta, 'LineWidth', 1.8); hold on;
stairs(T, tau, '--', 'LineWidth', 1.2);
grid on;
xlabel('Time [s]');
ylabel('Response');
legend('theta', 'sampled torque');
title('Fixed-step discrete-time PD response');
# Aliasing demo
import numpy as np
import matplotlib.pyplot as plt
f = 6.0 # true frequency [Hz]
dt = 0.13 # sampling timestep [s]
tf = 2.0
fs = 1/dt
print('Sampling frequency:', fs)
print('Nyquist frequency:', fs/2)
fine_t = np.linspace(0, tf, 3000)
sample_t = np.arange(0, tf + dt, dt)
x_true = np.sin(2*np.pi*f*fine_t)
x_sample = np.sin(2*np.pi*f*sample_t)
plt.plot(fine_t, x_true, label='true signal')
plt.plot(sample_t, x_sample, 'o--', label='sampled signal')
plt.grid(True)
plt.legend()
plt.show()
Fixed-step simulation is powerful, but timestep is a design choice
The equations may represent the real physics, but the discrete update can still distort the response.
A digital controller only reacts at update instants, so the torque naturally includes delay and phase lag.
If the timestep is too large, aliasing can make fast dynamics appear as a different slower motion.