Appearance
Controller API Reference
Overview
ErgoPlanner provides comprehensive process control interfaces supporting PID controllers and advanced control strategies for wastewater treatment processes. Controllers manage dissolved oxygen, solids retention time, return activated sludge, waste activated sludge, flow, pH, and advanced control schemes.
Base Controller Types
ControllerType
Union of all supported controller types.
Base Controllers
| Type | Description |
|---|---|
'DO' | Dissolved oxygen controller |
'SRT' | Solids retention time controller |
'RAS' | Return activated sludge controller |
'WAS' | Waste activated sludge controller |
'Flow' | Flow rate controller |
'pH' | pH controller |
Extended Controllers
| Type | Description |
|---|---|
'Cascade' | Master-slave cascade PID |
'Deadband' | On/off with hysteresis |
'Switch' | Smooth transition switch with S-curve |
'TimeOnOff' | Programmable time-based cycling |
'Ratio' | Flow ratio controller with PID trim |
'ContinuousP' | P-only for integrating processes |
'Feedforward' | Disturbance-based feedforward |
Core Interfaces
ControllerConfig
Base controller configuration interface.
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique controller ID |
| type | ControllerType | Yes | Controller type |
| enabled | boolean | Yes | Whether controller is enabled |
| setpoint | number | Yes | Controller setpoint value |
| kp | number | Yes | Proportional gain |
| ki | number | Yes | Integral gain (1/d) |
| kd | number | No | Derivative gain (d) |
| targetNodeId | string | Yes | Target process unit node ID |
| manipulatedVariable | string | Yes | Variable being manipulated |
Example
typescript
const doController: ControllerConfig = {
id: 'do-ctrl-1',
type: 'DO',
enabled: true,
setpoint: 2.0, // 2.0 mg/L DO
kp: 0.5, // Proportional gain
ki: 0.1, // Integral gain (1/d)
kd: 0.05, // Derivative gain (d)
targetNodeId: 'aeration-1',
manipulatedVariable: 'airFlow'
};PIDConfiguration
Complete PID configuration with anti-windup and filtering.
Properties
| Property | Type | Description |
|---|---|---|
| kp | number | Proportional gain |
| ki | number | Integral gain (1/s or 1/d) |
| kd | number | Derivative gain (s or d) |
| limits | ControllerLimits | Output limits |
| antiWindup | AntiWindupConfig | Anti-windup configuration |
| derivativeFilter | DerivativeFilterConfig | Derivative filter configuration |
| setpoint | number | Setpoint value |
| enabled | boolean | Whether controller is enabled |
Example
typescript
const pidConfig: PIDConfiguration = {
kp: 0.5,
ki: 0.1,
kd: 0.05,
limits: {
outputMin: 0,
outputMax: 100
},
antiWindup: {
enabled: true,
maxIntegral: 50,
minIntegral: -50,
backCalculationCoeff: 0.5
},
derivativeFilter: {
enabled: true,
coefficient: 0.1
},
setpoint: 2.0,
enabled: true
};ControllerState
Extended controller state with runtime data.
Properties
| Property | Type | Description |
|---|---|---|
| integralAccumulator | number | Accumulated integral term |
| previousError | number | Previous error for derivative calculation |
| lastOutput | number | Last calculated output |
| lastTimestamp | number | Timestamp of last calculation |
| isActive | boolean | Whether controller is actively controlling |
Extends ControllerConfig with all base configuration properties.
Example
typescript
const controllerState: ControllerState = {
id: 'do-ctrl-1',
type: 'DO',
enabled: true,
setpoint: 2.0,
kp: 0.5,
ki: 0.1,
kd: 0.05,
targetNodeId: 'aeration-1',
manipulatedVariable: 'airFlow',
integralAccumulator: 5.2,
previousError: 0.3,
lastOutput: 45.5,
lastTimestamp: 1234567890,
isActive: true
};ControllerOutput
Controller output result from a calculation step.
Properties
| Property | Type | Description |
|---|---|---|
| controllerId | string | Controller ID |
| type | ControllerType | Controller type |
| setpoint | number | Current setpoint value |
| processVariable | number | Current process variable (measured value) |
| error | number | Control error (setpoint - processVariable) |
| output | number | Controller output value |
| saturated | boolean | Whether output is saturated (at limits) |
| pTerm | number | Proportional term contribution |
| iTerm | number | Integral term contribution |
| dTerm | number | Derivative term contribution |
| outputUnit | string | Unit of the output |
| targetNodeId | string | Node ID being controlled |
Example
typescript
const output: ControllerOutput = {
controllerId: 'do-ctrl-1',
type: 'DO',
setpoint: 2.0,
processVariable: 1.8,
error: 0.2,
output: 48.5,
saturated: false,
pTerm: 0.1, // 0.5 × 0.2
iTerm: 48.0, // accumulated integral
dTerm: 0.4, // derivative component
outputUnit: 'm³/h',
targetNodeId: 'aeration-1'
};
console.log(`DO Error: ${output.error} mg/L`);
console.log(`Air Flow Output: ${output.output} ${output.outputUnit}`);
console.log(`P: ${output.pTerm}, I: ${output.iTerm}, D: ${output.dTerm}`);ControllerLimits
Output limits for controller.
Properties
| Property | Type | Description |
|---|---|---|
| outputMin | number | Minimum output value |
| outputMax | number | Maximum output value |
AntiWindupConfig
Anti-windup configuration for integral term.
Properties
| Property | Type | Description |
|---|---|---|
| enabled | boolean | Enable anti-windup |
| maxIntegral | number | Maximum integral value |
| minIntegral | number | Minimum integral value |
| backCalculationCoeff | number | Back-calculation coefficient (0-1) |
DerivativeFilterConfig
Derivative filter configuration to reduce noise sensitivity.
Properties
| Property | Type | Description |
|---|---|---|
| enabled | boolean | Enable derivative filtering |
| coefficient | number | Filter coefficient (0-1, lower = more filtering) |
Extended Controller Types
CascadeControllerConfig
Master-slave PID structure where master output becomes slave setpoint.
Properties
| Property | Type | Description |
|---|---|---|
| id | string | Controller ID |
| type | 'Cascade' | Controller type |
| enabled | boolean | Whether controller is enabled |
| master | MasterPIDConfig | Master PID configuration |
| slave | SlavePIDConfig | Slave PID configuration |
| mode | ExtendedControllerMode | Mode: 'auto', 'manual', 'tracking' |
| bumplessTransfer | boolean | Bumpless transfer enabled |
Master Configuration
| Property | Type | Description |
|---|---|---|
| setpoint | number | Master setpoint |
| kp | number | Proportional gain |
| ki | number | Integral gain (1/d) |
| kd | number | Derivative gain (d) |
| outputMin | number | Output minimum |
| outputMax | number | Output maximum |
| pvNodeId | string | Process variable source node |
| pvVariable | string | Process variable name |
Slave Configuration
Includes master properties plus:
| Property | Type | Description |
|---|---|---|
| manipulatedVariable | string | Manipulated variable name |
| targetNodeId | string | Target node for output |
Example
typescript
const cascadeController: CascadeControllerConfig = {
id: 'cascade-do-air',
type: 'Cascade',
enabled: true,
master: {
setpoint: 2.0, // 2.0 mg/L DO
kp: 0.8,
ki: 0.2,
kd: 0.1,
outputMin: 0,
outputMax: 100, // Maximum air flow setpoint
pvNodeId: 'aeration-1',
pvVariable: 'DO'
},
slave: {
kp: 0.5,
ki: 0.3,
kd: 0.05,
outputMin: 0,
outputMax: 100, // Maximum blower speed %
pvNodeId: 'blower-1',
pvVariable: 'airFlow',
manipulatedVariable: 'blowerSpeed',
targetNodeId: 'blower-1'
},
mode: 'auto',
bumplessTransfer: true
};RatioControllerConfig
Maintains ratio between wild and controlled flows with PID trim.
Properties
| Property | Type | Description |
|---|---|---|
| id | string | Controller ID |
| type | 'Ratio' | Controller type |
| enabled | boolean | Whether controller is enabled |
| wildNodeId | string | Wild variable source node (leader) |
| wildVariable | string | Wild variable name |
| controlledNodeId | string | Controlled variable source node (follower) |
| controlledVariable | string | Controlled variable name |
| targetNodeId | string | Target node for manipulated output |
| manipulatedVariable | string | Manipulated variable |
| ratio | number | Desired ratio (controlled/wild) |
| pidTrim | PIDTrimConfig | PID trim configuration |
| outputMin | number | Output minimum |
| outputMax | number | Output maximum |
| wildLag | number | Lag compensation for wild variable (days) |
| mode | ExtendedControllerMode | Mode of operation |
PID Trim Configuration
| Property | Type | Description |
|---|---|---|
| enabled | boolean | Enable PID trim |
| kp | number | Proportional gain |
| ki | number | Integral gain |
| kd | number | Derivative gain |
| maxTrim | number | Max trim adjustment (fraction, e.g., 0.1 = ±10%) |
Example
typescript
const rasRatioController: RatioControllerConfig = {
id: 'ras-ratio-1',
type: 'Ratio',
enabled: true,
wildNodeId: 'influent-1',
wildVariable: 'flow',
controlledNodeId: 'ras-pump-1',
controlledVariable: 'flow',
targetNodeId: 'ras-pump-1',
manipulatedVariable: 'pumpSpeed',
ratio: 1.0, // 1:1 RAS ratio
pidTrim: {
enabled: true,
kp: 0.2,
ki: 0.05,
kd: 0.01,
maxTrim: 0.1 // ±10% trim
},
outputMin: 0,
outputMax: 100,
wildLag: 0.042, // ~1 hour lag
mode: 'auto'
};DeadbandControllerConfig
On/off control with hysteresis to prevent hunting.
Properties
| Property | Type | Description |
|---|---|---|
| id | string | Controller ID |
| type | 'Deadband' | Controller type |
| enabled | boolean | Whether controller is enabled |
| targetNodeId | string | Target node ID |
| pvNodeId | string | Process variable source node |
| pvVariable | string | Process variable name |
| manipulatedVariable | string | Manipulated variable (on/off output) |
| setpoint | number | Setpoint (center of deadband) |
| deadband | number | Deadband width (total band = 2 × deadband) |
| highLimit | number | High limit for turn on |
| lowLimit | number | Low limit for turn off |
| onValue | number | Output when ON |
| offValue | number | Output when OFF |
| action | ControllerAction | 'direct' or 'reverse' |
| minOnTime | number | Minimum on time (days) |
| minOffTime | number | Minimum off time (days) |
| mode | ExtendedControllerMode | Mode of operation |
Example
typescript
const mixerController: DeadbandControllerConfig = {
id: 'mixer-deadband-1',
type: 'Deadband',
enabled: true,
targetNodeId: 'anoxic-1',
pvNodeId: 'anoxic-1',
pvVariable: 'DO',
manipulatedVariable: 'mixerSpeed',
setpoint: 0.3, // 0.3 mg/L DO target
deadband: 0.1, // ±0.1 mg/L deadband
highLimit: 0.4, // Turn off mixer at 0.4 mg/L
lowLimit: 0.2, // Turn on mixer at 0.2 mg/L
onValue: 100, // 100% mixer speed
offValue: 0, // 0% mixer speed
action: 'reverse', // High DO = turn off mixer
minOnTime: 0.021, // 30 minutes minimum on
minOffTime: 0.021, // 30 minutes minimum off
mode: 'auto'
};FeedforwardControllerConfig
Disturbance-based feedforward with optional lead-lag compensation.
Properties
| Property | Type | Description |
|---|---|---|
| id | string | Controller ID |
| type | 'Feedforward' | Controller type |
| enabled | boolean | Whether controller is enabled |
| targetNodeId | string | Target node ID |
| disturbanceNodeId | string | Disturbance variable source node |
| disturbanceVariable | string | Disturbance variable name |
| manipulatedVariable | string | Manipulated variable |
| staticGain | number | Static gain (output/disturbance relationship) |
| leadLag | LeadLagConfig | Lead-lag compensation |
| outputMin | number | Output minimum |
| outputMax | number | Output maximum |
| bias | number | Bias/offset for output |
| feedbackPID | FeedbackPIDConfig | undefined |
| mode | ExtendedControllerMode | Mode of operation |
Lead-Lag Configuration
| Property | Type | Description |
|---|---|---|
| leadTime | number | Lead time constant (days) |
| lagTime | number | Lag time constant (days) |
| gain | number | Gain |
Example
typescript
const carbonDoseController: FeedforwardControllerConfig = {
id: 'carbon-ff-1',
type: 'Feedforward',
enabled: true,
targetNodeId: 'carbon-dose-1',
disturbanceNodeId: 'influent-1',
disturbanceVariable: 'flow',
manipulatedVariable: 'doseRate',
staticGain: 0.05, // 50 mg/L per m³/d influent flow
leadLag: {
leadTime: 0.083, // 2 hours lead
lagTime: 0.042, // 1 hour lag
gain: 1.0
},
outputMin: 0,
outputMax: 200,
bias: 10, // 10 mg/L base dose
mode: 'auto'
};Controller Execution
ControllerExecutionContext
Context for controller execution during a simulation step.
Properties
| Property | Type | Description |
|---|---|---|
| currentTime | number | Current simulation time (days) |
| dt | number | Time step (days) |
| measurements | Map<string, ProcessMeasurement> | Current process measurements |
| configs | ControllerConfig[] | Controller configurations |
ControllerExecutionResult
Result of controller execution for a simulation step.
Properties
| Property | Type | Description |
|---|---|---|
| outputs | Map<string, ControllerOutput> | All controller outputs |
| parameterUpdates | Map<string, Record<string, number>> | Modified parameters to apply |
| warnings | string[] | Any warnings during execution |
| errors | string[] | Any errors during execution |
Example
typescript
const executionResult: ControllerExecutionResult = {
outputs: new Map([
['do-ctrl-1', doControllerOutput],
['ras-ratio-1', rasControllerOutput]
]),
parameterUpdates: new Map([
['aeration-1', { airFlow: 48.5 }],
['ras-pump-1', { pumpSpeed: 85.2 }]
]),
warnings: [],
errors: []
};
// Apply parameter updates to nodes
for (const [nodeId, params] of executionResult.parameterUpdates) {
const node = graph.nodes.get(nodeId);
if (node) {
Object.assign(node.parameters, params);
}
}Tuning Guidelines
Typical PID Gains by Controller Type
DO Controller
| Parameter | Typical Range | Notes |
|---|---|---|
| Kp | 0.3 - 0.8 | Higher for faster response |
| Ki | 0.05 - 0.2 | Lower to prevent overshoot |
| Kd | 0.01 - 0.1 | Small derivative for stability |
SRT Controller
| Parameter | Typical Range | Notes |
|---|---|---|
| Kp | 0.1 - 0.5 | Slow process, conservative tuning |
| Ki | 0.01 - 0.05 | Very slow integral action |
| Kd | 0 - 0.05 | Often zero or very small |
RAS Flow Controller
| Parameter | Typical Range | Notes |
|---|---|---|
| Kp | 0.5 - 1.5 | Fast flow control |
| Ki | 0.1 - 0.5 | Moderate integral action |
| Kd | 0.05 - 0.2 | Derivative for smooth control |
Implementation Notes
Anti-Windup
Anti-windup prevents integral term buildup during output saturation:
typescript
// Clamping method
if (output > limits.outputMax) {
integralAccumulator = Math.min(integralAccumulator, maxIntegral);
} else if (output < limits.outputMin) {
integralAccumulator = Math.max(integralAccumulator, minIntegral);
}
// Back-calculation method
const saturatedError = output - clampedOutput;
integralAccumulator -= backCalculationCoeff * saturatedError;Derivative Filtering
First-order filter reduces noise sensitivity:
typescript
const rawDerivative = (error - previousError) / dt;
const filteredDerivative = coefficient * rawDerivative +
(1 - coefficient) * previousFilteredDerivative;
dTerm = kd * filteredDerivative;Bumpless Transfer
For mode changes (auto/manual/tracking):
typescript
// When switching to auto, initialize integral to maintain current output
integralAccumulator = (currentOutput - pTerm - dTerm) / ki;Related Types
- ProcessMeasurement - Measurement data from simulation
- ProcessUnitParameters - Parameters that controllers manipulate