Skip to content

PID Controller

The PID (Proportional-Integral-Derivative) controller is a classic feedback control algorithm widely used in aerospace, robotics, and industrial automation. Our implementation follows MATLAB/Simulink conventions and includes automatic MATLAB-style coefficient tuning.

PID Block Diagram

Theory

A PID controller computes the control signal \(u(t)\) based on the error \(e(t) = r(t) - y(t)\) between the reference \(r(t)\) and the measured output \(y(t)\):

\[ u(t) = K_p e(t) + K_i \int_0^t e(\tau)\,d\tau + K_d \frac{de(t)}{dt} \]

Components

Term Role Effect
Proportional (P) Reacts to current error Fast response, may cause steady-state error
Integral (I) Accumulates past error Eliminates steady-state error, can cause overshoot
Derivative (D) Predicts future error Dampens oscillations, sensitive to noise

Discrete Implementation

In discrete time with step \(\Delta t\):

\[ u_k = K_p e_k + K_i \sum_{j=0}^{k} e_j \Delta t + K_d \frac{y_{k-1} - y_k}{\Delta t} \]

Derivative on Measurement

Our implementation uses derivative on measurement (not on error), as is default in Simulink. This avoids "derivative kick" when the setpoint changes suddenly.

Anti-Windup

When the control output saturates (hits actuator limits), the integral term can "wind up" causing large overshoot. Our implementation includes conditional integration anti-windup: the integral is frozen when output is saturated.

Quick Start

import gymnasium as gym
from tensoraerospace.agent.pid import PID

# Create environment
env = gym.make('LinearLongitudinalB747-v0', number_time_steps=2000)

# Create PID controller
pid = PID(env=env, kp=-0.1, ki=-0.01, kd=-0.05, dt=0.01)

# Control loop
obs, info = env.reset()
for _ in range(2000):
    reference = info['reference']
    measurement = obs[3]  # theta (pitch angle)
    action = pid.select_action(reference, measurement)
    obs, reward, done, truncated, info = env.step([action])

MATLAB-Style Automatic Tuning

The tune_matlab_style() method automatically finds optimal PID coefficients using global optimization, similar to MATLAB's PID Tuner in Simulink.

How It Works

  1. Extracts state-space model (A, B, C, D matrices) from the environment
  2. Determines loop sign automatically using DC gain analysis
  3. Runs differential evolution to minimize a cost function
  4. Optimizes for robustness: considers both step response AND tracking performance

Tuning Modes

Optimizes for clean step response with fast settling and minimal overshoot.

pid = PID(env=env)
result = pid.tune_matlab_style(
    track_state_idx=3,      # Index of theta state
    mode="step_response",
    target_settling_time=5.0,
    target_overshoot=10.0,
    n_iterations=100
)
print(result)
# MATLABTuneResult(Kp=-0.1234, Ki=-0.0456, Kd=-0.0789, ...)

Cost function minimizes: - Settling time (time to reach ±2% of final value) - Overshoot above target threshold - Steady-state error - Integral Squared Error (ISE) - Control effort and saturation

Also considers tracking performance as secondary objective (25% weight) to ensure the tuned PID doesn't fail on sinusoidal signals.

Optimizes for accurate following of time-varying signals (sinusoids, ramps).

pid = PID(env=env)
result = pid.tune_matlab_style(
    track_state_idx=3,
    mode="tracking",
    n_iterations=100
)

Cost function minimizes: - Root Mean Square Error (RMSE) - Integral Absolute Error (IAE) - Phase lag - Control effort and saturation

Also considers step response as secondary objective (25% weight) to ensure stability on sudden reference changes.

Usage Example with B747

import gymnasium as gym
import numpy as np
from tensoraerospace.agent.pid import PID
from tensoraerospace.signals.standard import unit_step
from tensoraerospace.utils import generate_time_period

# Setup
dt = 0.01
tp = generate_time_period(tn=20, dt=dt)
n_steps = len(tp)

# Create step reference signal (5 degrees)
reference = unit_step(degree=5, tp=tp, time_step=100, output_rad=False)

env = gym.make(
    'LinearLongitudinalB747-v0',
    number_time_steps=n_steps,
    initial_state=np.array([[0], [0], [0], [0]]),
    reference_signal=reference.reshape(1, -1),
    track_state='theta'
)

