-
Notifications
You must be signed in to change notification settings - Fork 34
Demand Response Optimization for Battery Energy Storage #679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
42b63c3
b0a030c
125b48f
7903e39
eb9b449
053e586
2f0a325
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,3 +58,93 @@ tech_to_dispatch_connections: [ | |
| ["battery", "battery"], | ||
| ] | ||
| ``` | ||
|
|
||
| # Optimized Demand Response Controller | ||
|
|
||
| This controller optimizes the dispatch of a Battery Energy Storage System (BESS) based on a pre-defined supervisory signal. This signal could be the Locational Marginal Price (LMP), a demand profile, or a $LMP\times demand$ product depending on the application. The objective is to maximize incentive payments to the battery, subject to constraints on the maximum number of dispatch events per month and on the battery state of charge. | ||
|
|
||
| ## Definitions | ||
|
|
||
| **Given:** | ||
| - $\lambda_t$ := `supervisory_signal`: price, demand, or price $\times$ demand time series at time $t$ | ||
| - $\mathcal{W}$ := `peak_window`: set of hours eligible for dispatch (e.g., 12:00--19:00) | ||
| - $\gamma$ := performance incentive (\$/kW per dispatch hour) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this truly required to be per hour, or is it per time-step? In other words, could it be per-minute if the user requested a smaller time step?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was under the impression that H2I only supports hourly timesteps. I can make this more general.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are currently in the process of enabling smaller time steps, so we are building the capability into new additions to the code!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, that's awesome! |
||
| - $\bar{P}$ := `max_charge_rate` (kW): maximum charge and discharge rate, used as deemed capacity since the battery is assumed to always dispatch at full rated power | ||
| - $E_{\max} :=$ `max_capacity` $\times$ (`max_soc_fraction` $-$ `min_soc_fraction`): usable energy capacity (kWh) | ||
| - $\eta_c$ := `charge_efficiency`, $\quad \eta_d$ := `discharge_efficiency` | ||
| - $\overline{\text{SoC}}$ := `max_soc_fraction`, $\quad \underline{\text{SoC}}$ := `min_soc_fraction` | ||
| - `n_control_window` := Horizon length for optimization | ||
| - $\mathcal{T} := \{0, 1, \ldots, T\}$: hourly time steps over `n_control_window` | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hours or time steps? |
||
| - $\mathcal{M}_m$ := set of hours in month $m$, for $m = 1, \ldots, 12$ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above, does this have to be hours? |
||
|
|
||
| ## Decision Variables | ||
|
|
||
| - $u_t \in \{0, 1\}$ := discharge binary: 1 if battery dispatches at hour $t$, 0 otherwise | ||
| - $v_t \in \{0, 1\}$ := charge binary: 1 if battery charges at hour $t$, 0 otherwise | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hours or time steps? |
||
| ## Optimization Problem | ||
|
|
||
| This optimization is executed for each window, during which the performance model is invoked and the initial conditions are set. | ||
|
|
||
| ### Objective | ||
|
|
||
| Maximize total annual incentive revenue: | ||
|
|
||
| $$ | ||
| \max_{u_t,\, v_t} \quad \gamma \cdot \bar{P} \sum_{t \in \mathcal{T}} u_t | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should the objective be based on max charge/discharge rate, or on actual discharge rate at each time step?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was assuming that the battery always charges and discharges at max discharge rate. If we want to solve for the actual discharge rate as well as when (the binary var) we want to discharge, the math becomes a little harder. I can work on that tomorrow.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see how this objective will lead to reducing peaks. It seems like it could just reduce the total demand during the peak window without actually reducing the peak. I understand the threshold on percentile of peak in the horizon constraint, but I think we may want to add something to the objective related to reducing the peaks rather than just maximizing revenue. I think this is probably what you are holding for the next PR though.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realized the objective here is what is supposed to manage for the supervisor, but revenue is for the local entity. The supervisor wants to reduce their peaks during the most critical times of the month, but I'm sure maximizing the local revenue will achieve that. We can assume that maximizing revenue locally will maximize revenue upstream as well, which assumes a perfect incentive structure. I think I've convinced myself this is ok for now, but let's make sure we continue to keep this in mind moving forward. |
||
| $$ | ||
|
|
||
| ### Constraints | ||
|
|
||
| - Dispatch only within peak window: | ||
|
|
||
| $$ | ||
| u_t = 0 \qquad \forall\, t \notin \mathcal{W} | ||
| $$ | ||
|
|
||
| - Dispatch only on high supervisory signal: | ||
|
|
||
| $$ | ||
| u_t = 1 \implies \lambda_t \geq \lambda^*_m \qquad \forall\, t \in \mathcal{M}_m | ||
| $$ | ||
|
|
||
| where $\lambda^*_m$ is the threshold selecting the high LMP/peak load hours within month $m$. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it makes sense to use a threshold as you have it here. We may want to consider ramp rate or some additional criteria as well in the future. |
||
|
|
||
| - Maximum $N_{max}$ events per month: | ||
|
|
||
| $$ | ||
| \sum_{t \in \mathcal{M}_m} u_t \leq N_{\max} \qquad \forall\, m, \quad N_{\max}. | ||
| $$ | ||
|
|
||
| - SoC evolution with charge and discharge: | ||
|
|
||
| $$ | ||
| \text{SoC}_{t+1} = \text{SoC}_t + \frac{\eta_c \cdot v_t \cdot \bar{P}}{E_{\max}} - \frac{u_t \cdot \bar{P}}{\eta_d \cdot E_{\max}} \qquad \forall\, t \in \mathcal{T} | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to use actual charge/discharge rate here instead of rated
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to discuss whether we want to assume SOC is based on nameplate capacity or actual capacity. In other components we have based it on nameplate capacity, but here you are using actual capacity. I think we should pick a standard for H2I and stick with it. I'm up for conversation on this for sure and would be very interested to get feedback from others, such as @genevievestarke and @aditiegarg9. |
||
| $$ | ||
|
|
||
| - SoC bounds: | ||
|
|
||
| $$ | ||
| \underline{\text{SoC}} \leq \text{SoC}_t \leq \overline{\text{SoC}} \qquad \forall\, t \in \mathcal{T} | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you mean to include bars and underscores here to indicate max and min SOC?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. |
||
| $$ | ||
|
|
||
| - No simultaneous charge and discharge: | ||
|
|
||
| $$ | ||
| u_t + v_t \leq 1 \qquad \forall\, t \in \mathcal{T} | ||
| $$ | ||
|
|
||
| - No charging during dispatch window (battery reserved for discharge): | ||
|
|
||
| $$ | ||
| v_t = 0 \qquad \forall\, t \in \mathcal{W} | ||
| $$ | ||
|
|
||
| - Binary variables: | ||
|
|
||
| $$ | ||
| u_t \in \{0, 1\}, \quad v_t \in \{0, 1\}, \quad \text{SoC}_t \in [0, 1] \qquad \forall\, t, m | ||
| $$ | ||
| Example 34 performs the optimization with a synthetic LMP signal. The look-ahead horizon is set to 10 hours. As this value increases, the computational complexity grows and the solver may take significantly longer to run or fail to converge. Care should be taken when choosing this parameter: a short horizon limits visibility, making it difficult for the optimizer to identify the best dispatch opportunities across the full month. See figure below for the results. | ||
|
|
||
|  | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| name: H2Integrate_config | ||
| system_summary: PLM MILP-optimized battery dispatch | ||
| driver_config: driver_config.yaml | ||
| technology_config: tech_config.yaml | ||
| plant_config: plant_config.yaml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super helpful to have the math laid out, thanks!