A common misconception in early conversations with operators new to battery dispatch software is that the optimizer's job is to choose "charge or discharge, how much, right now." That is the output. The job is actually to solve a multi-period constrained optimization problem across a planning horizon of 24 to 48 hours, subject to physics constraints, degradation limits, and contractual obligations that all interact in non-obvious ways.
This post covers the constraint structure we actually work with and why each constraint class matters. The goal is not to describe every solver implementation detail, but to give operators a clear mental model of what battery dispatch optimization is doing and where things can go wrong when constraints are misconfigured or missing.
The Objective Function: What You Are Optimizing For
Before getting to constraints, it is worth being explicit about the objective. For a grid-connected battery in a wholesale market context, the objective is typically to maximize net revenue across the dispatch horizon. This includes energy arbitrage (buy low, sell high across price intervals), ancillary service capacity payments (regulation up/down, spinning reserve), and demand charge reduction if the battery is also serving a behind-the-meter customer load. These revenue streams interact, and the optimizer has to allocate the battery's available capacity and energy across them simultaneously.
For utility-owned batteries serving a distribution operator, the objective may instead be to minimize grid cost: curtailment avoidance, peak load reduction, or deferral of distribution infrastructure upgrade. The constraint structure is similar, but the objective function changes how the solver weighs different dispatch options.
Getting the objective right is as important as getting the constraints right. An optimizer with a good constraint model but a miscalibrated objective will dispatch the battery in ways that are physically valid but economically suboptimal or operationally misaligned.
State of Charge Bounds
The most fundamental physical constraint is the state of charge (SoC) bound. A battery cannot charge above its rated capacity and cannot discharge below zero. In practice, both limits are tighter than the hardware maximum.
Battery management systems typically enforce a safe operating window: for lithium iron phosphate (LFP) cells commonly used in grid-scale systems, this is often 10% to 90% SoC. Operating outside those bounds accelerates calendar aging and risks thermal events. So the effective usable range is 80% of nameplate capacity, not 100%.
In our dispatch model, SoC bounds are parameterized per battery system based on manufacturer specifications and, where available, measured capacity fade history. A battery that has degraded to 88% of its original nameplate capacity after three years of operation has a different effective energy window than a new installation, and the optimizer needs to know this to compute accurate round-trip scheduling.
SoC is also a state variable that carries forward between optimization intervals. The optimizer cannot treat each 15-minute period independently. A decision to discharge 500 kW for 15 minutes reduces SoC by 125 kWh, and that reduction constrains every dispatch decision for the rest of the planning horizon. This is what makes battery dispatch a multi-period problem rather than a series of independent single-period decisions.
Ramp Rate Constraints
Power conversion systems (inverters) have maximum ramp rates: the fastest they can change output in kW per minute. For a 1 MW inverter, a typical ramp limit might be 100 kW per second on a steady-state basis, which sounds fast but matters when you are trying to provide primary frequency response or fast-ramping regulation service.
For most 15-minute energy dispatch scenarios, inverter ramp rates are not the binding constraint. The battery can fully ramp within a few seconds, far faster than the interval length. But for ancillary service products that require response to a signal within seconds, ramp rates become critical and need to be explicitly modeled. AGC regulation signals from an ISO, for example, may require the battery to track a signal that changes every 2 to 4 seconds. A dispatch optimizer that is scheduling regulation capacity needs to verify the inverter can actually track the expected signal variability, not just deliver the average megawatt figure.
Degradation Constraints and Cycle Counting
This is where battery dispatch optimization becomes genuinely different from optimizing any other energy storage medium. Batteries degrade with use. Each full charge-discharge cycle consumes a fraction of the battery's total cycle life. A lithium-ion battery rated for 4,000 cycles at 80% depth of discharge will lose roughly 0.025% of its capacity per cycle, accumulating to meaningful capacity fade over a few years of daily cycling.
An optimizer that ignores degradation will naturally push the battery to cycle as frequently as possible to capture arbitrage opportunities. This maximizes short-term revenue while destroying long-term asset value. The economically correct formulation includes a degradation cost per MWh of throughput, derived from the expected replacement cost divided by the total life throughput of the battery.
We parameterize degradation cost per-site based on battery chemistry, operating temperature profile, and contractual warranty terms. For a typical 2 MWh LFP system with a 10-year warranty and replacement cost in the range of current market rates, the degradation cost per cycle comes out to a figure that meaningfully affects when arbitrage spreads justify cycling and when they do not. Operators who run their batteries without this cost in the objective function tend to find themselves with capacity fade that surprises them 18 months into operation.
We are not saying degradation modeling gives you a perfect forecast of battery life. Chemistry is complex and real-world aging is influenced by temperature cycling, partial state-of-charge operation, and charging rate in ways that are hard to model precisely. But even a linearized degradation cost term in the objective substantially improves dispatch decisions compared to ignoring it entirely.
Contractual and Operational Constraints
Beyond physics, batteries operate under contractual obligations that the optimizer must respect as hard constraints.
Capacity reservation constraints arise when a battery has committed a portion of its capacity to an ancillary service product. If 500 kW of the battery's 1 MW capacity is committed to spinning reserve for an 8-hour block, the remaining 500 kW is available for energy dispatch, but the reserved 500 kW must be held ready and cannot be pre-discharged. The optimizer needs to track both the committed and available capacity envelopes simultaneously.
Minimum run-time constraints exist for some market products. A battery participating in non-spinning reserve may need to be capable of sustained discharge for 10 to 30 minutes at the offered capacity, not just peak delivery for one interval. The optimizer must verify that SoC at the time of potential dispatch is sufficient to meet the minimum run duration.
Interconnection and tariff constraints add another layer. Behind-the-meter batteries may be subject to net metering tariff rules that limit export, or interconnection agreement terms that cap ramp rates at the point of common coupling. Distribution utilities sometimes have operating agreements that restrict battery charge during periods of high feeder load. These constraints are site-specific and require careful configuration when a new site is onboarded.
The Mixed-Integer Structure
When you combine continuous variables (power output in kW), state variables (SoC in kWh), and binary decisions (is the battery operating in charge or discharge mode, is it committed to an ancillary product), the optimization problem becomes a mixed-integer linear program (MILP) or mixed-integer quadratic program depending on how degradation is formulated.
MILPs can be computationally expensive, which matters when you need to solve a 24-to-48-hour dispatch schedule every 15 minutes for a fleet of assets. We use a combination of problem structure exploitation (battery charge and discharge cannot occur simultaneously, which eliminates many combinations early) and warm-starting from the previous interval's solution to keep solve times within the operational window. For a portfolio of up to a dozen battery sites with shared grid constraints, this is tractable on commodity cloud compute. For very large fleets, decomposition approaches or rolling-horizon approximations may be necessary.
The point is that battery dispatch is not a lookup table. It is an optimization problem with a structure that needs to be maintained across every solve cycle, and the solution quality depends directly on whether the constraint set accurately represents the real physical and contractual limits of each asset.