# Feature: PID Controller ## Overview The PID (Proportional-Integral-Derivative) step size controller is an advanced adaptive time-stepping controller that provides better stability and efficiency than the basic PI controller, especially for difficult or oscillatory problems. **Key Characteristics:** - Three-term control: proportional, integral, and derivative components - More stable than PI for challenging problems - Standard in production ODE solvers - Can prevent oscillatory step size behavior ## Why This Feature Matters - **Robustness**: Handles difficult problems that cause PI controller to oscillate - **Industry standard**: Used in MATLAB, Sundials, and other production solvers - **Minimal overhead**: Small computational cost for significant stability improvement - **Smooth stepping**: Reduces erratic step size changes ## Dependencies - None (extends current controller infrastructure) ## Implementation Approach ### Mathematical Formulation The PID controller determines the next step size based on error estimates from the current and previous steps: ``` h_{n+1} = h_n * (ε_n)^(-β₁) * (ε_{n-1})^(-β₂) * (ε_{n-2})^(-β₃) ``` Where: - ε_i = error estimate at step i (normalized by tolerance) - β₁ = proportional coefficient (typically ~0.3 to 0.5) - β₂ = integral coefficient (typically ~0.04 to 0.1) - β₃ = derivative coefficient (typically ~0.01 to 0.05) Standard formula (Hairer & Wanner): ``` h_{n+1} = h_n * safety * (ε_n)^(-β₁/(k+1)) * (ε_{n-1})^(-β₂/(k+1)) * (h_n/h_{n-1})^(-β₃/(k+1)) ``` Where k is the order of the method. ### Advantages Over PI - **PI controller**: Uses only current and previous error (2 terms) - **PID controller**: Also uses rate of change of error (3 terms) - **Result**: Anticipates trends, prevents overshoot ### Implementation Design ```rust pub struct PIDController { // Coefficients pub beta1: f64, // Proportional pub beta2: f64, // Integral pub beta3: f64, // Derivative // Constraints pub factor_min: f64, // qmax inverse pub factor_max: f64, // qmin inverse pub h_max: f64, pub safety_factor: f64, // State (error history) pub err_old: f64, // ε_{n-1} pub err_older: f64, // ε_{n-2} pub h_old: f64, // h_{n-1} // Next step guess pub next_step_guess: TryStep, } ``` ## Implementation Tasks ### Core Controller - [ ] Define `PIDController` struct - [ ] Add beta1, beta2, beta3 coefficients - [ ] Add constraint fields (factor_min, factor_max, h_max, safety) - [ ] Add state fields (err_old, err_older, h_old) - [ ] Add next_step_guess field - [ ] Implement `Controller` trait - [ ] `determine_step()` method - [ ] Handle first step (no history) - [ ] Handle second step (partial history) - [ ] Full PID formula for subsequent steps - [ ] Apply safety factor and limits - [ ] Update error history - [ ] Return TryStep::Accepted or NotYetAccepted - [ ] Constructor methods - [ ] `new()` with all parameters - [ ] `default()` with standard coefficients - [ ] `for_order()` - scale coefficients by method order - [ ] Helper methods - [ ] `reset()` - clear history (for algorithm switching) - [ ] Update state after accepted/rejected steps ### Standard Coefficient Sets Different coefficient sets for different problem classes: - [ ] **Default (H312)**: - β₁ = 1/4, β₂ = 1/4, β₃ = 0 - Actually a PI controller with specific tuning - Good general-purpose choice - [ ] **H211**: - β₁ = 1/6, β₂ = 1/6, β₃ = 0 - More conservative - [ ] **Full PID (Gustafsson)**: - β₁ = 0.49/(k+1) - β₂ = 0.34/(k+1) - β₃ = 0.10/(k+1) - True PID behavior ### Integration - [ ] Export PIDController in prelude - [ ] Update Problem to accept any Controller trait - [ ] Examples using PID controller ### Testing - [ ] **Comparison test: Smooth problem** - [ ] Run exponential decay with PI and PID - [ ] Both should perform similarly - [ ] Verify PID doesn't hurt performance - [ ] **Oscillatory problem test** - [ ] Problem that causes PI to oscillate step sizes - [ ] Example: y'' + ω²y = 0 with varying ω - [ ] PID should have smoother step size evolution - [ ] Plot step size vs time for both - [ ] **Step rejection handling** - [ ] Verify history updated correctly after rejection - [ ] Doesn't blow up or get stuck - [ ] **Reset test** - [ ] Algorithm switching scenario - [ ] Verify reset() clears history appropriately - [ ] **Coefficient tuning test** - [ ] Try different β values - [ ] Verify stability bounds - [ ] Document which work best for which problems ### Benchmarking - [ ] Add PID option to existing benchmarks - [ ] Compare step count and function evaluations vs PI - [ ] Measure overhead (should be negligible) ### Documentation - [ ] Docstring explaining PID control - [ ] When to prefer PID over PI - [ ] Coefficient selection guidance - [ ] Example comparing PI and PID behavior ## Testing Requirements ### Oscillatory Test Problem Problem designed to expose step size oscillation: ```rust // Prothero-Robinson equation // y' = λ(y - φ(t)) + φ'(t) // where φ(t) = sin(ωt), λ << 0 (stiff), ω moderate // // This problem can cause step size oscillation with PI ``` Expected: PID should maintain more stable step sizes. ### Step Size Stability Metric Track standard deviation of log(h_i/h_{i-1}) over the integration: - PI controller: may have σ > 0.5 - PID controller: should have σ < 0.3 ## References 1. **PID Controllers for ODE**: - Gustafsson, K., Lundh, M., and Söderlind, G. (1988) - "A PI stepsize control for the numerical solution of ordinary differential equations" - BIT Numerical Mathematics, 28, 270-287 2. **Implementation Details**: - Hairer, E., Nørsett, S.P., and Wanner, G. (1993) - "Solving Ordinary Differential Equations I", Section II.4 - PID controller discussion 3. **Coefficient Selection**: - Söderlind, G. (2002) - "Automatic Control and Adaptive Time-Stepping" - Numerical Algorithms, 31, 281-310 4. **Julia Implementation**: - `OrdinaryDiffEq.jl/lib/OrdinaryDiffEqCore/src/integrators/controllers.jl` - Look for `PIDController` ## Complexity Estimate **Effort**: Small (3-5 hours) - Straightforward extension of PI controller - Main work is getting coefficients right - Testing requires careful problem selection **Risk**: Low - Well-understood algorithm - Minimal code changes - Easy to validate ## Success Criteria - [ ] Implements full PID formula correctly - [ ] Handles first/second step bootstrap - [ ] Shows improved stability on oscillatory test problem - [ ] Performance similar to PI on smooth problems - [ ] Error history management correct after rejections - [ ] Documentation complete with usage examples - [ ] Coefficient sets match literature values ## Future Enhancements - [ ] Automatic coefficient selection based on problem characteristics - [ ] More sophisticated controllers (H0211b, predictive) - [ ] Limiter functions to prevent extreme changes - [ ] Per-algorithm default coefficients