solar/docs/REAL_LIFE_SCENARIO_REVIEW.md

10 KiB
Raw Permalink Blame History

Real-life scenario review: EV energy, home battery, and card plausibility

This document reviews where EV energy comes from, how it is counted, and whether the persona/product card calculations are consistent and plausible.


1. Where does the "missing" energy for the EV come from?

There is no missing energy in the model. The optimizer is built so that charge energy = drive energy every day.

  • Drive energy (per day): distance_km × (consumption_kwh_per_100km / 100). This is the EVs actual need.
  • Charge energy (per day): The optimizer allocates exactly this amount into the cheapest hours in the 0006 UTC window (at max EV power per hour until the days need is covered).

So over the week:

  • Total EV need = total_drive_energy_kwh (from the weekly EV plan).
  • Total EV charging = sum of daily_summaries[].energy_charge_kwh = same value.

The source of that energy in the “with solar” view is split into:

  1. Solar (via home battery or direct)

    • Modelled as: solar_for_ev = min(expected_solar_kwh_per_day, energy_charge_kwh_per_day) per day.
    • Stored as weekly_solar_for_ev_kwh (e.g. 73.9 kWh in your example).
  2. Grid

    • The rest: grid_energy = energy_charge_kwh - solar_for_ev per day.
    • Only this part is paid at grid price; that cost is aggregated into weekly_cost_with_solar_eur.

So:

  • “Missing” in the sense “EV need not covered by solar” = the grid share. It is fully included in the energy balance and in the cost.
  • “Missing” in the sense “energy not accounted for” = there is none; charge = drive, and the split solar vs grid is explicit.

Relevant code: backend/app/weekly_optimizer.py (solar coupling loop, ~266288): solar_for_ev, grid_energy, cost_grid, and weekly_cost_with_solar_eur.


2. Is the EV energy included in “energy usage”?

Yes. The EVs energy usage is the drive energy (and equivalently the charge energy).

  • Optimised (no solar): All of that is assumed from the grid; cost = weekly_cost_optimized_eur (cheapest hours in 0006).
  • With solar: Part is solar (weekly_solar_for_ev_kwh), part is grid; only the grid part is charged, giving weekly_cost_with_solar_eur.

So:

  • Energy usage (kWh) = total charge (= total drive) — no double-counting.
  • Cost = grid part only when solar is considered; that grid part is exactly what is used to compute “effectieve kosten met zon”.

3. Home battery table: context and plausibility

The table “Thuisbatterijstatus (SoC)” is produced by the home battery SoC trajectory in the weekly optimizer.

Model (daily, per day):

  1. SoC start = previous days SoC end (or 50% on day 1).
  2. Solar in = solar production of the day, capped by battery headroom (1 SoC_start) × capacity, then efficiency applied for SoC.
  3. SoC after solar = SoC after that charge step.
  4. Demand from battery = household_daily_kwh + daily_solar_for_ev_kwh[day]
    So: household consumption + the share of EV charging that is attributed to solar.
  5. Energy out = min(demand, available energy in battery), then efficiency applied for SoC.
  6. SoC end = SoC after discharge.

So:

  • Energie in (kWh) = solar that actually goes into the battery (capped by headroom), in kWh.
  • Energie uit (kWh) = energy delivered from the battery to household + EV (solar share).

Interpretation:
“Zon laadt de batterij; huishouden en EV (zondeel) onttrekken eraan” is correct: solar charges the battery; household and the solar share of EV draw from it. The rest of the EV charging is from the grid and does not go through the home battery in this model.

Plausibility of your numbers:

  • SoC often ending at 0%: possible when household_daily_kwh + ev_solar_share is large relative to whats in the battery after solar (e.g. 15 kWh capacity, ~1415 kWh out on some days).
  • Day 1: SoC start 50% → after solar 97% → 14.62 kWh out → 0% end: consistent with high demand and full discharge.
  • The fact that “Energie in” and “Energie uit” are on the same order as capacity and daily demand is plausible.

Relevant code: backend/app/weekly_optimizer.py (~332371): home battery trajectory, demand_kwh = hh_kwh + ev_solar_day, energy_in_kwh, energy_out_kwh.


4. Card context: calculations and plausibility

The “Product templates & ruwe terugverdientijd” block uses:

  • Weekly figures:
    weekly_cost_baseline_eur, weekly_cost_optimized_eur, weekly_cost_with_solar_eur from the optimized plan.
  • Annual (EV only):
    • annualBaselineCost = weekly_cost_baseline_eur × 52
    • annualOptimizedCost = weekly_cost_optimized_eur × 52
    • annualCostWithSolar = weekly_cost_with_solar_eur × 52
  • Savings:
    annualSavings = (weekly_cost_baseline_eur - weekly_cost_with_solar_eur) × 52
    (Label: “Geschatte jaarlijkse besparing (EV-laden)”.)
  • Payback:
    paybackYears = totalCapexEnergyStack / annualSavings
    with totalCapexEnergyStack = solar CAPEX + home battery CAPEX (EV CAPEX is intentionally excluded).

