dalsi
This commit is contained in:
@@ -71,7 +71,7 @@ NEG_BUY_CHARGE_SHORTFALL_PENALTY_CZK_KWH = 100.0
|
||||
PRE_NEG_CHARGE_PENALTY_CZK_KWH = 400.0
|
||||
PRE_NEG_BATT_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||
PRE_NEG_BATT_EXPORT_MIN_SELL_CZK_KWH = 1.0
|
||||
PLANNER_BUILD_TAG = "2026-06-01-spot-grid-charge-at-acq-buy-v61"
|
||||
PLANNER_BUILD_TAG = "2026-06-01-kv1-fixed-night-self-consume-v62"
|
||||
# Ranní slabá FVE: neaplikovat pv_store ge_pv=0 (jinak curtail při sell < večerní peak).
|
||||
DAWN_LOW_PV_NO_CURTAIL_W = 1500
|
||||
# BA81/KV1: PV→bat jen v těsné blízkosti nejnižšího sell v horizontu (≈ poledne), ne při ~3 Kč ráno.
|
||||
@@ -1833,10 +1833,12 @@ def _night_self_consume_discourage_import_indices(
|
||||
evening_push_ts: set[int],
|
||||
charge_acquisition_czk_kwh: float,
|
||||
min_spread: float,
|
||||
purchase_fixed: bool = False,
|
||||
) -> set[int]:
|
||||
"""
|
||||
Noční sloty mimo evening_push: penalizace importu pro dům (preferovat bd).
|
||||
v45: celé noční okno, ne jen evening_early_export_ban subset.
|
||||
KV1: buy ≈ acq (konstantní ~6,35) — jinak prázdná množina, síť místo baterie v noci.
|
||||
"""
|
||||
out: set[int] = set()
|
||||
for t, s in enumerate(slots):
|
||||
@@ -1844,11 +1846,15 @@ def _night_self_consume_discourage_import_indices(
|
||||
continue
|
||||
if not _in_night_battery_export_window(s):
|
||||
continue
|
||||
buy_t = float(s.buy_price)
|
||||
if buy_t <= float(charge_acquisition_czk_kwh) + float(min_spread):
|
||||
continue
|
||||
if float(s.load_baseline_w) <= 0:
|
||||
continue
|
||||
buy_t = float(s.buy_price)
|
||||
if purchase_fixed:
|
||||
if buy_t >= 0.0:
|
||||
out.add(t)
|
||||
continue
|
||||
if buy_t <= float(charge_acquisition_czk_kwh) + float(min_spread):
|
||||
continue
|
||||
out.add(t)
|
||||
return out
|
||||
|
||||
@@ -2836,6 +2842,7 @@ def solve_dispatch(
|
||||
evening_push_ts=evening_push_ts,
|
||||
charge_acquisition_czk_kwh=charge_acquisition_czk_kwh,
|
||||
min_spread=float(degradation_cost_effective),
|
||||
purchase_fixed=purchase_fixed_pre,
|
||||
)
|
||||
post_evening_push_night_ts = _post_evening_push_night_self_consume_indices(
|
||||
slots, evening_push_ts
|
||||
@@ -4123,7 +4130,10 @@ def solve_dispatch(
|
||||
# Spot (home-01): buy > min ne-záporného buy v horizontu.
|
||||
# Fixní tarif (KV1): navíc buy > charge_acquisition (konstantní buy ≈ ref).
|
||||
expensive_import_slot = buy_t > ref_buy_horizon + min_spread
|
||||
if fixed_tariff_like_pre:
|
||||
if purchase_fixed_pre and buy_t >= 0.0:
|
||||
# KV1/BA81: buy skoro konstantní — buy > acq nikdy neplatí, jinak v noci import za 6 Kč.
|
||||
expensive_import_slot = True
|
||||
elif fixed_tariff_like_pre:
|
||||
expensive_import_slot = expensive_import_slot or (
|
||||
buy_t > charge_acquisition_czk_kwh + min_spread
|
||||
)
|
||||
|
||||
@@ -1833,6 +1833,88 @@ class NegativeSellPvChargeTests(unittest.TestCase):
|
||||
"sell nad min horizontu: žádné grid nabíjení",
|
||||
)
|
||||
|
||||
def test_kv1_fixed_night_uses_battery_not_grid_import(self) -> None:
|
||||
"""v62: po večerním push nocí bd≥load, ne import za fixní buy."""
|
||||
prague = ZoneInfo("Europe/Prague")
|
||||
push = PlanningSlot(
|
||||
interval_start=datetime(2026, 6, 1, 18, 45, tzinfo=prague).astimezone(
|
||||
timezone.utc
|
||||
),
|
||||
buy_price=6.353,
|
||||
sell_price=9.61,
|
||||
pv_a_forecast_w=0,
|
||||
pv_b_forecast_w=0,
|
||||
load_baseline_w=400,
|
||||
ev1_connected=False,
|
||||
ev2_connected=False,
|
||||
allow_charge=False,
|
||||
allow_discharge_export=True,
|
||||
charge_acquisition_buy_czk_kwh=6.353,
|
||||
)
|
||||
night = PlanningSlot(
|
||||
interval_start=datetime(2026, 6, 1, 23, 0, tzinfo=prague).astimezone(
|
||||
timezone.utc
|
||||
),
|
||||
buy_price=6.353,
|
||||
sell_price=3.09,
|
||||
pv_a_forecast_w=0,
|
||||
pv_b_forecast_w=0,
|
||||
load_baseline_w=800,
|
||||
ev1_connected=False,
|
||||
ev2_connected=False,
|
||||
allow_charge=False,
|
||||
allow_discharge_export=False,
|
||||
charge_acquisition_buy_czk_kwh=6.353,
|
||||
)
|
||||
battery = _battery(uc_wh=12_500.0, min_pct=10.0, arb_pct=30.0)
|
||||
battery.max_discharge_power_w = 6250
|
||||
hp = SimpleNamespace(
|
||||
rated_heating_power_w=0,
|
||||
tuv_min_temp_c=45.0,
|
||||
tuv_target_temp_c=55.0,
|
||||
)
|
||||
grid = SimpleNamespace(
|
||||
max_import_power_w=17_000,
|
||||
max_export_power_w=8000,
|
||||
block_export_on_negative_sell=True,
|
||||
purchase_pricing_mode="fixed",
|
||||
)
|
||||
vehicles = [
|
||||
SimpleNamespace(
|
||||
max_charge_power_w=0,
|
||||
battery_capacity_kwh=1.0,
|
||||
default_target_soc_pct=80.0,
|
||||
),
|
||||
SimpleNamespace(
|
||||
max_charge_power_w=0,
|
||||
battery_capacity_kwh=1.0,
|
||||
default_target_soc_pct=80.0,
|
||||
),
|
||||
]
|
||||
soc0 = 0.35 * battery.usable_capacity_wh
|
||||
results, _, _ = solve_dispatch(
|
||||
[push, night],
|
||||
battery,
|
||||
hp,
|
||||
grid,
|
||||
[None, None],
|
||||
vehicles,
|
||||
soc0,
|
||||
50.0,
|
||||
operating_mode="AUTO",
|
||||
)
|
||||
r_night = results[1]
|
||||
self.assertLess(
|
||||
r_night.battery_setpoint_w,
|
||||
-200,
|
||||
"noc po push: výdej z baterie na dům",
|
||||
)
|
||||
self.assertLessEqual(
|
||||
r_night.grid_setpoint_w,
|
||||
400,
|
||||
"noc: ne plný import za 6,35 Kč",
|
||||
)
|
||||
|
||||
def test_fixed_evening_push_no_charge_at_peak_sell(self) -> None:
|
||||
"""v59: večerní push — při sell>buy ne nabíjet, jen vybíjet."""
|
||||
prague = ZoneInfo("Europe/Prague")
|
||||
|
||||
@@ -5,6 +5,16 @@ Formát: **datum (ISO)** · stručný důvod · soubory · chování / ověřen
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-01 — KV1: noc z baterie, ne import za 6,35 Kč (v62)
|
||||
|
||||
**Problém:** Po večerním vývozu (~32 % SoC) plán **22:00–06:00** krmil dům ze **sítě** (`grid ~260 W`, `bat 0`) místo z baterie. Fixní **buy ≈ charge_acquisition ≈ 6,35** → `expensive_import_slot` nikdy true → neplatilo `bd ≥ load` ani noční penalizace importu (`buy > acq` je false).
|
||||
|
||||
**Změna (v62):** u **`purchase_pricing_mode=fixed`**: `expensive_import_slot = true` (buy ≥ 0); `_night_self_consume_discourage_import_indices` zahrne noční sloty i při **buy = acq**.
|
||||
|
||||
Tag **`2026-06-01-kv1-fixed-night-self-consume-v62`**.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-01 — home-01: grid jen při buy ≤ acquisition (v61, zrušeno v60)
|
||||
|
||||
**Problém:** **19:00** nabíjení za **buy ~5,5** při **`charge_acquisition ~3,25`** z rána → falešně ziskový večerní export. **v60** (`sell < buy` ve slotu) bylo **špatně**: u spotu (a často u fixního tarifu) je **`sell < buy` normální** (marže distributora) — arbitráž je **mezi sloty**, ne v jedné čtvrthodině.
|
||||
|
||||
Reference in New Issue
Block a user