Skip to content

Net Zero Strategy

The Net Zero strategy minimises grid import and export by continuously adjusting the battery setpoint to match site generation and consumption. It uses a PID controller as its feedback loop, with each control cycle reading live energy-flow metrics, computing a new setpoint, and dispatching a SetBatterySetpointCommand.

How It Works

Each time the strategy fires it runs through this pipeline:

Net Grid Power

The error signal fed into the PID controller is the net grid power - the power that the site is currently drawing from (or exporting to) the grid, after accounting for any charging power already supplied by the battery:

ts
netGridPower = batteryPower < 0
    ? gridPower − |batteryPower|   // battery is charging, subtract from grid
    : gridPower                    // battery is discharging or idle

A positive value means the site is net-importing; the strategy will command the battery to discharge to compensate. A negative value means the site is net-exporting; the strategy will command the battery to charge.

SoC Guard

Before dispatching any setpoint the strategy checks that the battery SoC is within its configured MinStateOfCharge/MaxStateOfCharge range. If the SoC is outside these limits the cycle is skipped entirely - no command is sent and the PID state is left unchanged. See Common Behaviour for the base class pattern.

Deadband

If |netGridPower| is less than ControlParameters.Deadband (default 500 W) no command is sent. Instead the PID integral is decayed by PidTuning.IntegralDecayFactor (default 0.5) to prevent integral windup when the site is already close to balance. The integral is then re-seeded via SetState before the next cycle.

Output Pipeline

After the raw PID output is produced it passes through three transforms in order:

StepDescriptionParameter
ClampConstrains output to [−MaxChargePower, MaxDischargePower] so the command never exceeds the hardware limit.BatteryConfiguration.MaxChargePower / MaxDischargePower
QuantizeRounds to the nearest multiple of DeviceStep using round-half-away-from-zero, matching device resolution.ControlParameters.DeviceStep (default 100 W)
Rate limitCaps the change between cycles to prevent large step changes. Uses the last known setpoint from the distributed cache as the reference. Cache entries expire after 5 minutes.ControlParameters.MaxRateOfChange (default 500 W)

Setpoint Mode

The final numeric setpoint is mapped to a BatterySetpointMode:

ConditionMode
|setpoint| < 1 WIdle
setpoint < 0Charging (value sent as positive magnitude)
setpoint > 0Discharging

Configuration

PID and control parameters are stored per battery asset in the platform database and loaded by GetBatteryConfiguration on each control cycle.

PID Tuning (PidTuning)

ParameterDefaultDescription
ProportionalGain0.8Kp - scales correction proportional to current error
IntegralGain0.02Ki - eliminates steady-state error over time
DerivativeGain2.5Kd - dampens correction based on rate of change
IntegralDecayFactor0.5Multiplier applied to the integral when within deadband (0 = reset, 1 = no decay)

Control Parameters (ControlParameters)

ParameterDefaultDescription
Deadband500 WMinimum grid imbalance before a setpoint is sent
MaxRateOfChange500 WMaximum setpoint change per control cycle
DeviceStep100 WSetpoints are quantized to multiples of this value

PID Controller

The PidController class in Voltimax.Edge.Gateway.Common implements the standard discrete PID formula:

u(t)=Kpe(t)+Ki0te(τ)dτ+Kddedt

Where the integral and derivative are approximated using the wall-clock time delta (dt) between control cycles. On the first call dt defaults to 10 seconds as a stable fallback. Backwards-in-time timestamps are rejected with an ArgumentException.

Gain Hot-Reload

The strategy holds a single PidController instance for the lifetime of a gateway run. If the PID gains are changed via the API (e.g. by updating PidTuning in the platform), the controller is recreated on the next cycle and state is reset. Gains that are unchanged reuse the existing controller, preserving the accumulated integral.

Behaviour Tests

Gateway mode gating is covered by GatewayModeBehaviorTests - see Strategies overview.

The underlying PidController is tested exhaustively in PidControllerTests (Voltimax.Edge.Gateway.Tests), including:

  • First-call default dt semantics
  • Integral accumulation and decay (DecayIntegral)
  • State injection via SetState
  • Backwards-time and NaN rejection
  • Real-world convergence scenario with default gains Kp=0.8, Ki=0.02, Kd=2.5
  • Deadband simulation (build integral → decay → verify halving)

No direct unit tests for NetZeroStrategy

NetZeroStrategy itself does not yet have dedicated unit or integration tests. The PID arithmetic is covered by PidControllerTests and the mode-gate behaviour is covered by GatewayModeBehaviorTests.