# SHIFT Simulator — Input/Output Interface > **Markdown report of a non-markdown source document.** > > | | | > |---|---| > | **Source** | [`docs/_originals/Simulator Interface Input-Output sheet.pdf`](../_originals/Simulator%20Interface%20Input-Output%20sheet.pdf) | > | **Format** | PDF, 10 pages, 556 kB | > | **MD5** | `0712f05593c39897abc8f651834bebde` | > | **Owner** | AI & Control Systems cluster | > | **Document status** | **Draft v0.1** — living document, TBD items unresolved | > | **Report generated** | 2026-07-25 | > [!NOTE] > Tables in the source PDF are rendered in a layout that machine extraction scrambles > (symbol, name, unit and note columns interleave). The tables below are **reconstructed** — > the content is the source's, the column alignment is this report's. Where a mapping was > ambiguous it is flagged inline. Check against the original PDF before relying on any single > row for implementation. ## Purpose Defines the contract between the SHIFT microgrid simulator and everything that talks to it: - the AI/RL policy, - the rule-based baseline, - the validation/benchmark layer, - the Economics team's downstream cost and CO₂ accounting. It covers what the simulator **consumes** (configuration, exogenous time-series, control actions) and what it **returns** at every timestep. > *"It is a living document — items flagged TBD need a decision from the cluster or whoever."* This document is the direct descendant of [Shift Input Data](../04-simulations/shift-input-data.md) — §1 explicitly refers to *"the constants Robert's doc lists in bold."* --- ## 0. Conventions ### Timestep **Symbol:** `dt` Default assumption **1 hour** — matches typical PV/load profiles and the one-year benchmarking horizon in the project brief. Whether a sub-hourly step is needed for battery fast-response behaviour is TBD. > *"I did 1 hour for this cause 15 mins time steps will be quite compute heavy for RL training, > so we do need to talk about that."* ### Sign conventions | Quantity | Positive means | Negative means | |---|---|---| | `P_battery` | discharging (supplying the bus) | charging (absorbing from the bus) | | `P_grid` | importing from grid | exporting to grid | | `n_H2_net` | net production into tank | net consumption from tank | All other power values — `P_PV`, `P_electrolyser`, `P_fuelcell`, `P_load` — are **non-negative by definition**. ### Power balance The invariant the simulator must satisfy at every step: ``` P_PV_used + P_fuelcell + P_grid + P_battery = P_load_served_critical + P_load_served_noncritical + P_electrolyser ``` Any residual after the policy's action is absorbed by unmet load — with critical load prioritised (see [§4](#4-priority-rules-the-simulator-enforces)). ### Units SI throughout: power in W, energy in Wh, mass in kg, amount in mol, time in s (or h for hourly steps). TBD to lock down before code is written. > *"I don't know the conventions for this, I let AI handle this, not an electrical engineer sorry."* --- ## 1. Static configuration inputs Set once per simulation run. ### 1.1 Electrolyser | Symbol | Name | Unit | Notes | |---|---|---|---| | `N_c_ele` | Number of cells | — | Usually difficult to find | | `mu_F` | Faraday efficiency | — | Fall back to literature average (~0.95–0.99 for PEM) | | `P_ele_max` | Rated / max power | W | | | `P_ele_min` | Minimum operating power | W | Below this the electrolyser shuts off (efficiency cliff) | | `I_ele_min` | Minimum operating current | A | Alternative to `P_ele_min` | | `cal_H2` | H₂ production calibration factor | — | If we end up reading H₂ flow from measured data | ### 1.2 Fuel cell | Symbol | Name | Unit | Notes | |---|---|---|---| | `N_c_fc` | Number of cells | — | | | `utilisation_fc` | H₂ utilisation | % | | | `P_fc_max` | Maximum output power | W | **Project spec: 100 kW** | | `V_fc_min`, `V_fc_max` | Operating voltage range | V | | ### 1.3 Hydrogen tank | Symbol | Name | Unit | Notes | |---|---|---|---| | `V_H2_max` | Maximum stored volume | L (or kg) | **Project spec: up to 200 kg total across two tanks** | | `V_H2_init` | Initial fill level | L (or kg) | | | `T_tank` | Operating temperature | K | TBD — isothermal assumption likely fine | | `p_tank` | Operating pressure | atm (or bar) | TBD — isobaric vs. ideal-gas model | ### 1.4 PV | Symbol | Name | Unit | Notes | |---|---|---|---| | `A_PV` | Total panel area | m² | **Project spec: 2,300 m²** | | `mu_PV` | Panel efficiency | — | | | `P_PV_max` | Inverter / rated cap | W | Optional; if set, clipping occurs above this | ### 1.5 Battery | Symbol | Name | Unit | Notes | |---|---|---|---| | `E_rated` | Rated energy capacity | Wh | | | `Q_rated` | Rated charge capacity | Ah | | | `P_batt_charge_max` | Max charge power | W | | | `P_batt_discharge_max` | Max discharge power | W | | | `SoC_init` | Initial state of charge | — (0–1) | | | `SoC_min`, `SoC_max` | Operating window | — (0–1) | E.g. 0.1–0.9 | | `eta_batt_ch`, `eta_batt_dis` | Round-trip efficiencies | — | Often split into charge & discharge | ### 1.6 Load | Symbol | Name | Unit | Notes | |---|---|---|---| | `V_load` | Bus voltage | V | Constant, per Robert's note | ### 1.7 Grid | Symbol | Name | Unit | Notes | |---|---|---|---| | `P_grid_max` | Max connection capacity (import & export) | W | Constant, per Robert's note | | `V_grid` | Bus voltage | V | | --- ## 2. Per-timestep inputs ### 2.1 Exogenous time-series Read from data; not under policy control. | Symbol | Name | Unit | Source / note | |---|---|---|---| | `G(t)` | PV generated power | W | Forecasted | | `L_crit(t)` | Critical hospital load demand | W | ICU, life-support, etc. — must always be served | | `L_noncrit(t)` | Non-critical hospital load demand | W | Lighting, HVAC, admin | | `grid_on(t)` | Grid availability (1/0) | — | Models outages | | `price(t)` | Grid electricity price | €/kWh | Import & export prices — TBD whether they differ | | `CO2_int(t)` | Grid carbon intensity | kg CO₂/kWh | For emissions accounting | ### 2.2 Control inputs From the AI/RL policy or the rule-based baseline. At each timestep the controller emits **setpoints, not direct power flows** — the simulator clips them to physical limits and reports actuals. | Symbol | Name | Unit | Range | |---|---|---|---| | `u_ele(t)` | Electrolyser power setpoint | W | `[0, P_ele_max]`; values in `(0, P_ele_min)` round to 0 (off) | | `u_fc(t)` | Fuel cell power setpoint | W | `[0, P_fc_max]` | | `u_batt(t)` | Battery setpoint (signed) | W | `[-P_batt_charge_max, P_batt_discharge_max]` | | `sw_ele(t)` | Electrolyser ON/OFF | 1/0 | Optional — can be folded into `u_ele = 0` | | `sw_fc(t)` | Fuel cell ON/OFF | 1/0 | Optional — can be folded into `u_fc = 0` | **On the grid:** the grid is treated as the **slack bus** — whatever the power-balance residual is after all other components act, the grid absorbs, within `P_grid_max` and `grid_on(t)`. The RL action space therefore probably does *not* include the grid directly. --- ## 3. Per-timestep outputs ### 3.1 State variables Carried forward to the next step. | Symbol | Name | Unit | |---|---|---| | `SoC(t)` | Battery state of charge | — (0–1) | | `H2_level(t)` | H₂ stored in tank | mol (or kg) | | `T_tank(t)` | Tank temperature | K (only if non-isothermal model) | | `p_tank(t)` | Tank pressure | bar (if modelled) | ### 3.2 Power flows | Symbol | Name | Unit | |---|---|---| | `P_PV_available(t)` | PV power available given irradiance | W | | `P_PV_used(t)` | PV power actually consumed | W | | `P_PV_curtailed(t)` | PV potential that was thrown away | W | | `P_ele(t)` | Actual electrolyser consumption | W | | `P_fc(t)` | Actual fuel cell output | W | | `P_batt(t)` | Actual battery flow (signed) | W | | `P_grid(t)` | Actual grid flow (signed) | W | | `P_load_served_crit(t)` | Critical load served | W | | `P_load_served_noncrit(t)` | Non-critical load served | W | ### 3.3 Mass flows (hydrogen) | Symbol | Name | Unit | |---|---|---| | `n_H2_prod(t)` | H₂ produced by electrolyser | mol/s (or kg/h) | | `n_H2_cons(t)` | H₂ consumed by fuel cell | mol/s (or kg/h) | | `n_H2_net(t)` | Net flow into tank | mol/s | ### 3.4 KPIs and accounting > *"the heart of the task"* | Symbol | Name | Unit | Notes | |---|---|---|---| | `unmet_crit(t)` | Unserved critical load | W | **Must be near-zero — primary resilience KPI** | | `unmet_noncrit(t)` | Unserved non-critical load | W | Restated as a KPI for clarity | | `curtailment(t)` | `= P_PV_curtailed(t)` | W | | | `cost(t)` | Operating cost of this step | € | TBD — see [§5](#5-open-questions) | | `CO2(t)` | Emissions of this step | kg CO₂ | TBD — see [§5](#5-open-questions) | ### 3.5 Diagnostic / efficiency outputs Recommended. Ties directly to [AI Efficiency Improvements](../01-project/ai-efficiency-improvements.md), which flagged ~30–40% electrolyser losses and ~40% fuel-cell losses as the biggest optimisation targets. If the simulator returns per-step efficiencies, the RL reward and the post-hoc analysis can both attack those losses directly. | Symbol | Name | Unit | |---|---|---| | `eta_ele(t)` | Electrolyser efficiency this step | — | | `eta_fc(t)` | Fuel cell efficiency this step | — | | `eta_PV(t)` | Effective PV efficiency this step | — | | `eta_batt(t)` | Battery round-trip-equivalent | — | --- ## 4. Priority rules the simulator enforces Not I/O, but contract-level — the policy needs to know what the simulator will do with a setpoint that violates physics or safety. 1. **Critical load is sacred.** If the policy's setpoints leave critical load unserved while the battery has charge, the fuel cell can run, or the grid is available, the simulator **overrides the policy in that order** and reports the override (e.g. via an output flag) so it shows up in training. 2. **State limits are hard.** `SoC ∈ [SoC_min, SoC_max]`, `H2_level ∈ [0, V_H2_max]`. Setpoints that would breach these are **clipped**; the difference shows up as `P_batt(t)` vs `u_batt(t)`. 3. **Electrolyser dead-zone.** Setpoints in `(0, P_ele_min)` are rounded to 0. 4. **Grid outage.** If `grid_on(t) = 0` then `P_grid(t) = 0` regardless of slack residual; the residual becomes `unmet_*` or `curtailment`. --- ## 5. Open questions Need answers before v1.0. - **Cost & CO₂ scope.** Flagged TBD in §3.4. If Economics handles these downstream, the simulator only needs to return `P_grid(t)` plus exogenous `price(t)` and `CO2_int(t)`, and Economics computes cost/CO₂ themselves. If the simulator computes them, it also needs to know whether there is an O&M cost per kWh through the electrolyser/fuel cell, a degradation cost, and so on. - **Tank model.** Isothermal + ideal gas, or do we need temperature and pressure dynamics? - **Battery degradation.** Modelled or ignored? - **Sub-hourly dynamics.** Does the battery's fast-response role require `dt < 1 h`? If so, mixed time-scale handling between battery (minutes) and electrolyser (hours) becomes a design question. - **Action space format.** Continuous setpoints (`u_ele ∈ [0, P_ele_max]`) vs. discrete buckets — affects what the RL team expects as input. - **Forecast vs. realised exogenous inputs.** The policy may see a forecast of `G(t+1)` and `L(t+1)`; the simulator advances with the realised values. Decide whether the simulator delivers both or only realised. - **Critical vs non-critical split — data availability.** Confirm with the hospital data source whether the load profile can actually be split, or whether we need a proxy fraction (e.g. assume X% of total load is critical). - **Mutual exclusion of electrolyser and fuel cell.** Should the action space structurally prevent simultaneous operation (mode-switch / hybrid action space), or allow them independently and let the reward penalise simultaneous operation? Has efficiency, sample-efficiency, and policy-expressiveness trade-offs. --- ## Cross-document notes Three consistency issues between this document and its neighbours: | Issue | Detail | |---|---| | **Naming convention** | This document uses physics-style symbols (`P_PV`, `SoC(t)`, `u_ele`). [RL State Variables](rl-state-variables.md) and [RL Action Variables](rl-action-variables.md) use descriptive identifiers (`PV_Generation`, `Battery_SOC`, `Electrolyzer_PowerSetpoint`). Neither references the other; one must win. | | **State coverage** | This sheet omits component temperatures, stack health, and water level, which the RL state doc lists. Consistent with the isothermal/no-degradation assumptions flagged TBD above. | | **Action coverage** | This sheet accepts 5 control signals; the RL action doc lists 16. Grid import/export and load shedding are deliberately excluded here (slack bus, and outcome-not-action respectively); PV curtailment control, thermal management, and mode supervision are genuine gaps. | Load-tier terminology also differs from Energy Management's [BIDMC/UCSD Energy Flow and Balances](../03-energy-management/bidmc-ucsd-energy-flow-and-balances.md), which uses a **three**-tier model (Tier 1 critical / Tier 2 essential / Tier 3 non-critical) against this document's **two**-way split (`L_crit` / `L_noncrit`). ## Related - [Shift Input Data](../04-simulations/shift-input-data.md) — the predecessor variable list this sheet formalises - [RL State Variables](rl-state-variables.md) · [RL Action Variables](rl-action-variables.md) · [RL Reward Function](rl-reward-function.md) - [Rule-Based Controller](rule-based-controller.md) — the baseline policy that consumes this contract - [Forecasting Requirements](forecasting-requirements.md) — produces `G(t)`, `L(t)`, `price(t)`