Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from dataclasses import dataclass | |
| from math import cos, pi | |
| class GridParams: | |
| base_load: float = 0.55 | |
| load_amplitude: float = 0.25 # daily swing | |
| charging_load_per_ev: float = 0.004 # added per occupied slot | |
| renewable_base: float = 0.18 | |
| renewable_amplitude: float = 0.35 # peaks midday | |
| def _clamp01(x: float) -> float: | |
| return 0.0 if x < 0.0 else 1.0 if x > 1.0 else x | |
| def baseline_grid_load(hour: int, *, day_type: str, params: GridParams = GridParams()) -> float: | |
| # Two-peak-ish load using cosine: highest around evening, lower around midday. | |
| # Map hour->angle with peak near 18:00. | |
| angle = 2 * pi * ((hour - 18) / 24.0) | |
| day_mult = 1.0 if day_type == "weekday" else 0.9 | |
| load = params.base_load + params.load_amplitude * (0.5 + 0.5 * cos(angle)) | |
| return _clamp01(load * day_mult) | |
| def renewable_pct(hour: int, params: GridParams = GridParams()) -> float: | |
| # Midday solar bump: peak around 13:00, low at night. | |
| angle = 2 * pi * ((hour - 13) / 24.0) | |
| ren = params.renewable_base + params.renewable_amplitude * (0.5 + 0.5 * cos(angle)) | |
| return _clamp01(ren) | |
| def update_grid_load( | |
| *, | |
| hour: int, | |
| day_type: str, | |
| occupied_slots_total: int, | |
| load_shift_action_strength: float = 0.0, | |
| params: GridParams = GridParams(), | |
| ) -> tuple[float, float]: | |
| base = baseline_grid_load(hour, day_type=day_type, params=params) | |
| added = occupied_slots_total * params.charging_load_per_ev | |
| load = _clamp01(base + added - load_shift_action_strength) | |
| ren = renewable_pct(hour, params=params) | |
| return load, ren | |