Grid and PCC Subsystem Simulation Model (AI / Code Generation Version)
This document specifies the Grid and PCC simulation model using formal notation for automated code generation. Targets: Python (NumPy), C/C++, MATLAB/Simulink.
Sign convention (shared across BESS, EMS, and Grid models):
- P_pcc > 0 → plant exports to grid (generating)
- P_pcc < 0 → plant imports from grid (consuming/charging)
- P_bess_setpoint > 0 → BESS charging (consuming from AC bus)
- P_bess_setpoint < 0 → BESS discharging (injecting to AC bus)
Simulation Loop (Top-Level Pseudocode)
# ─── Initialization ──────────────────────────────────────────────────────
Vg = 400.0 # V RMS line-to-line (grid source)
f = 50.0 # Hz
breaker_status = True # CLOSED = True
energy_acc = 0.0 # MWh accumulator
uv_timer = 0.0 # Under-voltage hold timer (s)
ov_timer = 0.0
uf_timer = 0.0
of_timer = 0.0
# ─── Per-step loop ───────────────────────────────────────────────────────
for k in range(N_steps):
# 1. Apply any disturbance scenario (FRT test, frequency step, etc.)
Vg_actual = Vg * Vg_dip_factor[k] # from test scenario
f_actual = f + f_disturbance[k] # from test scenario
# 2. Read plant asset currents / powers (from BESS and PV/Wind models)
P_bess = bess_model.P_bess_output # MW, positive=charging
Q_bess = bess_model.Q_bess_output # MVAr
P_pv = pv_model.P_pv_output # MW
P_wind = wind_model.P_wind_output # MW
# 3. Compute PCC bus voltage and current
I_plant, Vpcc = compute_pcc_voltage(Vg_actual, P_bess, P_pv, P_wind, Rg, Xg)
# 4. CT/PT scaling
V_sec, I_sec = ctpt_model(Vpcc, I_plant, PT_ratio, CT_ratio)
# 5. PCC Meter: compute measurements
P_pcc, Q_pcc, V_pcc, energy_acc = pcc_meter_step(
P_bess, Q_bess, P_pv, P_wind, V_pcc_kV, f_actual, energy_acc, dt
)
# 6. Publish to EMS (IF-GM01, IF-GM02)
emit_to_ems(P_pcc, Q_pcc, V_pcc, f_actual, energy_acc)
# 7. Breaker IED: check protection conditions
breaker_status, trip_alarm, trip_cause = ied_protection_step(
abs(I_plant), Vpcc, f_actual,
uv_timer, ov_timer, uf_timer, of_timer,
breaker_status, dt
)
# 8. Publish IED status to EMS (IF-BR01)
emit_to_ems_alarm(breaker_status, trip_alarm, trip_cause)
# 9. If breaker OPEN: disconnect all assets from grid (P_pcc = 0)
if not breaker_status:
P_bess = 0.0; P_pv = 0.0; P_wind = 0.0
1. AC Grid Voltage Source
Thevenin phasor model (scalar, steady-state, per time step):
V_{pcc} \approx V_g - I_{plant} \cdot R_g
(For simulation time scales of 0.5–1 s, the resistive drop dominates. Full complex phasor optionally:)
V_{pcc} = V_g - I_{plant} \cdot (R_g + j X_g)
Plant current from asset power injections:
I_{plant} = \frac{P_{bess} + P_{pv} + P_{wind}}{V_{pcc}} \cdot 10^6 \cdot \frac{1}{\sqrt{3}}
def compute_pcc_voltage(Vg, P_bess, P_pv, P_wind, Rg, Xg=0.0):
"""
Vg in V (line-to-line RMS).
P_* in MW (positive = generation / export).
Returns I_plant (A, positive = plant generating) and Vpcc (V).
"""
P_plant_total = P_bess + P_pv + P_wind # MW, positive = export
# Scalar approximation: P = V * I * sqrt(3) for three-phase
if abs(Vg) > 1.0:
I_plant = (P_plant_total * 1e6) / (Vg * 1.732)
else:
I_plant = 0.0
Vpcc = Vg - I_plant * Rg
return I_plant, Vpcc
Parameters:
| Symbol | Description | Default |
|---|---|---|
| $V_g$ | Grid source voltage (V, line-to-line RMS) | 400.0 |
| $R_g$ | Thevenin resistance ($\Omega$) | 0.01 |
| $X_g$ | Thevenin reactance ($\Omega$) | 0.05 |
| $f_{nom}$ | Nominal frequency (Hz) | 50.0 |
2. CT/PT Sensor Model
def ctpt_model(V_bus, I_bus, PT_ratio, CT_ratio,
V_noise_std=0.001, I_noise_std=0.001):
"""
Scales high-level bus signals to meter-level secondary values.
Adds small Gaussian noise to simulate real sensor imperfection.
"""
import numpy as np
V_sec = V_bus / PT_ratio + np.random.normal(0, V_noise_std)
I_sec = I_bus / CT_ratio + np.random.normal(0, I_noise_std)
return V_sec, I_sec
Parameters:
| Symbol | Description | Default |
|---|---|---|
PT_ratio |
Potential transformer ratio | 100 |
CT_ratio |
Current transformer ratio | 1000 |
V_noise_std |
Voltage noise std dev (V) | 0.001 |
I_noise_std |
Current noise std dev (A) | 0.001 |
3. PCC Meter
def pcc_meter_step(P_bess, Q_bess, P_pv, P_wind, V_pcc_kV,
f, energy_acc, dt, meter_rate=1.0):
"""
Computes PCC measurements from asset power injections.
P_* in MW (positive = export to grid).
Returns P_pcc, Q_pcc, V_pcc, updated energy_acc.
"""
# Power balance at PCC node
# Positive P_bess = charging = plant consuming = reduces export
P_pcc = -P_bess + P_pv + P_wind # MW; positive = net export to grid
Q_pcc = -Q_bess # MVAr; simplified (PV/Wind unity PF)
V_pcc = V_pcc_kV # kV
# Energy accumulation (MWh)
energy_acc += P_pcc * dt / 3600.0
return P_pcc, Q_pcc, V_pcc, energy_acc
Output signals (IF-GM01 to EMS):
| Signal | Type | Unit | Description |
|---|---|---|---|
P_pcc |
float | MW | Active power at PCC (+ = export) |
Q_pcc |
float | MVAr | Reactive power at PCC |
V_pcc |
float | kV | PCC voltage magnitude |
f |
float | Hz | Grid frequency |
energy_acc |
float | MWh | Accumulated exported energy |
quality |
string | — | "GOOD" / "SUSPECT" / "INVALID" |
timestamp |
datetime | UTC | Measurement timestamp |
Interface note:
P_pccpublished here is directly consumed by: -EMS PCC Tracking Controller(as feedback in the PI loop:P_error = P_target - P_pcc) -EMS Alarm Manager(for frequency/voltage alarm checks)
4. PCC Breaker + Protection IED
def ied_protection_step(I_mag, Vpcc, f, uv_t, ov_t, uf_t, of_t,
breaker_closed, dt):
"""
Evaluates protection conditions and updates timers.
Returns (breaker_status, trip_alarm, trip_cause).
"""
Vnom = 400.0
trip = False
cause = None
# Overcurrent: instantaneous
if I_mag > I_trip:
trip = True; cause = "OC"
# Under-voltage: time-delayed
if Vpcc < V_uv_trip * Vnom:
uv_t += dt
if uv_t >= trip_delay_uv:
trip = True; cause = "UV"
else:
uv_t = 0.0
# Over-voltage: time-delayed
if Vpcc > V_ov_trip * Vnom:
ov_t += dt
if ov_t >= trip_delay_ov:
trip = True; cause = "OV"
else:
ov_t = 0.0
# Under-frequency: time-delayed
if f < f_min_ied:
uf_t += dt
if uf_t >= trip_delay_uf:
trip = True; cause = "UF"
else:
uf_t = 0.0
# Over-frequency: time-delayed
if f > f_max_ied:
of_t += dt
if of_t >= trip_delay_of:
trip = True; cause = "OF"
else:
of_t = 0.0
if trip:
breaker_closed = False
return breaker_closed, trip, cause, uv_t, ov_t, uf_t, of_t
Parameters:
| Symbol | Description | Default |
|---|---|---|
I_trip |
Instantaneous overcurrent trip (A) | 1500.0 |
V_uv_trip |
Under-voltage trip fraction of Vnom | 0.80 |
V_ov_trip |
Over-voltage trip fraction of Vnom | 1.10 |
f_min_ied |
Under-frequency trip (Hz) | 47.5 |
f_max_ied |
Over-frequency trip (Hz) | 51.5 |
trip_delay_uv |
UV hold timer before trip (s) | 3.0 |
trip_delay_ov |
OV hold timer before trip (s) | 0.5 |
trip_delay_uf |
UF hold timer before trip (s) | 4.0 |
trip_delay_of |
OF hold timer before trip (s) | 0.5 |
Output signals (IF-BR01 to EMS Alarm Manager):
| Signal | Type | Description |
|---|---|---|
breaker_status |
bool | True = CLOSED, False = OPEN |
trip_alarm |
bool | True = protection trip occurred |
trip_cause |
string | "OC", "UV", "OV", "UF", "OF", "Manual" |
Interface note:
breaker_statusis consumed by the EMS Alarm Manager using:if not breaker_status: alarms["critical"] = True alarms["source"] = "Breaker_Open"
5. Complete Interface Signal Table (Cross-System)
All signals defined below are the canonical interface contracts between the three simulation models.
Grid → EMS
| Signal | IF-ID | From | To | Unit |
|---|---|---|---|---|
P_pcc |
IF-GM01 | PCC Meter | EMS P_error = P_target - P_pcc |
MW |
Q_pcc |
IF-GM01 | PCC Meter | EMS reactive control | MVAr |
V_pcc |
IF-GM01 | PCC Meter | EMS voltage control / alarm | kV |
f |
IF-GM01 | PCC Meter | EMS alarm frequency check | Hz |
breaker_status |
IF-BR01 | Breaker IED | EMS alarm_state["critical"] |
bool |
trip_alarm |
IF-BR01 | Breaker IED | EMS Alarm Manager | bool |
EMS → Grid
| Signal | IF-ID | From | To | Unit |
|---|---|---|---|---|
breaker_open_cmd |
IF-BR02 | EMS Alarm Manager | Breaker IED | bool |
BESS → Grid (AC Bus)
| Signal | IF-ID | From | To | Unit |
|---|---|---|---|---|
P_bess_output |
IF-BE01 | BESS PCS Pout |
Grid P_pcc computation |
MW |
Q_bess_output |
IF-BE01 | BESS PCS Qout |
Grid Q_pcc computation |
MVAr |
EMS → BESS
| Signal | IF-ID | From | To | Unit |
|---|---|---|---|---|
P_bess_setpoint |
IF-BE02 | EMS Coordinator | BESS PCS Preq |
MW (+ = charge) |
Q_bess_setpoint |
IF-BE02 | EMS Coordinator | BESS PCS Qreq |
MVAr |
BESS → EMS
| Signal | IF-ID | From | To | Unit |
|---|---|---|---|---|
SoC |
IF-BM01 | BESS BMS | EMS Coordinator | 0.0–1.0 |
P_lim_chg |
IF-BM01 | BESS BMS | EMS Ramp Manager + Coordinator | MW |
P_lim_dis |
IF-BM01 | BESS BMS | EMS Ramp Manager + Coordinator | MW |
bms_critical_alarm |
IF-BM01 | BESS BMS | EMS Alarm Manager | bool |