# Create and tune PID
pid = PID(env=env, dt=dt)
result = pid.tune_matlab_style(
    track_state_idx=3,        # theta index
    mode="step_response",
    target_settling_time=5.0,
    target_overshoot=10.0,
    n_iterations=150,
    verbose=True
)

print(f"Tuned PID: Kp={pid.kp:.4f}, Ki={pid.ki:.4f}, Kd={pid.kd:.4f}")
print(f"Settling time: {result.settling_time:.2f}s")
print(f"Overshoot: {result.overshoot:.1f}%")

Output Example

📊 MATLAB-Style PID Optimization (Step Response)
------------------------------------------------------------
   System dimension: 4 states
   Matrices: A=(4, 4), B=(4, 1), C=(4, 4), D=(4, 1)
   Simulation steps: 2000, dt: 0.01s
   Mode: Step Response
   Target settling time: 5.0s
   Target overshoot: 10.0%
   DC Gain: -0.0421

   🔄 Running optimization (150 iterations)...
   Optimization: 100%|██████████| 150/150 [00:45<00:00]

    Optimization completed!
   Kp=-0.1523, Ki=-0.0234, Kd=-0.0891
   [Primary step] Settling time: 4.32s
   [Primary step] Overshoot: 8.45%
   [Primary step] Static error: 0.0012
   [Secondary sine] RMSE: 0.3421

Key Parameters

Parameter Description Default
kp Proportional gain 1.0
ki Integral gain 1.0
kd Derivative gain 0.5
dt Time step (seconds) 0.01
env Gymnasium environment None

tune_matlab_style() Parameters

Parameter Description Default
track_state_idx Index of state to control Required
mode "step_response" or "tracking" "step_response"
target_settling_time Desired settling time (s) Auto
target_overshoot Max acceptable overshoot (%) 10.0
n_iterations Optimization iterations 100
verbose Print progress True

Comparison with Other Methods

Method Pros Cons Best For
PID Simple, fast, well-understood Limited performance on complex dynamics Linear systems, quick prototyping
MPC Handles constraints, optimal Computationally expensive Constrained systems, trajectories
RL (SAC/PPO) Adapts to nonlinear dynamics Requires training, less interpretable Complex nonlinear systems

Practical Tips

When to Use PID vs Other Methods

  • Use PID when the system is approximately linear and you need a simple, interpretable controller
  • Use MPC when you have explicit constraints on states or controls
  • Use RL when the dynamics are highly nonlinear or unknown

Unit Consistency

Ensure your reference signal and observations use the same units. Our tuner automatically handles degree/radian conversion for B747 environments.

Starting Point

For most aerospace systems, start with mode="step_response" and target_overshoot=10.0. This gives a good balance between speed and stability.

API Reference

PID(env=None, kp=1.0, ki=1.0, kd=0.5, dt=0.01)

Bases: BaseRLModel

PID controller implementation for control systems.

This class implements a PID (Proportional-Integral-Derivative) controller for automatic control systems. The PID controller uses proportional (P), integral (I), and derivative (D) components to compute the control signal.

Parameters:

Name Type Description Default
env Env | None

Gymnasium environment. Defaults to None.

None
kp float

Proportional gain. Defaults to 1.

1.0
ki float

Integral gain. Defaults to 1.

1.0
kd float

Derivative gain. Defaults to 0.5.

0.5
dt float

Time step (time difference between consecutive updates). Defaults to 0.01.

0.01

Attributes:

Name Type Description
kp float

Proportional gain.

ki float

Integral gain.

kd float

Derivative gain.

dt float

Time step.

integral float

Accumulated integral value.

prev_error float

Previous error value for derivative computation.

env

Gymnasium environment.

Example

pid = PID(env=env, kp=0.1, ki=0.01, kd=0.05, dt=1) control_signal = pid.select_action(10, 7)

Initialize PID controller parameters.

select_action(setpoint, measurement)

Compute and return control signal based on setpoint and measurement.

This method uses the current measurement and setpoint to compute the error, then applies the PID algorithm to compute the control signal.

Parameters:

Name Type Description Default
setpoint float

Desired value that the system should reach.

required
measurement float

