Feature Branch for MPPOC Data Centers#106
Conversation
…hybrid_supervisory_controller`
There was a problem hiding this comment.
Pull request overview
This PR adds new controller utilities and expands Hercules v2 integration to better support MPPOC-style simulations (notably thermal plant handling, filtering utilities, and supervisory controller features).
Changes:
- Added a reusable
LowPassFilterutility (with new tests) and introduced SciPy as a dependency. - Extended
HerculesInterfaceto recognizeThermalPlant, add batteryroundtrip_efficiency, and apply a default setpoint for uncontrolled components. - Enhanced
HybridSupervisoryControllerGenericwith minimum-power constraints and storage charging availability propagation; added a newThermalPlantController.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
tests/controller_utilities_test.py |
Adds unit tests for the new low-pass filter utility. |
pyproject.toml |
Adds SciPy dependency required by signal conditioning utilities. |
hycon/interfaces/hercules_interface.py |
Extends Hercules v2 component support (thermal plant params, battery efficiency, default controls). |
hycon/controllers/thermal_plant_controller.py |
Introduces a new controller for thermal plant power setpoints. |
hycon/controllers/signal_conditioning.py |
Introduces LowPassFilter implemented via SciPy. |
hycon/controllers/hybrid_supervisory_controller.py |
Adds minimum-power handling and storage charging availability propagation. |
hycon/controllers/controller_base.py |
Makes controller parameter checking tolerant of None. |
hycon/controllers/__init__.py |
Exposes the new ThermalPlantController at the package level. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self.plant_parameters[c] = { | ||
| "type": "thermal", | ||
| "component_category": "generator", | ||
| "P_min": h_dict[c]["min_stable_load_fraction"] * h_dict[c]["rated_capacity"], | ||
| "P_max": h_dict[c]["rated_capacity"], | ||
| "ramp_rate": h_dict[c]["ramp_rate_fraction"] | ||
| * h_dict[c]["rated_capacity"] | ||
| / 60.0, | ||
| } |
| else: | ||
| # Set a safe default power_setpoint for components without controllers | ||
| h_dict[c].setdefault("power_setpoint", 0.0) |
| def set_controller_parameters( | ||
| self, | ||
| component_controllers=[], | ||
| curtailment_order=None, | ||
| minimum_power=None, |
| # Check valid minimum_power | ||
| if minimum_power is None: | ||
| # Default is reverse order of component_controllers | ||
| self.minimum_power = np.zeros_like(component_controllers) | ||
| elif len(minimum_power) != len(component_controllers): | ||
| raise ValueError("minimum_power must be the same length as component_controllers.") | ||
| elif not all([isinstance(c, (float, int)) and c >= 0 for c in minimum_power]): | ||
| raise ValueError( | ||
| "All entries in minimum_power must be non-negative floats or integers corresponding" | ||
| " to indices of component_controllers." | ||
| ) | ||
| else: | ||
| self.minimum_power = minimum_power | ||
|
|
| for cidx in self.curtailment_order[::-1]: | ||
| cc = self.component_controllers[cidx] | ||
|
|
||
| if cc.plant_parameters[cc.cname]["component_category"] == "generator": | ||
| power_reference_component = power_reference_with_storage - power_export_total | ||
| power_reference_component = max( |
| def compute_controls(self, measurements_dict): | ||
| return {self.cname: {"power_setpoint": measurements_dict[self.cname]["power_reference"]}} |
| # Check DC gain of the filter is 1, raise warning if not | ||
| if a[-1] != b[-1]: | ||
| print( | ||
| "Warning: DC gain of the low-pass filter is not 1. " | ||
| "This will lead to a steady-state scaling of the reference trajectory." | ||
| ) |
|
I accidentally triggered Copilot. We can disregard for now or delete to remove the noise. My bad. |
|
@jfrederik-nrel @dzalkind I've added some utilities for signal conditioning in hycon/controllers/signal_conditioning.py. At first, I formulated them as controllers that inherited from Currently included are:
You can see how they are each set up and called in tests/controller_utilities_tests.py. @jfrederik-nrel , I think I'll now see if I can refactor the |
Working branch for team to push updates for working together on multi-level control.
We can use this as a shared working/discussion space.
In general, most things should be pushed to mppoc_data_center_sim, but some things make more sense in hycon long term:
HerculesInterface)