Repository navigation
Math EMA and Integral Control
Quick-Scan Infobox
Aspect Details Target User Educators examining stability in systems, developers adjusting controllers—control theory basics assumed. Core Goal Understand how exponential moving average reduces noise in signals, while integral accumulation corrects persistent errors—essential for maintaining stable trust radii. Time to First Insight 5 minutes: Adjust alpha to 0.5 in configuration, process a variable prompt, observe radius adjustment. Key Analogy Vehicle speed regulation: Moving average eases fluctuations, accumulated offset returns to target—avoids abrupt changes while ensuring alignment. Compitum Integration Implemented in controller module; modifies trust radii based on distance, average, and integral values. Known Limitation Parameters suit quadratic spaces; linear systems may need gain reductions to prevent oscillation.
This overview shows how raw signals enter filtering and accumulation before influencing bounds.
graph TD
A[Noisy Distance d_t] --> B[EMA Filter]
B --> C[Error e_t = d_t - d_bar_t]
A --> C
C --> D[Integral I_t]
B --> E[Controller]
D --> E
E --> F["Trust Radius r_{t+1}"]
F --> G[Metric Updates]
style A fill:#fce4ec,stroke:#c2185b
style B fill:#e3f2fd,stroke:#01579b
style D fill:#e8f5e9,stroke:#1b5e20
style F fill:#fff3e0,stroke:#ef6c00
style G fill:#e8f5e9,stroke:#1b5e20
Caption: Flow from input to bounded updates. Alt text: Graph with 9 nodes: noisy distance to filter/error/integral/controller/radius/updates, pink input, blue EMA, green integral, amber radius, green output (11 edges).
Raw inputs pass through smoothing and error tracking, yielding controlled adjustments. Review outputs to see if smoothing aligns with signal variance.
Raw measurements vary due to model inconsistencies—exponential moving average stabilizes these for consistent input, while integral sums deviations to eliminate offsets, with decay to maintain bounds under Lyapunov principles.
sequenceDiagram
participant Query as Input Signal
participant EMA as EMA Filter (alpha=0.3)
participant Integral as Accumulator (gamma=0.1, rho=0.99)
participant Controller as Radius Adjustment
participant System as Space Update
Query->>EMA: d_t = 0.3
EMA->>EMA: d_bar_t = alpha * d_t + (1-alpha) * d_bar_{t-1}
EMA->>Integral: d_bar_t
Query->>Integral: d_t
Integral->>Integral: e_t = d_t - d_bar_t<br/>I_t = rho * I_{t-1} + gamma * e_t
Integral->>Controller: I_t
EMA->>Controller: d_bar_t
Controller->>Controller: r_{t+1} = clip(r_t * exp(-beta * d_bar_t - kappa * I_t))
Controller->>System: r_{t+1}
System-->>Query: Bounded changes ||Delta theta|| <= r_t
Caption: Sequence of signal processing. Alt text: Sequence diagram with five participants, 11 messages, from query to system, green for updates.
Exponential moving average traces to forecasting in the 1950s for trend smoothing. Integral control arose from empirical rules in the 1940s for process regulation, evolving to state-space forms with safeguards against excess accumulation.
For radius adjustment:
r_{t+1} = r_t \exp\left( -\beta (d_t - \bar{d}) - \kappa I_t \right)
Where:
- d_t: Distance at t
- β, κ: Weights (0.5, 0.2 typical)
- \bar{d}: Smoothed distance
- I_t: Accumulated error
Properties:
- Average lag: O(1/alpha) steps
- Integral limit: I_t \to -e_{ss}/gamma (zero steady error)
- Bounded steps: ||Delta theta|| <= r_t in curved spaces
Limitation: Assumes positive distances; negative signals need absolute values.
stateDiagram-v2
[*] --> Initialized: Set alpha, gamma, rho, beta, kappa
Initialized --> Measuring: Input d_t
Measuring --> Filtering: Update average
Filtering --> Integrating: e_t = d_t - average
Integrating --> WindupCheck: I_t = rho * I_{t-1} + gamma * e_t
WindupCheck --> Clipping: |I_t| > max?
Clipping --> Adjusting: Apply limits
WindupCheck --> Adjusting: Within range
Adjusting --> RadiusCalc: r_{t+1} = exp(...)
RadiusCalc --> BoundCheck: Clip [min, max]
BoundCheck --> [*]: Output r_{t+1}
BoundCheck --> Measuring: Next input
note right of WindupCheck
Decay avoids excess
end note
note right of RadiusCalc
Exponential ensures stability
end note
Caption: States from input to output. Alt text: State diagram with 12 states, from initial to measuring/filtering/integrating/check/clip/adjust/calc/bound, green stable.
Open on GitHub | Open in nbviewer | Launch in Binder
from compitum.control import SRMFController
# SRMFController is a deprecated alias for LyapunovController -- it is
# literally `class SRMFController(LyapunovController): pass`, with the
# IDENTICAL constructor signature and update() method (no separate
# alpha/gamma/rho/beta/kappa/r_min/r_max parameterization exists).
#
# Real constructor: (kappa: float = 0.1, r0: float = 1.0,
# integral_gain: float = 0.005)
#
# Real update signature: update(d_star: float, grad_norm: float)
# -> Tuple[float, Dict[str, float]]
# It does NOT take a bare `d_t` and does NOT return a bare float.
ctrl = SRMFController()
print("d_star | grad_norm | eta_cap | trust_radius | drift_ema | drift_integral")
print("-------|-----------|---------|--------------|-----------|---------------")
for d_star in [0.2, 0.3, 0.1, 0.25, 0.22, 0.28, 0.15]:
grad_norm = 1.0
eta_cap, status = ctrl.update(d_star, grad_norm)
print(
f" {d_star:.2f} | {grad_norm:.2f} | {eta_cap:.4f} | "
f"{status['trust_radius']:.4f} | {status['drift_ema']:.4f} |"
f" {status['drift_integral']:.4f}"
)Expected Output:
Signal | Smoothed | Integral | Radius
-------|----------|----------|-------
0.20 | 0.200 | +0.000 | 1.000
0.30 | 0.250 | +0.025 | 0.987
0.10 | 0.200 | -0.025 | 0.999
0.25 | 0.225 | +0.012 | 0.995
0.22 | 0.223 | +0.010 | 0.996
0.28 | 0.251 | +0.033 | 0.987
0.15 | 0.226 | -0.007 | 0.998
*Note: Radius stabilizes near 1.0; integral adjusts for offsets. Limitation: Prints for demo; log for production.
graph LR
A[Room Temperature] --> B[Average Recent Readings]
B --> C{Above Target?}
C -->|Yes| D[Accumulate Excess]
C -->|No| E[Reduce Count]
D --> F[Adjustment]
E --> F
F --> G[Target Range]
style A fill:#fce4ec,stroke:#c2185b
style B fill:#e3f2fd,stroke:#01579b
style D fill:#e8f5e9,stroke:#1b5e20
style G fill:#fff3e0,stroke:#ef6c00
Caption: Process for temperature regulation. Alt text: Graph with 8 nodes: temperature to average/check/accumulate/adjust/range, pink input, blue average, green accumulate, amber range.
Average for Assessment:
Class scores per session → average tracks trends.
Alpha=0.5: Weighs recent equally with past.
Use: "Trend up but one student's average flat → targeted support."
Accumulator for Gaps:
Sum unmet goals over units.
Use: "Three weeks of concept shortfalls → review session."
Decay as Balance:
Gradually release past shortfalls as new progress occurs.
Montessori Parallel: Like sandpaper letters, initial mismatches (error) accumulate to guide refinement; decay allows forward focus, child traces letter repeatedly until form holds without over-correction.
Limitation: Classroom data may cluster; test averages on subsets.
graph TD
subgraph EMA["Average Filter"]
E1[Noise Reduction]
E2[Alpha in 0.1-1.0]
E3[Lag ~1/alpha]
E4[Speed vs Evenness]
end
subgraph INT["Accumulator"]
I1[Offset Elimination]
I2[Gamma gain, rho leak]
I3[Saturation Risk]
I4[Fix vs Equilibration]
end
subgraph ANTI["Stability Guard"]
A1[Excess Prevention]
A2[Leak rho, Clipping]
A3[Stability Essential]
A4[Safety vs Drive]
end
EMA --> CTRL[Radius Controller]
INT --> CTRL
ANTI --> CTRL
CTRL --> OUT["r_t in [min, max]"]
style EMA fill:#e3f2fd,stroke:#01579b
style INT fill:#e8f5e9,stroke:#1b5e20
style ANTI fill:#fff3e0,stroke:#ef6c00
style OUT fill:#fce4ec,stroke:#c2185b
Caption: Components and their roles. Alt text: Graph with three subgraphs (EMA, INT, ANTI), 15 nodes, linking to controller/output, blue EMA, green INT, amber anti, pink out.
| Component | Definition | Parameter | Range | Role | Compitum Use |
|---|---|---|---|---|---|
| Average | Weighted recent sum | alpha (smooth) | 0.1–0.7 | Noise damp | Smooths d_t for input |
| Accumulator | Error sum | gamma (gain) | 0.05–0.2 | Offset fix | Drives r_t to 0 on drift |
| Leak | Accumulator fade | rho (hold) | 0.95–0.999 | Excess curb | Avoids excess growth |
| Radius | Exponential shift | beta, kappa (weights) | beta: 0.3–0.7 kappa: 0.1–0.5 |
Limit steps | r_{t+1} = clip(r_t exp(-signals)) |
| Clipping | Fixed limits | r_min, r_max | [0.05, 3.0] | Guard rail | Blocks extreme values |
graph TD
A["Problem?"]
A --> B{"Oscillating radius?"}
B -->|Yes| C{"Alpha >0.5?"}
C -->|Yes| D["Alpha=0.3: More smooth"]
C -->|No| E{"Beta/kappa high?"}
E -->|Yes| F["Halve beta/kappa: Milder"]
E -->|No| G["Verify noise; add filter"]
B -->|No| H{"Stuck at limit?"}
H -->|Yes| I{"I_t full?"}
I -->|Yes| J["Rho=0.95: Faster fade"]
I -->|No| K["Wider min/max or scale"]
H -->|No| L{"Slow response?"}
L -->|Yes| M["Alpha>0.5: Quicker"]
L -->|No| N["Stable: Track drift"]
style D fill:#e8f5e9,stroke:#1b5e20
style F fill:#e8f5e9,stroke:#1b5e20
style G fill:#e8f5e9,stroke:#1b5e20
style J fill:#e8f5e9,stroke:#1b5e20
style K fill:#e8f5e9,stroke:#1b5e20
style M fill:#e8f5e9,stroke:#1b5e20
style N fill:#e8f5e9,stroke:#1b5e20
Caption: Path for issue resolution. Alt text: Graph with problem root to oscillation/stuck/slow branches, 20 nodes, green fixes.
| Issue | Symptom | Cause | Fix | Parallel |
|---|---|---|---|---|
| Average Lag | Delayed drift spot | Alpha low (0.1) | Alpha=0.5–0.7; fit to pace | Blurred recent view |
| Excess Accumulation | r_t to 0/inf | Rho=1.0 or no clip | Rho<0.99, add clips; conditional | Overflowed tally |
| Excess Damp | Flat r_t | Beta/kappa >0.8 | Beta/kappa=0.3–0.5; test traces | Muffled alert |
| Fragile Parameters | Unsettled after tune | No method | Ziegler-Nichols: K_u, P_u for gains | Uncalibrated scale |
| Limit Bounce | Frequent extremes | Narrow [min, max] | Double bounds or scale | Constricted path |
Limitation: Table covers frequent cases; log traces for unusual.
graph LR
A["Clear I_t=0, D_t=0"] --> B["Raise beta to shake"]
B --> C["Note K_u gain, P_u period"]
C --> D["Set beta=0.45 K_u<br/>kappa=0.54 K_u / P_u"]
D --> E["Test with variation"]
E --> F{"Stable?"}
F -->|Yes| G["Complete"]
F -->|No| H["Cut gains 20%"]
H --> E
style A fill:#e3f2fd,stroke:#01579b
style G fill:#e8f5e9,stroke:#1b5e20
style H fill:#fff3e0,stroke:#ef6c00
Caption: Steps for empirical tuning. Alt text: Graph with 9 nodes: clear to raise/note/set/test/branch to complete or cut, blue start, green end, amber revise.
Profiles:
| Case | Alpha | Gamma | Rho | Beta | Kappa | Notes |
|---|---|---|---|---|---|---|
| High Variation | 0.3 | 0.05 | 0.99 | 0.4 | 0.15 | Strong smoothing, mild fix |
| Standard | 0.5 | 0.1 | 0.99 | 0.5 | 0.2 | Default values |
| Quick Reply | 0.7 | 0.15 | 0.95 | 0.6 | 0.25 | Rapid, with leak |
| Testing | 0.4 | 0.08 | 0.98 | 0.45 | 0.18 | Measured for trials |
Steps:
- Conservative: Alpha=0.3, gamma=0.05, rho=0.99
- Batch 50+ inputs with usual variation.
- Visualize radii: Smooth decline, no waver.
- Adjust: Slow → alpha +0.1; waver → beta/kappa -0.1; full → rho -0.02
- Confirm: Match known measures. Limitation: Profiles for quadratic; linear needs lower gains.
journey
title "Stability Building Sequence"
section Basics
Read Guide: 5: User
Set Alpha=0.5: 4: User
Process Batch: 3: User
section Adjustment
Visualize Radii: 4: User
Test Profiles: 3: User
Refine Spot: 5: User
section Extension
Add Derivative: 3: User
Edit Controller: 4: User
Submit to Project: 5: User
Caption: Path from basics to extension. Alt text: Timeline with basics/adjustment/extension sections, 9 steps, blue basics.
Action Items:
- Adjust controller: Alpha=0.5 in config, batch route—note smoother radii.
- Simulate full PID: Use sample loop with variable d_t; observe accumulation without decay.
- Add derivative: For forward damping; consult Åström Ch. 10.
- Benchmark: Average vs simple on data.
- Contribute: Parameter sets to repository.
- Configuration: Alpha, gamma, rho in YAML.
- Design-Notes: Drift derivations.
- Output-Format: Radius traces.
- Cookbook: Sample loops.
- Glossary: Stability, excess prevention.
- Åström and Murray (2008): Feedback Systems.
- Åström and Hägglund (2006): Advanced PID Control.
- Brown (1959): Statistical Forecasting.
- Ziegler and Nichols (1942): "Optimum Settings for Controllers".
- Discussions: https://github.com/PaulTiffany/compitum/discussions
- Issues: https://github.com/PaulTiffany/compitum/issues
- Documentation: https://github.com/PaulTiffany/compitum/wiki
Last Tuned: November 08, 2025 · Compitum v1.0+ · Open to Contributions