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

// 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}
}