Check against your numbers:

Item Your value Formula / check
Baseline week 14.90 €
Geoptimaliseerde week 13.86 €
Effectieve kosten met zon 6.75 €
Jaarlijkse EV baseline 775 € 14.90 × 52 ≈ 775 ✓
Jaarlijkse EV geoptimaliseerd 721 € 13.86 × 52 ≈ 721 ✓
Jaarlijkse EV met zon 351 € 6.75 × 52 = 351 ✓
Jaarlijkse besparing (EV) 424 € (14.90 6.75) × 52 ≈ 424 ✓
Terugverdientijd 43.7 yr 18500 / 424 ≈ 43.6 ✓
Huishoudelijk verbruik ~5100 kWh
Huishoudelijke kosten (baseline) 528 € baseline €/kWh × 5100 ✓ (€/kWh from EV baseline)
Totaal baseline 1303 € 775 + 528 = 1303 ✓
Totaal geoptimaliseerd + zon 879 € 351 + 528 = 879 ✓

So the arithmetic is consistent with the code.

Design choices that affect interpretation:

  1. Household cost is not reduced by solar in the card
    “Jaarlijkse energiekosten huishouden + EV (geoptimaliseerd + zon)” uses the same household cost as baseline (528 €). Only the EV cost is reduced (351 €). So the 424 € savings are EV-only (baseline → optimised + solar). That is why payback is so long: CAPEX (solar + battery) is divided only by EV-related savings.

  2. Savings mix optimisation + solar
    “Geschatte jaarlijkse besparing (EV-laden)” = baseline (optimised + solar), so it includes both:

    • gain from time-of-use (0006, cheapest hours), and
    • gain from solar covering part of EV charging.
      So it is not “solar-only” savings. If you wanted a “solar-only” figure, you would use (weekly_cost_optimized_eur - weekly_cost_with_solar_eur) × 52.
  3. Payback is conservative
    Because only EV savings are used and household consumption is still valued at baseline price, the 43.7 years is a conservative (pessimistic) estimate. If household self-consumption from solar/battery were included in savings, payback would be shorter.

Relevant code: frontend/src/UseCaseView.tsx (~313322 payback, ~325351 annual costs and combined totals).


5. Summary

Question / topic Answer
Where does “missing” EV energy come from? There is no missing energy. The part not supplied by solar comes from the grid and is fully counted in weekly_cost_with_solar_eur.
Is EV energy in “energy usage”? Yes. EV usage = drive energy = charge energy; cost is grid share when solar is applied.
Home battery table correct? Yes. “Energie in” = solar into battery; “Energie uit” = household + EV solar share; logic and numbers are plausible.
Card calculations correct? Yes. Weekly → annual × 52, combined totals, and payback formula match the code and your numbers.
Card plausibility / caveats Payback is conservative (EV savings only; household cost unchanged with solar). Savings label is “EV-laden” and combines optimisation + solar.

5b. Average buy and sell price used in the models

Single price source: All cost and revenue calculations use day-ahead (spot) electricity prices from the same series (Utilitarian Spot / ENTSO-E), stored in electricity_prices as value_eur_mwh per timestamp.

Average buy price (grid import): Used for EV baseline, EV optimized cost per hour, home battery baseline cost, and household cost. The weekly optimizer builds a 24-hour pattern over the last 7 days (configurable, max 30) for the zone. For each UTC hour it averages that hour's prices; the overall average is the mean of those 24 hourly averages: weekly_avg_price_eur_mwh (e.g. 103.46 €/MWh) or weekly_avg_price_eur_kwh.

Sell price: No separate sell/export price. Solar revenue uses the same day-ahead price (value = kwh × price). So buy price = sell price = day-ahead spot. Code: app/price_patterns.py, app/weekly_optimizer.py, app/spot_prices.py, app/trading.py.


6. UI clarity. The real-life simulation UI now includes: (1) a note under the optimised plan that charging covers the full drive need and effective cost with solar is grid-only cost (usecase.optimisedPlanEnergyNote); (2) the existing home battery intro (solar charges battery; household + EV solar share draw); (3) a note that payback uses EV savings only and household stays at baseline (usecase.productTemplatesPaybackNote).

If you want to change behaviour, possible next steps are: (1) add household self-consumption savings to the card and payback, or (2) show “solar-only” EV savings separately from “optimisation-only” savings.