Current measured value.

required

Returns:

Name Type Description
float float

Control signal computed by the PID controller.

Example

pid = PID(env=env, kp=0.1, ki=0.01, kd=0.05, dt=1) control_signal = pid.select_action(10, 7) print(control_signal)

reset()

Reset PID controller internal state.

Resets integral accumulator and previous error to zero. Should be called before starting a new control episode.

tune_matlab_style(track_state_idx=0, target_settling_time=None, target_overshoot=10.0, n_iterations=100, verbose=True, mode='step_response', control_input_idx=0)

MATLAB-style PID tuning using state-space model optimization.

This method implements PID tuning similar to MATLAB Simulink PID Tuner. It requires the environment to have a model with state-space matrices (A, B, C, D).

Two optimization modes are available: - "step_response": Primary objective is step response (settling time, overshoot), with an additional secondary check on tracking (sinusoid) to avoid oscillatory controllers. - "tracking": Primary objective is tracking (RMSE), with an additional secondary check on step response to avoid controllers that behave poorly on setpoint steps.

Parameters:

Name Type Description Default
track_state_idx int

Index of the state to track (in output vector). Defaults to 0.

0
target_settling_time float

Target settling time in seconds. If None, uses 50% of simulation time. Only used in "step_response" mode.

None
target_overshoot float

Target maximum overshoot in percent. Defaults to 10.0. Only used in "step_response" mode.

10.0
n_iterations int

Number of optimization iterations. Defaults to 100.

100
verbose bool

Whether to print progress. Defaults to True.

True
mode str

Optimization mode. Options: - "step_response": Minimize settling time, overshoot, static error - "tracking": Minimize RMSE and phase lag for signal tracking Defaults to "step_response".

'step_response'
control_input_idx int

Index of the control input column of B used to compute the DC gain. For MIMO plants where the tracked output is not controlled by the first input, set this to the correct column. Defaults to 0 (backward compatible).

0

Returns:

Name Type Description
MATLABTuneResult MATLABTuneResult

Optimized PID parameters and performance metrics.

Raises:

Type Description
StateSpaceNotAvailable

If environment does not have state-space matrices.

ValueError

If environment is not set or invalid mode.

Example

Step response optimization

result = pid.tune_matlab_style(track_state_idx=0, mode="step_response")

Tracking optimization (for sinusoids, etc.)

result = pid.tune_matlab_style(track_state_idx=0, mode="tracking")

get_param_env()

Get environment and agent parameters for saving.

Returns:

Name Type Description
dict Dict[str, Dict[str, Any]]

Dictionary with environment and agent policy parameters.

save(path=None)

Save PID model to the specified directory.

If path is not specified, creates a directory with current date and time.

Parameters:

Name Type Description Default
path str

Path where the model will be saved. If None, creates a directory with current date and time.

None

Returns:

Name Type Description
Path Path

Path to the directory with saved model.

__load(path) classmethod

Load PID model from the specified directory.

Parameters:

Name Type Description Default
path str or Path

Path to directory with saved model.

required

Returns:

Name Type Description
PID 'PID'

Loaded PID model instance.

Raises:

Type Description
TheEnvironmentDoesNotMatch

If agent type does not match expected.

from_pretrained(repo_name, access_token=None, version=None) classmethod

Load pretrained model from local path or Hugging Face Hub.

Parameters:

Name Type Description Default
repo_name str

Repository name or local path to model.

required
access_token str

Access token for Hugging Face Hub.

None
version str

Model version to load.

None

Returns:

Name Type Description
PID 'PID'

Loaded PID model instance.

MATLABTuneResult(kp, ki, kd, settling_time, overshoot, ise, method='MATLAB-Style') dataclass

Result of MATLAB-style PID tuning.

Attributes:

Name Type Description
kp float

Proportional gain.

ki float

Integral gain.

kd float

Derivative gain.

settling_time float

Achieved settling time in seconds.

overshoot float

Achieved overshoot in percent.

ise float

Integral Squared Error.

method str

Tuning method name.

StateSpaceNotAvailable

Bases: Exception

Exception raised when state-space matrices are not available.

This exception is raised when trying to use MATLAB-style tuning methods on an environment that does not provide state-space matrices (A, B, C, D).