You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
4.3 KiB
133 lines
4.3 KiB
// Package pid defines interfaces for PID controller process variable sources. |
|
// This abstraction allows the PID controller to be used for any dynamic |
|
// adjustment scenario - rate limiting, PoW difficulty adjustment, etc. |
|
package pid |
|
|
|
import "time" |
|
|
|
// ProcessVariable represents a measurable quantity that the PID controller |
|
// regulates. Implementations provide the current value and optional metadata. |
|
type ProcessVariable interface { |
|
// Value returns the current process variable value. |
|
// The value should typically be normalized to a range where the setpoint |
|
// makes sense (e.g., 0.0-1.0 for percentage-based control, or absolute |
|
// values for things like hash rate or block time). |
|
Value() float64 |
|
|
|
// Timestamp returns when this measurement was taken. |
|
// This is used for derivative calculations and staleness detection. |
|
Timestamp() time.Time |
|
} |
|
|
|
// Source provides process variable measurements to the PID controller. |
|
// Implementations are domain-specific (e.g., memory monitor, hash rate tracker). |
|
type Source interface { |
|
// Sample returns the current process variable measurement. |
|
// This should be efficient as it may be called frequently. |
|
Sample() ProcessVariable |
|
|
|
// Name returns a human-readable name for this source (for logging/debugging). |
|
Name() string |
|
} |
|
|
|
// Output represents the result of a PID controller update. |
|
type Output interface { |
|
// Value returns the computed output value. |
|
// The interpretation depends on the application: |
|
// - For rate limiting: delay in seconds |
|
// - For PoW difficulty: difficulty adjustment factor |
|
// - For temperature control: heater power level |
|
Value() float64 |
|
|
|
// Clamped returns true if the output was clamped to limits. |
|
Clamped() bool |
|
|
|
// Components returns the individual P, I, D contributions for debugging. |
|
Components() (p, i, d float64) |
|
} |
|
|
|
// Controller defines the interface for a PID controller. |
|
// This allows for different controller implementations (standard PID, |
|
// PID with filtered derivative, adaptive PID, etc.). |
|
type Controller interface { |
|
// Update computes the controller output based on the current process variable. |
|
// Returns the computed output. |
|
Update(pv ProcessVariable) Output |
|
|
|
// UpdateValue is a convenience method that takes a raw float64 value. |
|
// Uses the current time as the timestamp. |
|
UpdateValue(value float64) Output |
|
|
|
// Reset clears all internal state (integral accumulator, previous values). |
|
Reset() |
|
|
|
// SetSetpoint updates the target value. |
|
SetSetpoint(setpoint float64) |
|
|
|
// Setpoint returns the current setpoint. |
|
Setpoint() float64 |
|
|
|
// SetGains updates the PID gains. |
|
SetGains(kp, ki, kd float64) |
|
|
|
// Gains returns the current PID gains. |
|
Gains() (kp, ki, kd float64) |
|
} |
|
|
|
// Tuning holds PID tuning parameters. |
|
// This can be used for configuration or auto-tuning. |
|
type Tuning struct { |
|
Kp float64 // Proportional gain |
|
Ki float64 // Integral gain |
|
Kd float64 // Derivative gain |
|
|
|
Setpoint float64 // Target value |
|
|
|
// Derivative filtering (0.0-1.0, lower = more filtering) |
|
DerivativeFilterAlpha float64 |
|
|
|
// Anti-windup limits for integral term |
|
IntegralMin float64 |
|
IntegralMax float64 |
|
|
|
// Output limits |
|
OutputMin float64 |
|
OutputMax float64 |
|
} |
|
|
|
// DefaultTuning returns sensible defaults for a normalized (0-1) process variable. |
|
func DefaultTuning() Tuning { |
|
return Tuning{ |
|
Kp: 0.5, |
|
Ki: 0.1, |
|
Kd: 0.05, |
|
Setpoint: 0.5, |
|
DerivativeFilterAlpha: 0.2, |
|
IntegralMin: -10.0, |
|
IntegralMax: 10.0, |
|
OutputMin: 0.0, |
|
OutputMax: 1.0, |
|
} |
|
} |
|
|
|
// SimpleProcessVariable is a basic implementation of ProcessVariable. |
|
type SimpleProcessVariable struct { |
|
V float64 |
|
T time.Time |
|
} |
|
|
|
// Value returns the process variable value. |
|
func (p SimpleProcessVariable) Value() float64 { return p.V } |
|
|
|
// Timestamp returns when this measurement was taken. |
|
func (p SimpleProcessVariable) Timestamp() time.Time { return p.T } |
|
|
|
// NewProcessVariable creates a SimpleProcessVariable with the current time. |
|
func NewProcessVariable(value float64) SimpleProcessVariable { |
|
return SimpleProcessVariable{V: value, T: time.Now()} |
|
} |
|
|
|
// NewProcessVariableAt creates a SimpleProcessVariable with a specific time. |
|
func NewProcessVariableAt(value float64, t time.Time) SimpleProcessVariable { |
|
return SimpleProcessVariable{V: value, T: t} |
|
}
|
|
|