Contents — find the section you need
Change parameters and verify
Open the panel, then press Run to load Python. You can stop execution and reset parameters. Results are computed on this device. No Python installation is required.
Local execution steps below are optional for reproducing the source results; they are not required for the browser experiment.
Background and reading guide
Background The roles of P, I and D. The browser Lab requires no Python installation.
Hands-on · Numerical simulation executed with Python 3.12.3; not hardware measurements.
A small executable model makes PID gain changes and actuator saturation easier to inspect. These results were calculated on September 7, 2026 with Python 3.12.3. They are numerical simulations, not measurements or an identified motor model.
Model and conditions
The plant is \ddot y+2\dot y+y=u. Output y and control u are normalized; time is in seconds. Initial output, velocity and integral are zero. The target is 1 from time zero, then 0.4 from 6 seconds. The step is 0.005 seconds over 0–12 seconds, giving 2,401 samples per case.
The controller is u=K_pe+K_iI-K_d\dot y_m, with e=r-y_m. Here y_m is the measured output. The derivative acts on it rather than the target. Baseline gains are K_p=3, K_i=2, K_d=1. Integration and differentiation explicitly use the time step; the plant uses semi-implicit Euler integration. See PID fundamentals for the principles.
Run the code
Save pid_lab.py in an empty working directory and run the following. It requires only the Python standard library and overwrites result files with the same names.
python3 --version
python3 pid_lab.py
It produces the CSV and summary JSON. To regenerate the figure, save and run plot_pid.py in the same directory; plotting was checked with matplotlib 3.6.3. CSV columns are scenario, time, target, output, control and integral.
Compare delay and saturation
The upper plot shows output; the lower plot shows control. The black line is the target. Scenario labels match the CSV, and aw means anti-windup.
| Scenario | Change | Output at 12 s | Integrated absolute error |
|---|---|---|---|
| nominal | No delay, control limited to ±3 | 0.4008 | 1.7913 |
| delay_0.4s | Measurement delayed by 0.4 s | 0.3883 | 1.8860 |
| limit_0.8_aw | Control ±0.8, conditional integration | 0.4003 | 3.3424 |
| limit_0.8_no_aw | Control ±0.8, unrestricted integration | 0.6602 | 5.0996 |
Integrated absolute error uses left-rectangle integration over 0–12 seconds. Its units are normalized output times seconds, not physical position error in meters. Inspect oscillation and control effort as well as the final sample.
Anti-windup does not increase actuator capability
At equilibrium this plant has y=u, so a 0.8 control limit cannot reach a target of 1. If the error keeps accumulating, the integral can demand excessive input even after the target falls to 0.4. The code rejects integration that would drive further into saturation, while allowing integration that helps leave it.
This changes the controller's internal state, not the motor or supply capacity. Making the target achievable is a separate decision.
Change one gain at a time
from pid_lab import simulate
for kp in (1., 3., 6.):
rows = simulate("gain", kp=kp)
print(kp, max(row[3] for row in rows if row[1] < 6))
Compare the peak during the initial target interval. Then vary only ki, and then only kd, also recording maximum control effort. Larger gains are not universally better; repeat the comparisons with delay and saturation.
Limits and next checks
The model excludes measurement noise, friction, quantization, communication jitter and derivative filtering. Halve the time step: if the response changes substantially, investigate numerical approximation first. Do not copy these gains into hardware without identifying the plant and matching units and time scales. Continue to MPC to study constraints within the control problem.
Run the same calculation locally
Extract the complete runnable source ZIP, or save the experiment entrypoint, generated kernels, and original PID source in one folder. PID uses the Python standard library; Kalman and ICP require NumPy. The original figure-generation commands remain available.
python3 experiment.py pid --parameters '{"kp":3,"ki":2,"kd":1,"delay":0,"limit":3,"antiwindup":true}' > result.json
Set delay to 0.4 or limit to 0.8 and compare IAE and final output with and without anti-windup.
Code, data and reproduction
The ZIP contains the same computation code as the browser, synthetic data and comparison cases. These are not physical measurements.
Download reproduction package · Instructions (EN/JA) · Files and experiment conditions (JSON)
Extract the ZIP into a new directory, then run:
python3 reproduce.py --experiment pid
This Lab compares 4 cases. PID uses Python’s standard library; Kalman/ICP require NumPy. See the instructions for dependencies and tested versions.
Comments
Please log in to post a comment
No comments yet.