surge_network/dynamics/models.rs
1// SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0
2//! Dynamic model types for transient stability analysis.
3//!
4//! This module defines data structures for electromechanical generator models,
5//! excitation systems, turbine-governors, and power system stabilizers loaded
6//! from PSS/E `.dyr` files.
7//!
8//! # Supported models
9//!
10//! - **Generators**: GENCLS, GENROU, GENSAL
11//! - **Exciters**: EXST1, ESST3A, ESDC2A, EXDC2, IEEEX1/IEEEXC1
12//! - **Governors**: TGOV1, IEEEG1
13//! - **PSS**: IEEEST, ST2CUT
14//!
15//! # Simplified vs. detailed models (DYN-01)
16//!
17//! Several models in this module are **standard planning-level simplifications**,
18//! suitable for use when detailed dynamic data is unavailable. For precise
19//! transient stability studies, use the detailed models when dynamic test data
20//! files (DYRE) provide the necessary parameters.
21//!
22//! ## Exciter model mapping
23//!
24//! | Simplified model | Detailed equivalent | When to upgrade |
25//! |------------------|---------------------------|----------------------------------------|
26//! | SEXS | AC5A, ESST4B, EXAC1 | Detailed AVR test data available |
27//! | SCRX | ESST4B, ESST3A | Static exciter field test data |
28//! | IEEET1 | ESDC2A, EXDC2, IEEEX1 | Rotating exciter field data |
29//!
30//! ## Governor model mapping
31//!
32//! | Simplified model | Detailed equivalent | When to upgrade |
33//! |------------------|---------------------------|----------------------------------------|
34//! | GAST | GAST2A, GGOV1 | Gas turbine performance test data |
35//! | TGOV1 | IEEEG1, TGOV5 | Steam turbine test data with reheat |
36//!
37//! ## IBR (inverter-based resource) models
38//!
39//! | Simplified model | Detailed equivalent | When to upgrade |
40//! |------------------|---------------------------|----------------------------------------|
41//! | REPC_A (simplified) | Full REPC_A with AGC droop | Plant-level control parameters |
42//! | REEC_A (simplified) | Full REEC_A with Kqv droop | Electrical controller test data |
43//! | REGC_A | (already detailed) | N/A |
44//!
45//! The simplified IBR models use constant Pref/Qref (no AGC droop or plant-level
46//! voltage regulation), which is acceptable for planning-level studies where the
47//! IBR is not the focus. For studies involving IBR fault ride-through, frequency
48//! response, or voltage regulation, use the full model parameters.
49
50use serde::{Deserialize, Serialize};
51
52// ---------------------------------------------------------------------------
53// Top-level container
54// ---------------------------------------------------------------------------
55
56/// Complete dynamic model database parsed from a `.dyr` file.
57#[derive(Debug, Clone, Default, Serialize, Deserialize)]
58pub struct DynamicModel {
59 /// Generator dynamic models (GENCLS, GENROU, GENSAL).
60 pub generators: Vec<GeneratorDyn>,
61 /// Excitation system models (EXST1, ESST3A, ESDC2A, EXDC2, IEEEX1).
62 pub exciters: Vec<ExciterDyn>,
63 /// Turbine-governor models (TGOV1, IEEEG1).
64 pub governors: Vec<GovernorDyn>,
65 /// Power system stabilizer models (IEEEST, ST2CUT).
66 pub pss: Vec<PssDyn>,
67 /// Load dynamic models (CLOD, INDMOT, MOTOR) — Phase 12.
68 #[serde(default)]
69 pub loads: Vec<LoadDyn>,
70 /// FACTS/HVDC dynamic models (CSVGN1, CSTCON, TCSC, CDC4T, VSCDCT) — Phase 13.
71 #[serde(default)]
72 pub facts: Vec<FACTSDyn>,
73 /// Records with unrecognised model names — stored verbatim for diagnostics.
74 pub unknown_records: Vec<UnknownDyrRecord>,
75 /// Over-excitation limiter models (OEL1B, OEL2C, SCL1C) — Wave 37.
76 #[serde(default)]
77 pub oels: Vec<OelDyn>,
78 /// Under-excitation limiter models (UEL1, UEL2C) — Wave 37.
79 #[serde(default)]
80 pub uels: Vec<UelDyn>,
81 /// Multi-mass torsional shaft models for time-domain SSR simulation.
82 #[serde(default)]
83 pub shafts: Vec<ShaftDyn>,
84}
85
86impl DynamicModel {
87 /// Number of generator dynamic records.
88 pub fn n_generators(&self) -> usize {
89 self.generators.len()
90 }
91
92 /// Number of exciter records.
93 pub fn n_exciters(&self) -> usize {
94 self.exciters.len()
95 }
96
97 /// Number of governor records.
98 pub fn n_governors(&self) -> usize {
99 self.governors.len()
100 }
101
102 /// Number of PSS records.
103 pub fn n_pss(&self) -> usize {
104 self.pss.len()
105 }
106
107 /// Number of load dynamic records.
108 pub fn n_loads(&self) -> usize {
109 self.loads.len()
110 }
111
112 /// Total number of recognised dynamic records.
113 pub fn total(&self) -> usize {
114 self.n_generators()
115 + self.n_exciters()
116 + self.n_governors()
117 + self.n_pss()
118 + self.n_loads()
119 + self.n_facts()
120 + self.oels.len()
121 + self.uels.len()
122 + self.shafts.len()
123 }
124
125 /// Compute supported model coverage.
126 /// Returns `(n_supported, n_total, coverage_pct)`.
127 pub fn coverage(&self) -> (usize, usize, f64) {
128 let n_supported = self.total();
129 let n_unknown = self.unknown_records.len();
130 let n_total = n_supported + n_unknown;
131 let pct = if n_total > 0 {
132 n_supported as f64 / n_total as f64 * 100.0
133 } else {
134 100.0
135 };
136 (n_supported, n_total, pct)
137 }
138
139 /// Number of FACTS/HVDC dynamic records.
140 pub fn n_facts(&self) -> usize {
141 self.facts.len()
142 }
143
144 /// Find the first FACTS/HVDC dynamic record at the given bus with the given device ID.
145 pub fn find_facts(&self, bus: u32, device_id: &str) -> Option<&FACTSDyn> {
146 self.facts
147 .iter()
148 .find(|f| f.bus == bus && f.device_id == device_id)
149 }
150
151 /// Find the first load dynamic record at the given bus with the given load ID.
152 pub fn find_load(&self, bus: u32, load_id: &str) -> Option<&LoadDyn> {
153 self.loads
154 .iter()
155 .find(|l| l.bus == bus && l.load_id == load_id)
156 }
157
158 /// Find the first generator dynamic record at the given bus with the given machine ID.
159 pub fn find_generator(&self, bus: u32, machine_id: &str) -> Option<&GeneratorDyn> {
160 self.generators
161 .iter()
162 .find(|g| g.bus == bus && g.machine_id == machine_id)
163 }
164
165 /// Find the first exciter record at the given bus with the given machine ID.
166 pub fn find_exciter(&self, bus: u32, machine_id: &str) -> Option<&ExciterDyn> {
167 self.exciters
168 .iter()
169 .find(|e| e.bus == bus && e.machine_id == machine_id)
170 }
171
172 /// Find the first governor record at the given bus with the given machine ID.
173 pub fn find_governor(&self, bus: u32, machine_id: &str) -> Option<&GovernorDyn> {
174 self.governors
175 .iter()
176 .find(|g| g.bus == bus && g.machine_id == machine_id)
177 }
178
179 /// Find the first PSS record at the given bus with the given machine ID.
180 pub fn find_pss(&self, bus: u32, machine_id: &str) -> Option<&PssDyn> {
181 self.pss
182 .iter()
183 .find(|p| p.bus == bus && p.machine_id == machine_id)
184 }
185
186 /// Find the first shaft dynamic record at the given bus with the given machine ID.
187 pub fn find_shaft(&self, bus: u32, machine_id: &str) -> Option<&ShaftDyn> {
188 self.shafts
189 .iter()
190 .find(|s| s.bus == bus && s.machine_id == machine_id)
191 }
192
193 // -----------------------------------------------------------------------
194 // USRMDL transparency — summary report & gap analysis
195 // -----------------------------------------------------------------------
196
197 /// Build a summary report of unknown/unrecognized dynamic models.
198 ///
199 /// Groups unknown records by model name, counts occurrences, lists affected
200 /// buses, and suggests standard equivalents where known.
201 pub fn unknown_model_summary(&self) -> Vec<UnknownModelGroup> {
202 use std::collections::BTreeMap;
203
204 let mut groups: BTreeMap<String, UnknownModelGroup> = BTreeMap::new();
205 for rec in &self.unknown_records {
206 let entry = groups.entry(rec.model_name.clone()).or_insert_with(|| {
207 let equiv = crate::dynamics::usrmdl_equiv::suggest_equivalent(&rec.model_name);
208 let category = crate::dynamics::usrmdl_equiv::guess_category(&rec.model_name);
209 UnknownModelGroup {
210 model_name: rec.model_name.clone(),
211 count: 0,
212 buses: Vec::new(),
213 category: category.label().to_string(),
214 suggested_equivalent: equiv.map(|e| e.suggested.to_string()),
215 suggestion_notes: equiv.map(|e| e.notes.to_string()),
216 }
217 });
218 entry.count += 1;
219 if !entry.buses.contains(&rec.bus) {
220 entry.buses.push(rec.bus);
221 }
222 }
223
224 groups.into_values().collect()
225 }
226
227 /// Find generators that have a generator model but are missing one or more
228 /// of: exciter, governor, or PSS.
229 ///
230 /// Returns `(bus, machine_id, has_exciter, has_governor, has_pss)` tuples.
231 pub fn incomplete_machines(&self) -> Vec<IncompleteMachine> {
232 self.generators
233 .iter()
234 .filter_map(|g| {
235 let has_exc = self.find_exciter(g.bus, &g.machine_id).is_some();
236 let has_gov = self.find_governor(g.bus, &g.machine_id).is_some();
237 let has_pss = self.find_pss(g.bus, &g.machine_id).is_some();
238 // Report if missing any component (exciter, governor, or PSS)
239 if !has_exc || !has_gov || !has_pss {
240 Some(IncompleteMachine {
241 bus: g.bus,
242 machine_id: g.machine_id.clone(),
243 has_exciter: has_exc,
244 has_governor: has_gov,
245 has_pss,
246 })
247 } else {
248 None
249 }
250 })
251 .collect()
252 }
253}
254
255/// Summary of an unrecognized dynamic model group.
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct UnknownModelGroup {
258 /// Model name as read from the DYR file.
259 pub model_name: String,
260 /// Number of records with this model name.
261 pub count: usize,
262 /// Unique bus numbers where this model appears.
263 pub buses: Vec<u32>,
264 /// Guessed category (Generator, Exciter, Governor, PSS, etc.).
265 pub category: String,
266 /// Suggested standard equivalent model name, if known.
267 pub suggested_equivalent: Option<String>,
268 /// Notes about the suggested mapping.
269 pub suggestion_notes: Option<String>,
270}
271
272/// A generator with an incomplete dynamic model representation.
273#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct IncompleteMachine {
275 /// Bus number.
276 pub bus: u32,
277 /// Machine ID.
278 pub machine_id: String,
279 /// Whether an exciter model was found.
280 pub has_exciter: bool,
281 /// Whether a governor model was found.
282 pub has_governor: bool,
283 /// Whether a PSS model was found.
284 pub has_pss: bool,
285}
286
287// ---------------------------------------------------------------------------
288// Generator dynamic records
289// ---------------------------------------------------------------------------
290
291/// A generator dynamic model record (GENCLS, GENROU, or GENSAL).
292#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct GeneratorDyn {
294 /// Bus number of the associated static generator.
295 pub bus: u32,
296 /// Machine ID (matches PSS/E machine ID field, e.g. `"1"`, `"G1"`, `"WND"`).
297 pub machine_id: String,
298 /// The specific generator model and its parameters.
299 pub model: GeneratorModel,
300}
301
302/// Discriminated union of supported generator dynamic models.
303#[derive(Debug, Clone, Serialize, Deserialize)]
304#[serde(tag = "type")]
305pub enum GeneratorModel {
306 Gencls(GenclsParams),
307 Genrou(GenrouParams),
308 Gensal(GensalParams),
309 /// REGC_A — IBR inner converter (voltage-source Norton equivalent, no swing equation).
310 Regca(RegcaParams),
311 Gentpj(GentpjParams),
312 Genqec(GenqecParams),
313 /// REGCB — enhanced IBR inner converter.
314 Regcb(RegcbParams),
315 /// WT3G2U — Type 3 (DFIG) wind generator.
316 Wt3g2u(Wt3g2uParams),
317 /// WT4G1 — Type 4 (full-converter) wind generator.
318 Wt4g1(Wt4g1Params),
319 /// REGFM_A1 — Grid-forming inverter (droop).
320 RegfmA1(RegfmA1Params),
321 /// REGFM_B1 — Grid-forming inverter (VSM).
322 RegfmB1(RegfmB1Params),
323 /// DER_A — Distributed energy resource aggregate.
324 Dera(DeraParams),
325 /// GENTRA — Third-order transient generator (3 states: δ, ω, E'q).
326 Gentra(GentraParams),
327 /// GENTPF — Flux-based saturation round-rotor (same state/equations as GENTPJ).
328 Gentpf(GentpjParams),
329 /// REGCC — Next-gen GFM-capable converter (4 states).
330 Regcc(RegccParams),
331 /// WT4G2 — Type 4 wind variant GE (2 states, same as WT4G1).
332 Wt4g2(Wt4g2Params),
333 /// DER_C / DERC — DER_A variant C (3 states).
334 Derc(DercParams),
335 // Phase 21
336 /// GENROA — GENROU with additional AVR interface (Phase 21, same state as GENROU).
337 Genroa(GenrouParams),
338 /// GENSAA — GENSAL with additional AVR interface (Phase 21, same state as GENSAL).
339 Gensaa(GensalParams),
340 /// REGFM_C1 — Grid-forming inverter C1 (Phase 21).
341 RegfmC1(RegfmC1Params),
342 // Phase 22
343 /// PVGU1 — WECC 1st-gen photovoltaic converter unit (Phase 22).
344 Pvgu1(Pvgu1Params),
345 /// PVDG — Distributed/rooftop PV aggregate model (Phase 22).
346 Pvdg(PvdgParams),
347 // Phase 27
348 /// WT3G3 — Type 3 wind generator variant 3 (Phase 27, reuses Wt3g2u dynamics).
349 Wt3g3(Wt3g2uParams),
350 /// REGCO1 — Grid-following converter generator (Phase 27, 4 states).
351 Regco1(Regco1Params),
352 /// GENWTG — Alias for GENROU (Phase 27).
353 Genwtg(GenrouParams),
354 /// GENROE — GENROU with extended saturation (Phase 27, reuses GENROU params).
355 Genroe(GenrouParams),
356 /// GENSAL3 — Third-order salient-pole generator (Phase 27, 3 dynamic states).
357 Gensal3(Gensal3Params),
358 // Phase 28
359 /// DERP — DER with Protection (Phase 28, 2 states).
360 Derp(DerpParams),
361 /// REGFM_D1 — WECC hybrid GFM/GFL converter (Phase 28, 8 states).
362 RegfmD1(Regfmd1Params),
363 // Wave 34
364 /// GENSAE — Salient-pole with exponential saturation (reuses GensalParams).
365 Gensae(GensalParams),
366 // Wave 36: legacy wind and distributed PV
367 /// WT1G1 — Type 1 fixed-speed wind generator (Wave 36, IBR equivalent).
368 Wt1g1(Wt1g1Params),
369 /// WT2G1 — Type 2 variable-slip wind generator (Wave 36, alias Wt1g1Params).
370 Wt2g1(Wt1g1Params),
371 /// PVD1 — Distributed PV aggregate (Wave 36, alias PvdgParams).
372 Pvd1(PvdgParams),
373 /// PVDU1 — PV distributed unit (Wave 36, alias Pvgu1Params).
374 Pvdu1(Pvgu1Params),
375}
376
377// --- GENCLS ------------------------------------------------------------------
378
379/// Classical generator model — swing equation only.
380///
381/// PSS/E params: `H D`
382#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct GenclsParams {
384 /// Inertia constant (s).
385 pub h: f64,
386 /// Damping coefficient (pu).
387 pub d: f64,
388}
389
390// --- GENROU ------------------------------------------------------------------
391
392/// Round-rotor synchronous generator (full-order, PSS/E GENROU).
393///
394/// PSS/E params (14 required, Ra optional):
395/// `Td0' Td0'' Tq0' Tq0'' H D Xd Xq Xd' Xq' Xd'' Xl S(1.0) S(1.2) [Ra]`
396#[derive(Debug, Clone, Serialize, Deserialize)]
397pub struct GenrouParams {
398 /// d-axis open-circuit transient time constant (s).
399 pub td0_prime: f64,
400 /// d-axis open-circuit sub-transient time constant (s).
401 pub td0_pprime: f64,
402 /// q-axis open-circuit transient time constant (s).
403 pub tq0_prime: f64,
404 /// q-axis open-circuit sub-transient time constant (s).
405 pub tq0_pprime: f64,
406 /// Inertia constant (s).
407 pub h: f64,
408 /// Damping coefficient (pu).
409 pub d: f64,
410 /// d-axis synchronous reactance (pu).
411 pub xd: f64,
412 /// q-axis synchronous reactance (pu).
413 pub xq: f64,
414 /// d-axis transient reactance (pu).
415 pub xd_prime: f64,
416 /// q-axis transient reactance (pu).
417 pub xq_prime: f64,
418 /// d-axis sub-transient reactance (pu).
419 pub xd_pprime: f64,
420 /// Leakage reactance (pu).
421 pub xl: f64,
422 /// Saturation factor at 1.0 pu.
423 pub s1: f64,
424 /// Saturation factor at 1.2 pu.
425 pub s12: f64,
426 /// Armature resistance (pu) — optional trailing field.
427 #[serde(default, skip_serializing_if = "Option::is_none")]
428 pub ra: Option<f64>,
429}
430
431// --- GENSAL ------------------------------------------------------------------
432
433/// Salient-pole synchronous generator (PSS/E GENSAL).
434///
435/// PSS/E params (13 required):
436/// `Td0' Td0'' Tq0'' H D Xd Xq Xd' Xd'' Xl S(1.0) S(1.2) Xtran`
437#[derive(Debug, Clone, Serialize, Deserialize)]
438pub struct GensalParams {
439 /// d-axis open-circuit transient time constant (s).
440 pub td0_prime: f64,
441 /// d-axis open-circuit sub-transient time constant (s).
442 pub td0_pprime: f64,
443 /// q-axis open-circuit sub-transient time constant (s).
444 pub tq0_pprime: f64,
445 /// Inertia constant (s).
446 pub h: f64,
447 /// Damping coefficient (pu).
448 pub d: f64,
449 /// d-axis synchronous reactance (pu).
450 pub xd: f64,
451 /// q-axis synchronous reactance (pu).
452 pub xq: f64,
453 /// d-axis transient reactance (pu).
454 pub xd_prime: f64,
455 /// d-axis sub-transient reactance (pu).
456 pub xd_pprime: f64,
457 /// Leakage reactance (pu).
458 pub xl: f64,
459 /// Saturation factor at 1.0 pu.
460 pub s1: f64,
461 /// Saturation factor at 1.2 pu.
462 pub s12: f64,
463 /// Transient reactance for saturation (pu).
464 pub xtran: f64,
465}
466
467// --- REGCA ------------------------------------------------------------------
468
469/// IBR inner converter model (PSS/E REGC_A).
470///
471/// Models the converter as a controlled current source behind a small reactance.
472/// No swing equation — IBR is grid-following (ω = 1.0 always).
473///
474/// Key params: `Tg Xeq Imax Tfltr`
475#[derive(Debug, Clone, Serialize, Deserialize)]
476pub struct RegcaParams {
477 /// Converter current control time constant (s).
478 pub tg: f64,
479 /// Equivalent reactance for Norton shunt (pu system base) — default 0.02 pu.
480 pub x_eq: f64,
481 /// Maximum current magnitude limit (pu machine base).
482 pub imax: f64,
483 /// Voltage filter time constant (s).
484 pub tfltr: f64,
485 // --- Phase 1: PLL, current ramp, voltage dip parameters ---
486 /// PLL proportional gain.
487 pub kp_pll: f64,
488 /// PLL integral gain.
489 pub ki_pll: f64,
490 /// Current ramp rate limit (pu/s) for LVACM/current recovery.
491 pub rrpwr: f64,
492 /// Low-voltage threshold for momentary cessation (pu).
493 pub vdip: f64,
494 /// High-voltage threshold for momentary cessation (pu).
495 pub vup: f64,
496}
497
498// ---------------------------------------------------------------------------
499// Phase 11: IBR / Wind / GFM / DER generator records
500// ---------------------------------------------------------------------------
501
502/// REGCB — enhanced IBR inner converter with IP filter.
503#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct RegcbParams {
505 pub tg: f64,
506 pub x_eq: f64,
507 pub imax: f64,
508 pub tfltr: f64,
509 pub tip: f64,
510 /// PLL proportional gain.
511 pub kp_pll: f64,
512 /// PLL integral gain.
513 pub ki_pll: f64,
514}
515
516/// WT3G2U — Type 3 (DFIG) wind turbine generator.
517///
518/// Full DFIG model: RSC controls d/q rotor currents via first-order lags
519/// (`t_rotor`). Electrical torque couples through mutual inductance ratio
520/// `lm_over_ls`. PLL tracks grid voltage angle with PI gains `kpll`/`kipll`.
521#[derive(Debug, Clone, Serialize, Deserialize)]
522pub struct Wt3g2uParams {
523 /// Current command time constant (s) — lag from exciter ip/iq_ref to ip/iq_cmd.
524 pub tg: f64,
525 /// Equivalent source reactance (pu).
526 pub x_eq: f64,
527 /// Maximum current limit (pu).
528 pub imax: f64,
529 /// Voltage filter time constant (s).
530 pub tfltr: f64,
531 /// PLL proportional gain.
532 pub kpll: f64,
533 /// PLL integral gain (rad/s per pu freq error).
534 pub kipll: f64,
535 /// Rotor inertia constant (s, MWs/MVA).
536 pub h_rotor: f64,
537 /// Rotor damping coefficient.
538 pub d_rotor: f64,
539 /// Rotor current time constant (s) — RSC current control lag.
540 /// Default 0.02 s if zero or absent.
541 pub t_rotor: f64,
542 /// Mutual-to-stator inductance ratio Lm/Ls (pu).
543 /// Default 0.9 if zero or absent (typical DFIG value).
544 pub lm_over_ls: f64,
545}
546
547/// WT4G1 — Type 4 (full-converter) wind turbine generator.
548#[derive(Debug, Clone, Serialize, Deserialize)]
549pub struct Wt4g1Params {
550 pub tg: f64,
551 pub x_eq: f64,
552 pub imax: f64,
553 /// PLL proportional gain.
554 pub kp_pll: f64,
555 /// PLL integral gain.
556 pub ki_pll: f64,
557}
558
559/// REGFM_A1 — Grid-forming inverter (droop control, 9 dynamic states).
560///
561/// ## States
562///
563/// 1. δ — angle (rad)
564/// 2. ω — speed (pu)
565/// 3. i_d — d-axis current command (pu)
566/// 4. i_q — q-axis current command (pu)
567/// 5. v_filt — voltage measurement filter (pu)
568/// 6. x_pll — PLL frequency estimation state
569/// 7. x_vi — virtual impedance filter state (pu)
570/// 8. x_droop_p — P-f droop integrator (pu)
571/// 9. x_droop_q — Q-V droop integrator (pu)
572#[derive(Debug, Clone, Serialize, Deserialize)]
573pub struct RegfmA1Params {
574 pub x_eq: f64,
575 pub h: f64,
576 pub d: f64,
577 pub imax: f64,
578 /// Current injection time constant (s, default 0.02).
579 pub tg: f64,
580 /// Voltage measurement filter time constant (s, default 0.02).
581 #[serde(default = "default_gfm_tv")]
582 pub tv: f64,
583 /// PLL time constant (s, default 0.02).
584 #[serde(default = "default_gfm_tpll")]
585 pub tpll: f64,
586 /// Virtual impedance filter time constant (s, default 0.05).
587 #[serde(default = "default_gfm_tvi")]
588 pub tvi: f64,
589 /// P-f droop gain (pu power / pu freq, default 20.0 = 5% droop).
590 #[serde(default = "default_gfm_kp_droop")]
591 pub kp_droop: f64,
592 /// P-f droop integral gain (default 0.0 = pure proportional).
593 #[serde(default)]
594 pub ki_droop: f64,
595 /// Q-V droop gain (pu reactive / pu voltage, default 20.0).
596 #[serde(default = "default_gfm_kq_droop")]
597 pub kq_droop: f64,
598 /// Q-V droop integral gain (default 0.0).
599 #[serde(default)]
600 pub ki_q: f64,
601 /// Virtual resistance (pu, default 0.0).
602 #[serde(default)]
603 pub r_vi: f64,
604 /// Virtual reactance (pu, default 0.1).
605 #[serde(default = "default_gfm_x_vi")]
606 pub x_vi: f64,
607}
608
609fn default_gfm_tv() -> f64 {
610 0.02
611}
612fn default_gfm_tpll() -> f64 {
613 0.02
614}
615fn default_gfm_tvi() -> f64 {
616 0.05
617}
618fn default_gfm_kp_droop() -> f64 {
619 20.0
620}
621fn default_gfm_kq_droop() -> f64 {
622 20.0
623}
624fn default_gfm_x_vi() -> f64 {
625 0.1
626}
627
628/// REGFM_B1 — Grid-forming inverter (virtual synchronous machine, 9 dynamic states).
629///
630/// Same state structure as RegfmA1 but with VSM control philosophy:
631/// the swing equation emulates a synchronous machine rather than direct droop.
632#[derive(Debug, Clone, Serialize, Deserialize)]
633pub struct RegfmB1Params {
634 pub x_eq: f64,
635 pub h: f64,
636 pub d: f64,
637 pub imax: f64,
638 /// Current injection time constant (s, default 0.02).
639 pub tg: f64,
640 /// Voltage measurement filter time constant (s, default 0.02).
641 #[serde(default = "default_gfm_tv")]
642 pub tv: f64,
643 /// PLL time constant (s, default 0.02).
644 #[serde(default = "default_gfm_tpll")]
645 pub tpll: f64,
646 /// Virtual impedance filter time constant (s, default 0.05).
647 #[serde(default = "default_gfm_tvi")]
648 pub tvi: f64,
649 /// P-f droop gain (pu power / pu freq, default 20.0 = 5% droop).
650 #[serde(default = "default_gfm_kp_droop")]
651 pub kp_droop: f64,
652 /// P-f droop integral gain (default 0.0).
653 #[serde(default)]
654 pub ki_droop: f64,
655 /// Q-V droop gain (pu reactive / pu voltage, default 20.0).
656 #[serde(default = "default_gfm_kq_droop")]
657 pub kq_droop: f64,
658 /// Q-V droop integral gain (default 0.0).
659 #[serde(default)]
660 pub ki_q: f64,
661 /// Virtual resistance (pu, default 0.0).
662 #[serde(default)]
663 pub r_vi: f64,
664 /// Virtual reactance (pu, default 0.1).
665 #[serde(default = "default_gfm_x_vi")]
666 pub x_vi: f64,
667}
668
669/// DER_A — Distributed energy resource aggregate model.
670#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct DeraParams {
672 pub x_eq: f64,
673 pub trf: f64,
674 pub imax: f64,
675 pub trv: f64,
676}
677
678// ---------------------------------------------------------------------------
679// Phase 15: Generator variants
680// ---------------------------------------------------------------------------
681
682/// GENTRA — Third-order transient generator (3 states: δ, ω, E'q).
683///
684/// Simplified round-rotor model: classical swing + single transient EMF.
685/// No sub-transient dynamics (Xd'' = Xd', Td0'' → ∞).
686///
687/// PSS/E params: `H D Ra Xd Xd' Td0' Xq`
688#[derive(Debug, Clone, Serialize, Deserialize)]
689pub struct GentraParams {
690 /// Inertia constant (s).
691 pub h: f64,
692 /// Damping coefficient (pu).
693 pub d: f64,
694 /// Armature resistance (pu).
695 pub ra: f64,
696 /// d-axis synchronous reactance (pu).
697 pub xd: f64,
698 /// d-axis transient reactance (pu).
699 pub xd_prime: f64,
700 /// d-axis open-circuit transient time constant (s).
701 pub td0_prime: f64,
702 /// q-axis synchronous reactance (pu).
703 pub xq: f64,
704 /// Saturation factor at 1.0 pu (0.0 = unsaturated).
705 pub s1: f64,
706 /// Saturation factor at 1.2 pu (0.0 = unsaturated).
707 pub s12: f64,
708}
709
710/// REGCC — Next-gen GFM-capable converter (4 states).
711///
712/// Grid-following converter with PLL state for frequency tracking.
713#[derive(Debug, Clone, Serialize, Deserialize)]
714pub struct RegccParams {
715 /// Converter current control time constant (s).
716 pub tg: f64,
717 /// Equivalent reactance (pu system base).
718 pub x_eq: f64,
719 /// Maximum current magnitude (pu machine base).
720 pub imax: f64,
721 /// Voltage filter time constant (s).
722 pub tfltr: f64,
723 /// PLL time constant (s).
724 pub t_pll: f64,
725}
726
727/// WT4G2 — Type 4 wind generator variant GE (2 states, same as WT4G1).
728#[derive(Debug, Clone, Serialize, Deserialize)]
729pub struct Wt4g2Params {
730 pub tg: f64,
731 pub x_eq: f64,
732 pub imax: f64,
733 /// PLL proportional gain.
734 pub kp_pll: f64,
735 /// PLL integral gain.
736 pub ki_pll: f64,
737}
738
739/// DER_C / DERC — DER_A variant C (3 states: p_rec, q_rec, vfilt).
740#[derive(Debug, Clone, Serialize, Deserialize)]
741pub struct DercParams {
742 pub tp: f64,
743 pub tq: f64,
744 pub tv: f64,
745 pub mbase: f64,
746 pub lfac: f64,
747 /// Norton equivalent reactance (pu, default 0.02).
748 pub x_eq: f64,
749}
750
751// ---------------------------------------------------------------------------
752// Exciter records
753// ---------------------------------------------------------------------------
754
755/// An excitation system dynamic model record.
756#[derive(Debug, Clone, Serialize, Deserialize)]
757pub struct ExciterDyn {
758 pub bus: u32,
759 pub machine_id: String,
760 pub model: ExciterModel,
761}
762
763/// REEC_D — IBR electrical controller (drives voltage recovery).
764#[derive(Debug, Clone, Serialize, Deserialize)]
765pub struct ReecdParams {
766 /// Voltage deadband lower (pu, typically negative).
767 pub dbd1: f64,
768 /// Voltage deadband upper (pu, typically positive).
769 pub dbd2: f64,
770 /// Reactive current PI proportional gain.
771 pub kqv: f64,
772 /// Reactive current PI integral gain.
773 pub kqi: f64,
774 /// Voltage measurement filter time constant (s).
775 pub trv: f64,
776 /// Active power measurement filter time constant (s).
777 pub tp: f64,
778 /// Maximum reactive current (pu).
779 pub iqmax: f64,
780 /// Minimum reactive current (pu).
781 pub iqmin: f64,
782 /// Maximum active current (pu).
783 pub ipmax: f64,
784 /// Active power ramp rate limit (pu/s).
785 pub rrpwr: f64,
786 /// Frequency droop gain (down).
787 pub ddn: f64,
788 /// Frequency droop gain (up).
789 pub dup: f64,
790 /// Frequency deadband lower (Hz).
791 pub fdbd1: f64,
792 /// Frequency deadband upper (Hz).
793 pub fdbd2: f64,
794 /// Voltage dip threshold for momentary cessation (pu).
795 pub vdip: f64,
796 /// Voltage up threshold for momentary cessation (pu).
797 pub vup: f64,
798 /// Active power reference (pu).
799 pub pref: f64,
800 /// Max/min active power (pu).
801 pub pmax: f64,
802 pub pmin: f64,
803}
804
805/// REECCU / REECCU1 — IBR electrical controller, current-unlimited (PI + ramp).
806#[derive(Debug, Clone, Serialize, Deserialize)]
807pub struct ReeccuParams {
808 /// Voltage deadband (pu).
809 pub dbd1: f64,
810 /// Reactive current PI proportional gain.
811 pub kqv: f64,
812 /// Reactive current PI integral gain.
813 pub kqi: f64,
814 /// Voltage measurement filter time constant (s).
815 pub trv: f64,
816 /// Active power measurement filter time constant (s).
817 pub tp: f64,
818 /// Active power ramp rate limit (pu/s).
819 pub rrpwr: f64,
820 /// Voltage dip threshold for momentary cessation (pu).
821 pub vdip: f64,
822 /// Voltage up threshold for momentary cessation (pu).
823 pub vup: f64,
824 /// Active power reference (pu).
825 pub pref: f64,
826 /// Max/min active power (pu).
827 pub pmax: f64,
828 pub pmin: f64,
829}
830
831/// REXS — Excitation system with rate feedback.
832#[derive(Debug, Clone, Serialize, Deserialize)]
833pub struct RexsParams {
834 pub te: f64,
835 pub tf: f64,
836 pub ke: f64,
837 pub kf: f64,
838 pub efd1: f64,
839 pub efd2: f64,
840 pub sefd1: f64,
841 pub sefd2: f64,
842 /// Lead-lag numerator time constant (s). Zero = no lead-lag.
843 pub tc: f64,
844 /// Lead-lag denominator time constant (s). Zero = no lead-lag.
845 pub tb: f64,
846}
847
848/// Discriminated union of supported exciter models.
849#[derive(Debug, Clone, Serialize, Deserialize)]
850#[serde(tag = "type")]
851pub enum ExciterModel {
852 Exst1(Exst1Params),
853 Esst3a(Esst3aParams),
854 Esdc2a(Esdc2aParams),
855 Exdc2(Exdc2Params),
856 Ieeex1(Ieeex1Params),
857 /// SEXS — Simplified Exciter (common in planning studies).
858 Sexs(SexsParams),
859 /// IEEET1 — IEEE Type 1 rotating exciter (classic 1968 AVR).
860 Ieeet1(Ieeet1Params),
861 /// SCRX — Simplified Bus-Fed Static Exciter.
862 Scrx(ScrxParams),
863 /// REEC_A — IBR electrical controller (maps to exciter slot).
864 Reeca(ReecaParams),
865 Esst1a(Esst1aParams),
866 Exac1(Exac1Params),
867 /// ESAC1A — same params as EXAC1, different model tag.
868 Esac1a(Exac1Params),
869 Esac7b(Esac7bParams),
870 Esst4b(Esst4bParams),
871 /// REEC_D — IBR electrical controller (voltage recovery).
872 Reecd(ReecdParams),
873 /// REECCU — IBR electrical controller (curtailment).
874 Reeccu(ReeccuParams),
875 /// REXS — Excitation system with rate feedback.
876 Rexs(RexsParams),
877 /// ESAC2A — AC2A high-initial-response rotating exciter (Phase 14).
878 Esac2a(Esac2aParams),
879 /// ESAC5A — AC5A simplified brushless exciter (Phase 14).
880 Esac5a(Esac5aParams),
881 /// ESST5B — IEEE ST5B static exciter (Phase 15, 3 states).
882 Esst5b(Esst5bParams),
883 /// EXAC4 / AC4A — IEEE AC4A controlled-rectifier exciter (Phase 15, 2 states).
884 Exac4(Exac4Params),
885 // Phase 17
886 /// ESST6B — IEEE ST6B Static Exciter (Phase 17).
887 Esst6b(Esst6bParams),
888 /// ESST7B — IEEE ST7B Static Exciter (Phase 17).
889 Esst7b(Esst7bParams),
890 /// ESAC6A — AC6A Rotating Exciter (Phase 17).
891 Esac6a(Esac6aParams),
892 /// ESDC1A — DC1A Rotating Exciter (Phase 17).
893 Esdc1a(Esdc1aParams),
894 /// EXST2 — Static Exciter Type ST2 (Phase 17).
895 Exst2(Exst2Params),
896 /// AC8B — IEEE AC8B High Initial Response Exciter (Phase 17).
897 Ac8b(Ac8bParams),
898 /// BBSEX1 — Bus-Branch Static Exciter 1 (Phase 17).
899 Bbsex1(Bbsex1Params),
900 /// IEEET3 — IEEE Type 3 Rotating Exciter (Phase 17).
901 Ieeet3(Ieeet3Params),
902 // Phase 19
903 /// WT3E1 — Type 3 Wind Electrical Controller (Phase 19).
904 Wt3e1(Wt3e1Params),
905 /// WT3E2 — Type 3 Wind Electrical Controller Variant 2 (Phase 19).
906 Wt3e2(Wt3e2Params),
907 /// WT4E1 — Type 4 Wind Electrical Controller (Phase 19).
908 Wt4e1(Wt4e1Params),
909 /// WT4E2 — Type 4 Wind Electrical Controller Variant 2 (Phase 19).
910 Wt4e2(Wt4e1Params),
911 /// REPCB — REPCA Variant B (Phase 19).
912 Repcb(RepcbParams),
913 /// REPCC — REPCA Variant C (Phase 19, same params as REPCB).
914 Repcc(RepcbParams),
915 // Phase 21
916 /// EXST3 — Static Exciter Type ST3 (Phase 21).
917 Exst3(Exst3Params),
918 /// CBUFR — Buffer-Frequency-Regulated BESS (Phase 21).
919 Cbufr(CbufrParams),
920 /// CBUFD — Buffer-Frequency-Dependent BESS (Phase 21).
921 Cbufd(CbufdParams),
922 // Phase 22
923 /// PVEU1 — WECC 1st-gen PV electrical control unit (Phase 22, maps to exciter slot).
924 Pveu1(Pveu1Params),
925 // Phase 23
926 /// IEEET2 — IEEE Type 2 rotating-machine exciter (Phase 23).
927 Ieeet2(Ieeet2Params),
928 /// EXAC2 — IEEE AC2A high initial response rotating exciter (Phase 23).
929 Exac2(Exac2Params),
930 /// EXAC3 — IEEE AC3A controlled-rectifier exciter (Phase 23).
931 Exac3(Exac3Params),
932 /// ESAC3A — IEEE 421.5-2005 AC3A exciter update (Phase 23).
933 Esac3a(Esac3aParams),
934 /// ESST8C — IEEE 421.5-2016 ST8C static exciter (Phase 23).
935 Esst8c(Esst8cParams),
936 /// ESST9B — IEEE 421.5-2016 ST9B static exciter (Phase 23).
937 Esst9b(Esst9bParams),
938 /// ESST10C — IEEE 421.5-2016 ST10C static exciter (Phase 23).
939 Esst10c(Esst10cParams),
940 /// ESDC3A — IEEE 421.5-2005 DC3A rotating-machine exciter (Phase 23).
941 Esdc3a(Esdc3aParams),
942 // Wave 32
943 /// EXDC1 — IEEE Type DC1A rotating-machine exciter (legacy 13-param form).
944 Exdc1(Exdc1Params),
945 /// ESST2A — IEEE 421.5-2016 Type ST2A static exciter.
946 Esst2a(Esst2aParams),
947 // Wave 33
948 /// EXDC3 — PSS/E non-continuously-acting (relay-type) DC exciter (legacy).
949 Exdc3(Exdc3Params),
950 // Phase 27
951 /// WT3C2 — Type 3 wind electrical controller variant 2 (Phase 27, same params as WT3E1).
952 Wt3c2(Wt3e1Params),
953 // Wave 35
954 /// ESAC7C — IEEE 421.5-2016 AC7C exciter (same structure as ESAC7B, C-series).
955 Esac7c(Esac7cParams),
956 /// ESDC4C — IEEE 421.5-2016 DC4C exciter (PID + DC rotating, 3 states).
957 Esdc4c(Esdc4cParams),
958 // Wave 36: new REEC variants
959 /// REECBU1 — REEC variant B for Unit (Wave 36, alias ReeccuParams).
960 Reecbu1(ReeccuParams),
961 /// REECE — Enhanced REECA with voltage ride-through (Wave 36, alias ReecaParams).
962 Reece(ReecaParams),
963 /// REECEU1 — REECE curtailment variant (Wave 36, alias ReeccuParams).
964 Reeceu1(ReeccuParams),
965 // Wave 37: IEEE 421.5-2016 C-series AC exciters
966 /// ESAC8C — IEEE 421.5-2016 AC8C high-initial-response exciter (alias AC8B structure).
967 Esac8c(Ac8bParams),
968 /// ESAC9C — IEEE 421.5-2016 AC9C exciter (alias ESAC7B structure).
969 Esac9c(Esac7bParams),
970 /// ESAC10C — IEEE 421.5-2016 AC10C exciter (alias ESAC7C structure).
971 Esac10c(Esac7cParams),
972 /// ESAC11C — IEEE 421.5-2016 AC11C high-bandwidth AC exciter (alias AC8B structure).
973 Esac11c(Ac8bParams),
974}
975
976// --- EXST1 ------------------------------------------------------------------
977
978/// Static exciter (PSS/E EXST1).
979///
980/// PSS/E params (12 required; klr, ilr optional):
981/// `TR VIMAX VIMIN TC TB KA TA VRMAX VRMIN KC KF TF [KLR ILR]`
982#[derive(Debug, Clone, Serialize, Deserialize)]
983pub struct Exst1Params {
984 pub tr: f64,
985 pub vimax: f64,
986 pub vimin: f64,
987 pub tc: f64,
988 pub tb: f64,
989 pub ka: f64,
990 pub ta: f64,
991 pub vrmax: f64,
992 pub vrmin: f64,
993 pub kc: f64,
994 pub kf: f64,
995 pub tf: f64,
996 #[serde(default, skip_serializing_if = "Option::is_none")]
997 pub klr: Option<f64>,
998 #[serde(default, skip_serializing_if = "Option::is_none")]
999 pub ilr: Option<f64>,
1000}
1001
1002// --- ESST3A -----------------------------------------------------------------
1003
1004/// IEEE type ST3A static exciter (PSS/E ESST3A).
1005///
1006/// PSS/E params (14 required):
1007/// `TR VIMAX VIMIN KM TC TB KA TA VRMAX VRMIN KG KP KI VBMAX`
1008#[derive(Debug, Clone, Serialize, Deserialize)]
1009pub struct Esst3aParams {
1010 pub tr: f64,
1011 pub vimax: f64,
1012 pub vimin: f64,
1013 pub km: f64,
1014 pub tc: f64,
1015 pub tb: f64,
1016 pub ka: f64,
1017 pub ta: f64,
1018 pub vrmax: f64,
1019 pub vrmin: f64,
1020 pub kg: f64,
1021 pub kp: f64,
1022 pub ki: f64,
1023 pub vbmax: f64,
1024}
1025
1026// --- ESDC2A -----------------------------------------------------------------
1027
1028/// IEEE type DC2A exciter (PSS/E ESDC2A).
1029///
1030/// PSS/E params (12 required):
1031/// `TR KA TA TB TC VRMAX VRMIN KE TE KF TF1 SWITCH`
1032#[derive(Debug, Clone, Serialize, Deserialize)]
1033pub struct Esdc2aParams {
1034 pub tr: f64,
1035 pub ka: f64,
1036 pub ta: f64,
1037 pub tb: f64,
1038 pub tc: f64,
1039 pub vrmax: f64,
1040 pub vrmin: f64,
1041 pub ke: f64,
1042 pub te: f64,
1043 pub kf: f64,
1044 pub tf1: f64,
1045 pub switch_: f64,
1046}
1047
1048// --- EXDC2 ------------------------------------------------------------------
1049
1050/// IEEE type DC2 exciter (PSS/E EXDC2) — used in Kundur 4-machine system.
1051///
1052/// PSS/E params (12 required; E1, SE1, E2, SE2 optional):
1053/// `TR KA TA TB TC VRMAX VRMIN KE TE KF TF1 SWITCH [E1 SE1 E2 SE2]`
1054#[derive(Debug, Clone, Serialize, Deserialize)]
1055pub struct Exdc2Params {
1056 pub tr: f64,
1057 pub ka: f64,
1058 pub ta: f64,
1059 pub tb: f64,
1060 pub tc: f64,
1061 pub vrmax: f64,
1062 pub vrmin: f64,
1063 pub ke: f64,
1064 pub te: f64,
1065 pub kf: f64,
1066 pub tf1: f64,
1067 pub switch_: f64,
1068 #[serde(default, skip_serializing_if = "Option::is_none")]
1069 pub e1: Option<f64>,
1070 #[serde(default, skip_serializing_if = "Option::is_none")]
1071 pub se1: Option<f64>,
1072 #[serde(default, skip_serializing_if = "Option::is_none")]
1073 pub e2: Option<f64>,
1074 #[serde(default, skip_serializing_if = "Option::is_none")]
1075 pub se2: Option<f64>,
1076}
1077
1078// --- IEEEX1 -----------------------------------------------------------------
1079
1080/// IEEE type AC1A exciter (PSS/E IEEEX1 / IEEEXC1).
1081///
1082/// PSS/E params (12 required; E1, SE1, E2, SE2 optional):
1083/// `TR KA TA TB TC VRMAX VRMIN KE TE KF TF AEX BEX [E1 SE1 E2 SE2]`
1084#[derive(Debug, Clone, Serialize, Deserialize)]
1085pub struct Ieeex1Params {
1086 pub tr: f64,
1087 pub ka: f64,
1088 pub ta: f64,
1089 pub tb: f64,
1090 pub tc: f64,
1091 pub vrmax: f64,
1092 pub vrmin: f64,
1093 pub ke: f64,
1094 pub te: f64,
1095 pub kf: f64,
1096 pub tf: f64,
1097 pub aex: f64,
1098 pub bex: f64,
1099 #[serde(default, skip_serializing_if = "Option::is_none")]
1100 pub e1: Option<f64>,
1101 #[serde(default, skip_serializing_if = "Option::is_none")]
1102 pub se1: Option<f64>,
1103 #[serde(default, skip_serializing_if = "Option::is_none")]
1104 pub e2: Option<f64>,
1105 #[serde(default, skip_serializing_if = "Option::is_none")]
1106 pub se2: Option<f64>,
1107}
1108
1109// --- SEXS -------------------------------------------------------------------
1110
1111/// Simplified Exciter (PSS/E SEXS) -- very common in planning studies.
1112///
1113/// This is a standard planning-level model for use when detailed AVR test data
1114/// is unavailable. For precise transient stability studies, upgrade to a
1115/// detailed exciter model (AC5A, ESST4B, or EXAC1) when field test data is
1116/// available. See the module-level documentation for the full model mapping.
1117///
1118/// PSS/E params: `TB TC K TE EMIN EMAX`
1119#[derive(Debug, Clone, Serialize, Deserialize)]
1120pub struct SexsParams {
1121 /// Lead-lag denominator time constant (s).
1122 pub tb: f64,
1123 /// Lead-lag numerator time constant (s).
1124 pub tc: f64,
1125 /// Exciter gain.
1126 pub k: f64,
1127 /// Exciter time constant (s).
1128 pub te: f64,
1129 /// Minimum field voltage limit (pu).
1130 pub emin: f64,
1131 /// Maximum field voltage limit (pu).
1132 pub emax: f64,
1133}
1134
1135// --- IEEET1 -----------------------------------------------------------------
1136
1137/// IEEE Type 1 Rotating Exciter (PSS/E IEEET1) — classic 1968 AVR.
1138///
1139/// PSS/E params: `TR KA TA KE TE KF TF E1 SE1 E2 SE2 [VRMAX VRMIN]`
1140#[derive(Debug, Clone, Serialize, Deserialize)]
1141pub struct Ieeet1Params {
1142 pub tr: f64,
1143 pub ka: f64,
1144 pub ta: f64,
1145 pub ke: f64,
1146 pub te: f64,
1147 pub kf: f64,
1148 pub tf: f64,
1149 /// Saturation function reference point 1 (pu).
1150 pub e1: f64,
1151 /// Saturation factor at E1.
1152 pub se1: f64,
1153 /// Saturation function reference point 2 (pu).
1154 pub e2: f64,
1155 /// Saturation factor at E2.
1156 pub se2: f64,
1157 #[serde(default, skip_serializing_if = "Option::is_none")]
1158 pub vrmax: Option<f64>,
1159 #[serde(default, skip_serializing_if = "Option::is_none")]
1160 pub vrmin: Option<f64>,
1161}
1162
1163// --- SCRX -------------------------------------------------------------------
1164
1165/// Simplified Bus-Fed Static Exciter (PSS/E SCRX).
1166///
1167/// This is a standard planning-level model for static exciters when detailed
1168/// parameters are unavailable. For precise transient stability studies,
1169/// upgrade to ESST4B or ESST3A when static exciter field test data is available.
1170/// See the module-level documentation for the full model mapping.
1171///
1172/// PSS/E params: `TR K TE EMIN EMAX [Rcrfd]`
1173#[derive(Debug, Clone, Serialize, Deserialize)]
1174pub struct ScrxParams {
1175 /// Transducer time constant (s).
1176 pub tr: f64,
1177 /// Exciter gain.
1178 pub k: f64,
1179 /// Exciter time constant (s).
1180 pub te: f64,
1181 /// Minimum field voltage (pu).
1182 pub emin: f64,
1183 /// Maximum field voltage (pu).
1184 pub emax: f64,
1185 /// Ratio of exciter to field current (optional).
1186 #[serde(default, skip_serializing_if = "Option::is_none")]
1187 pub rcrfd: Option<f64>,
1188}
1189
1190// --- REECA ------------------------------------------------------------------
1191
1192/// REEC_A -- IBR electrical controller (maps to exciter slot, Phase 8 simplified).
1193///
1194/// Simplified to voltage-following / constant power factor mode.
1195/// Full REEC_A includes Kqv droop, deadband, FRT limits.
1196///
1197/// This is a standard planning-level model for IBR electrical controllers.
1198/// For studies involving IBR fault ride-through, voltage regulation, or reactive
1199/// power control, use the full REEC_A model with Kqv droop and deadband parameters.
1200/// See the module-level documentation for the full model mapping.
1201///
1202/// Key params: `Trv Kqv Tp Kqp Kqi Vref0 Dbd1 Dbd2 Vdip Vup Iqh1 Iql1 Qmax Qmin`
1203#[derive(Debug, Clone, Serialize, Deserialize)]
1204pub struct ReecaParams {
1205 /// Voltage filter time constant (s).
1206 pub trv: f64,
1207 /// Reactive power control voltage droop gain.
1208 pub kqv: f64,
1209 /// Active current filter time constant (s).
1210 pub tp: f64,
1211 /// Reactive power proportional gain.
1212 pub kqp: f64,
1213 /// Reactive power integral gain (1/s).
1214 pub kqi: f64,
1215 /// Initial voltage reference (pu).
1216 pub vref0: f64,
1217 /// Voltage deadband lower limit (pu, negative).
1218 pub dbd1: f64,
1219 /// Voltage deadband upper limit (pu, positive).
1220 pub dbd2: f64,
1221 /// Low voltage protection threshold (pu).
1222 pub vdip: f64,
1223 /// High voltage protection threshold (pu).
1224 pub vup: f64,
1225 /// Maximum reactive current (pu).
1226 pub iqh1: f64,
1227 /// Minimum reactive current (pu).
1228 pub iql1: f64,
1229 /// Maximum reactive power (pu).
1230 pub qmax: f64,
1231 /// Minimum reactive power (pu).
1232 pub qmin: f64,
1233 /// Active power measurement filter time constant (s).
1234 pub tpfilt: f64,
1235 /// Reactive power measurement filter time constant (s).
1236 pub tqfilt: f64,
1237 /// Active power ramp rate up limit (pu/s).
1238 pub rrpwr: f64,
1239 /// Active power ramp rate down limit (pu/s, negative).
1240 pub rrpwr_dn: f64,
1241 /// Current priority flag: 0 = Q priority, 1 = P priority.
1242 pub pqflag: i32,
1243 /// Maximum total current magnitude (pu).
1244 pub imax: f64,
1245 /// Maximum active current (pu, used with PQFLAG=1).
1246 pub ipmax: f64,
1247 /// VDL1 breakpoints: voltage-dependent reactive current limit (Vq, Iq) pairs.
1248 /// If all zeros or empty, flat iqh1/iql1 limits apply.
1249 pub vdl1: [(f64, f64); 4],
1250 /// VDL2 breakpoints: voltage-dependent active current limit (Vp, Ip) pairs.
1251 /// If all zeros or empty, flat ipmax limit applies.
1252 pub vdl2: [(f64, f64); 4],
1253}
1254
1255// ---------------------------------------------------------------------------
1256// Governor records
1257// ---------------------------------------------------------------------------
1258
1259/// A turbine-governor dynamic model record.
1260#[derive(Debug, Clone, Serialize, Deserialize)]
1261pub struct GovernorDyn {
1262 pub bus: u32,
1263 pub machine_id: String,
1264 pub model: GovernorModel,
1265}
1266
1267/// REPCD — IBR plant power controller (drives active power).
1268#[derive(Debug, Clone, Serialize, Deserialize)]
1269pub struct RepdcParams {
1270 pub tp: f64,
1271 pub kpg: f64,
1272 pub kig: f64,
1273 pub pmax: f64,
1274 pub pmin: f64,
1275 pub tlag: f64,
1276}
1277
1278/// WT3T1 — Type 3 wind turbine drive train.
1279#[derive(Debug, Clone, Serialize, Deserialize)]
1280pub struct Wt3t1Params {
1281 pub h: f64,
1282 pub damp: f64,
1283 pub ka: f64,
1284 pub theta: f64,
1285}
1286
1287/// WT3P1 — Type 3 wind turbine pitch controller.
1288#[derive(Debug, Clone, Serialize, Deserialize)]
1289pub struct Wt3p1Params {
1290 pub tp: f64,
1291 pub kpp: f64,
1292 pub kip: f64,
1293 pub pmax: f64,
1294 pub pmin: f64,
1295}
1296
1297/// GGOV1D — Enhanced GGOV1 with droop deadband.
1298#[derive(Debug, Clone, Serialize, Deserialize)]
1299pub struct Ggov1dParams {
1300 pub r: f64,
1301 pub t_pelec: f64,
1302 pub maxerr: f64,
1303 pub minerr: f64,
1304 pub kpgov: f64,
1305 pub kigov: f64,
1306 pub kdgov: f64,
1307 pub fdbd1: f64,
1308 pub fdbd2: f64,
1309 pub pmax: f64,
1310 pub pmin: f64,
1311 pub tact: f64,
1312 pub kturb: f64,
1313 pub wfnl: f64,
1314 pub tb: f64,
1315 pub tc: f64,
1316 pub flag: f64,
1317 pub teng: f64,
1318 pub tfload: f64,
1319 pub kpload: f64,
1320 pub kiload: f64,
1321 pub ldref: f64,
1322 pub dm: f64,
1323 pub ropen: f64,
1324 pub rclose: f64,
1325 pub kimw: f64,
1326 pub pmwset: f64,
1327 pub aset: f64,
1328 pub ka: f64,
1329 pub ta: f64,
1330 pub db: f64,
1331 pub tsa: f64,
1332 pub tsb: f64,
1333 pub rup: f64,
1334 pub rdown: f64,
1335 pub load_ref: f64,
1336}
1337
1338/// TGOV1N / TGOV1NDB — TGOV1 with null deadband.
1339#[derive(Debug, Clone, Serialize, Deserialize)]
1340pub struct Tgov1nParams {
1341 pub r: f64,
1342 pub dt: f64,
1343 pub t1: f64,
1344 pub vmax: f64,
1345 pub vmin: f64,
1346 pub t2: f64,
1347 pub t3: f64,
1348 pub d: f64,
1349 pub db: f64,
1350}
1351
1352/// Discriminated union of supported governor models.
1353#[derive(Debug, Clone, Serialize, Deserialize)]
1354#[serde(tag = "type")]
1355pub enum GovernorModel {
1356 Tgov1(Tgov1Params),
1357 Ieeeg1(Ieeeg1Params),
1358 Ggov1(Ggov1Params),
1359 /// GAST — Gas Turbine Simplified governor (Rowen model).
1360 Gast(GastParams),
1361 /// REPC_A — IBR plant controller (maps to governor slot, simplified Phase 8).
1362 Repca(RepcaParams),
1363 Hygov(HygovParams),
1364 Hygovd(HygovdParams),
1365 Tgov1d(Tgov1dParams),
1366 Ieeeg1d(Ieeeg1dParams),
1367 /// WSIEG1 — WECC IEEEG1 (same structure as Ieeeg1).
1368 Wsieg1(Ieeeg1Params),
1369 Ieeeg2(Ieeeg2Params),
1370 /// REPCD — IBR plant power controller.
1371 Repcd(RepdcParams),
1372 /// WT3T1 — Type 3 wind drive train.
1373 Wt3t1(Wt3t1Params),
1374 /// WT3P1 — Type 3 wind pitch controller.
1375 Wt3p1(Wt3p1Params),
1376 /// GGOV1D — Enhanced GGOV1 with droop deadband.
1377 Ggov1d(Ggov1dParams),
1378 /// TGOV1N / TGOV1NDB — TGOV1 with null deadband.
1379 Tgov1n(Tgov1nParams),
1380 /// CBEST — PSS/E native BESS model (Phase 14).
1381 Cbest(CbestParams),
1382 /// CHAAUT — BESS active power controller with frequency droop (Phase 14).
1383 Chaaut(ChaautParams),
1384 /// PIDGOV — PID governor for any prime mover (Phase 14).
1385 Pidgov(PidgovParams),
1386 /// DEGOV1 — Diesel governor Type 1 (Phase 14).
1387 Degov1(Degov1Params),
1388 /// TGOV5 — Multi-reheat steam governor HP+IP (Phase 15, 4 states).
1389 Tgov5(Tgov5Params),
1390 /// GAST2A — Advanced Rowen gas turbine with ambient temperature (Phase 15, 4 states).
1391 Gast2a(Gast2aParams),
1392 // Phase 18
1393 /// H6E — Hydro Governor 6 Elements (Phase 18).
1394 H6e(H6eParams),
1395 /// WSHYGP — Wind-Synchronous Hydro Governor+Pitch (Phase 18).
1396 Wshygp(WshygpParams),
1397 // Phase 25
1398 /// GGOV2 — GE GGOV1 variant 2 with supplemental load reference input (Phase 25, 4 states).
1399 Ggov2(Ggov2Params),
1400 /// GGOV3 — GE GGOV1 variant 3 with washout filter (Phase 25, 4 states).
1401 Ggov3(Ggov3Params),
1402 /// WPIDHY — Woodward PID Hydro Governor (Phase 25, 4 states).
1403 Wpidhy(WpidhyParams),
1404 /// H6B — Six-State Hydro Governor Variant B (Phase 25, 5 states).
1405 H6b(H6bParams),
1406 /// WSHYDD — WSHYGP with speed deadband (Phase 25, 4 states).
1407 Wshydd(WshyddParams),
1408 // Phase 28
1409 /// REPCGFM_C1 — GFM plant Volt/Var controller (Phase 28, 3 states).
1410 Repcgfmc1(Repcgfmc1Params),
1411 /// WTDTA1 — Wind turbine two-mass drive-train (Phase 28, 2 states).
1412 Wtdta1(Wtdta1Params),
1413 /// WTARA1 — Wind turbine aerodynamic aggregation (Phase 28, 2 states).
1414 Wtara1(Wtara1Params),
1415 /// WTPTA1 — Wind turbine pitch angle control (Phase 28, 2 states).
1416 Wtpta1(Wtpta1Params),
1417 // Wave 34
1418 /// IEESGO — IEEE Standard Governor (5-state steam turbine).
1419 Ieesgo(IeesgoParams),
1420 /// WTTQA1 — WECC Type 2 Wind Torque Controller (2 states).
1421 Wttqa1(Wttqa1Params),
1422 // Wave 35
1423 /// HYGOV4 — Hydro Governor with Surge Tank (5 states).
1424 Hygov4(Hygov4Params),
1425 /// WEHGOV — WECC Enhanced Hydro Governor (4 states).
1426 Wehgov(WehgovParams),
1427 /// IEEEG3 — IEEE Type G3 Hydro Governor (3 states).
1428 Ieeeg3(Ieeeg3Params),
1429 /// IEEEG4 — IEEE Type G4 Hydro Governor (3 states, lead-lag form).
1430 Ieeeg4(Ieeeg4Params),
1431 // Wave 36: combined cycle + steam + wind governors
1432 /// GOVCT1 — Single-shaft combined cycle turbine governor (Wave 36, 5 states).
1433 Govct1(Govct1Params),
1434 /// GOVCT2 — Two-shaft combined cycle turbine governor (7 states: 5 GT + HRSG + ST).
1435 Govct2(Govct2Params),
1436 /// TGOV3 — TGOV1 variant with two-reheat steam turbine (Wave 36, 3 states).
1437 Tgov3(Tgov3Params),
1438 /// TGOV4 — TGOV1 with IP/LP split (Wave 36, alias Tgov3Params).
1439 Tgov4(Tgov3Params),
1440 /// WT2E1 — Type 2 wind electrical controller (Wave 36, 2 states).
1441 Wt2e1(Wt2e1Params),
1442 /// WT12T1 — Type 1/2 wind drive train (Wave 36, alias Wt3t1Params).
1443 Wt12t1(Wt3t1Params),
1444 /// WT12A1 — Type 1/2 wind aerodynamics (Wave 36, alias Wt3p1Params).
1445 Wt12a1(Wt3p1Params),
1446 /// WTAERO — Full aerodynamic Cp(λ,β) wind turbine model (B4).
1447 Wtaero(WtaeroParams),
1448}
1449
1450// --- TGOV1 ------------------------------------------------------------------
1451
1452/// Steam turbine-governor (PSS/E TGOV1).
1453///
1454/// PSS/E params (6 required; DT optional):
1455/// `R T1 VMAX VMIN T2 T3 [DT]`
1456#[derive(Debug, Clone, Serialize, Deserialize)]
1457pub struct Tgov1Params {
1458 pub r: f64,
1459 pub t1: f64,
1460 pub vmax: f64,
1461 pub vmin: f64,
1462 pub t2: f64,
1463 pub t3: f64,
1464 #[serde(default, skip_serializing_if = "Option::is_none")]
1465 pub dt: Option<f64>,
1466}
1467
1468// --- IEEEG1 -----------------------------------------------------------------
1469
1470/// IEEE type G1 turbine-governor (PSS/E IEEEG1).
1471///
1472/// PSS/E params (9 required; K1..K8, T5..T7 optional):
1473/// `K T1 T2 T3 UO UC PMAX PMIN T4 [K1 K2 T5 K3 K4 T6 K5 K6 T7 K7 K8]`
1474#[derive(Debug, Clone, Serialize, Deserialize)]
1475pub struct Ieeeg1Params {
1476 pub k: f64,
1477 pub t1: f64,
1478 pub t2: f64,
1479 pub t3: f64,
1480 pub uo: f64,
1481 pub uc: f64,
1482 pub pmax: f64,
1483 pub pmin: f64,
1484 pub t4: f64,
1485 #[serde(default, skip_serializing_if = "Option::is_none")]
1486 pub k1: Option<f64>,
1487 #[serde(default, skip_serializing_if = "Option::is_none")]
1488 pub k2: Option<f64>,
1489 #[serde(default, skip_serializing_if = "Option::is_none")]
1490 pub t5: Option<f64>,
1491 #[serde(default, skip_serializing_if = "Option::is_none")]
1492 pub k3: Option<f64>,
1493 #[serde(default, skip_serializing_if = "Option::is_none")]
1494 pub k4: Option<f64>,
1495 #[serde(default, skip_serializing_if = "Option::is_none")]
1496 pub t6: Option<f64>,
1497 #[serde(default, skip_serializing_if = "Option::is_none")]
1498 pub k5: Option<f64>,
1499 #[serde(default, skip_serializing_if = "Option::is_none")]
1500 pub k6: Option<f64>,
1501 #[serde(default, skip_serializing_if = "Option::is_none")]
1502 pub t7: Option<f64>,
1503 #[serde(default, skip_serializing_if = "Option::is_none")]
1504 pub k7: Option<f64>,
1505 #[serde(default, skip_serializing_if = "Option::is_none")]
1506 pub k8: Option<f64>,
1507}
1508
1509// ---------------------------------------------------------------------------
1510// PSS records
1511// ---------------------------------------------------------------------------
1512
1513/// A power system stabilizer dynamic model record.
1514#[derive(Debug, Clone, Serialize, Deserialize)]
1515pub struct PssDyn {
1516 pub bus: u32,
1517 pub machine_id: String,
1518 pub model: PssModel,
1519}
1520
1521/// Discriminated union of supported PSS models.
1522#[derive(Debug, Clone, Serialize, Deserialize)]
1523#[serde(tag = "type")]
1524pub enum PssModel {
1525 Ieeest(IeeestParams),
1526 St2cut(St2cutParams),
1527 Pss2a(Pss2aParams),
1528 Pss2b(Pss2bParams),
1529 Stab1(Stab1Params),
1530 /// PSS1A — Single-input single lead-lag PSS (Phase 14).
1531 Pss1a(Pss1aParams),
1532 /// STAB2A — WSCC stabilizer variant A, double lead-lag (Phase 15, 3 states).
1533 Stab2a(Stab2aParams),
1534 /// PSS4B — Four-band multi-frequency PSS (Phase 15, 4 states).
1535 Pss4b(Pss4bParams),
1536 // Phase 18
1537 /// STAB3 — Three-Band PSS (Phase 18).
1538 Stab3(Stab3Params),
1539 /// PSS3B — Three-Input Power System Stabilizer (Phase 18).
1540 Pss3b(Pss3bParams),
1541 // Phase 24
1542 /// PSS2C — PSS2B with ramp-tracking filter on input 2 (Phase 24).
1543 Pss2c(Pss2cParams),
1544 /// PSS5 — Five-band multi-frequency PSS (Phase 24).
1545 Pss5(Pss5Params),
1546 /// PSS6C — Six-input multi-band PSS (Phase 24).
1547 Pss6c(Pss6cParams),
1548 /// PSSSB — WSCC/BPA simple PSS vendor variant B (Phase 24).
1549 Psssb(PsssbParams),
1550 /// STAB4 — WSCC stabilizer variant 4 (Phase 24).
1551 Stab4(Stab4Params),
1552 /// STAB5 — WSCC stabilizer variant 5 (Phase 24).
1553 Stab5(Stab5Params),
1554 // Wave 35
1555 /// PSS3C — IEEE 421.5-2016 3-band PSS (alias to PSS3B params/dynamics).
1556 Pss3c(Pss3bParams),
1557 /// PSS4C — IEEE 421.5-2016 4-band PSS (alias to PSS4B params/dynamics).
1558 Pss4c(Pss4bParams),
1559 /// PSS5C — IEEE 421.5-2016 5-band PSS (alias to PSS5 params/dynamics).
1560 Pss5c(Pss5Params),
1561 /// PSS7C — IEEE 421.5-2016 7-input multi-band PSS (2 states: washout + lead-lag).
1562 Pss7c(Pss7cParams),
1563}
1564
1565// --- IEEEST -----------------------------------------------------------------
1566
1567/// IEEE standard PSS (PSS/E IEEEST).
1568///
1569/// PSS/E params (13 required; LSMAX, LSMIN, VCU, VCL optional):
1570/// `A1 A2 A3 A4 A5 A6 T1 T2 T3 T4 T5 T6 KS [LSMAX LSMIN VCU VCL]`
1571#[derive(Debug, Clone, Serialize, Deserialize)]
1572pub struct IeeestParams {
1573 pub a1: f64,
1574 pub a2: f64,
1575 pub a3: f64,
1576 pub a4: f64,
1577 pub a5: f64,
1578 pub a6: f64,
1579 pub t1: f64,
1580 pub t2: f64,
1581 pub t3: f64,
1582 pub t4: f64,
1583 pub t5: f64,
1584 pub t6: f64,
1585 pub ks: f64,
1586 #[serde(default, skip_serializing_if = "Option::is_none")]
1587 pub lsmax: Option<f64>,
1588 #[serde(default, skip_serializing_if = "Option::is_none")]
1589 pub lsmin: Option<f64>,
1590 #[serde(default, skip_serializing_if = "Option::is_none")]
1591 pub vcu: Option<f64>,
1592 #[serde(default, skip_serializing_if = "Option::is_none")]
1593 pub vcl: Option<f64>,
1594}
1595
1596// --- GGOV1 ------------------------------------------------------------------
1597
1598/// General-purpose turbine-governor model (PSS/E GGOV1).
1599///
1600/// Simplified 3-state implementation capturing the key dynamics of gas turbines
1601/// and combined-cycle units. Covers ~40% of ERCOT/SPP generation fleet.
1602///
1603/// PSS/E params (17 required):
1604/// `R RSELECT TPELEC MAXERR MINERR KPGOV KIGOV KDGOV TDGOV VMAX VMIN TSA FSR TSB TSE IANG KCMF KTURB WFNL TB TC TRATE FLAG`
1605#[derive(Debug, Clone, Serialize, Deserialize)]
1606pub struct Ggov1Params {
1607 /// Droop (pu) — speed regulation.
1608 pub r: f64,
1609 /// Electrical power transducer time constant (s).
1610 pub tpelec: f64,
1611 /// Maximum governor output (pu on machine base).
1612 pub vmax: f64,
1613 /// Minimum governor output (pu on machine base).
1614 pub vmin: f64,
1615 /// Proportional governor gain.
1616 pub kpgov: f64,
1617 /// Integral governor gain (1/s).
1618 pub kigov: f64,
1619 /// Turbine gain.
1620 pub kturb: f64,
1621 /// No-load fuel flow (pu on machine base).
1622 pub wfnl: f64,
1623 /// Turbine reheat lead time constant (s).
1624 pub tb: f64,
1625 /// Turbine reheat lag time constant (s).
1626 pub tc: f64,
1627 /// Rated turbine power (MW, 0 = use machine mbase).
1628 #[serde(default, skip_serializing_if = "Option::is_none")]
1629 pub trate: Option<f64>,
1630 /// Load reference set point (pu) — initialized to Pm0.
1631 #[serde(default, skip_serializing_if = "Option::is_none")]
1632 pub ldref: Option<f64>,
1633 /// Damping constant (pu).
1634 #[serde(default, skip_serializing_if = "Option::is_none")]
1635 pub dm: Option<f64>,
1636}
1637
1638// --- GAST -------------------------------------------------------------------
1639
1640/// Gas Turbine Simplified governor (PSS/E GAST) -- Rowen model.
1641///
1642/// This is a standard planning-level model for gas turbines when detailed
1643/// performance test data is unavailable. For precise transient stability
1644/// studies, upgrade to GAST2A (with ambient temperature effects) or GGOV1
1645/// (with detailed PID governor) when gas turbine test data is available.
1646/// See the module-level documentation for the full model mapping.
1647///
1648/// PSS/E params: `R T1 T2 T3 AT KT VMIN VMAX`
1649#[derive(Debug, Clone, Serialize, Deserialize)]
1650pub struct GastParams {
1651 /// Droop (speed regulation, pu).
1652 pub r: f64,
1653 /// Governor valve time constant (s).
1654 pub t1: f64,
1655 /// Turbine time constant (s).
1656 pub t2: f64,
1657 /// Exhaust temperature time constant (s).
1658 pub t3: f64,
1659 /// Ambient temperature load limit (pu).
1660 pub at: f64,
1661 /// Exhaust temperature coefficient.
1662 pub kt: f64,
1663 /// Minimum governor output (pu).
1664 pub vmin: f64,
1665 /// Maximum governor output (pu).
1666 pub vmax: f64,
1667}
1668
1669// --- REPCA ------------------------------------------------------------------
1670
1671/// REPC_A -- IBR plant controller (maps to governor slot, Phase 8 simplified).
1672///
1673/// Simplified to constant Pref/Qref -- no AGC droop or plant-level control.
1674///
1675/// This is a standard planning-level model for IBR plant controllers.
1676/// For studies involving plant-level AGC response, frequency droop, or
1677/// coordinated voltage/reactive control, use the full REPC_A model with droop
1678/// and PI controller parameters. See the module-level documentation for details.
1679#[derive(Debug, Clone, Serialize, Deserialize)]
1680pub struct RepcaParams {
1681 // --- Reactive power / voltage control ---
1682 /// Voltage / reactive power control flag: 0 = Q control, 1 = voltage control.
1683 pub vrflag: f64,
1684 /// Reactive power droop gain (pu).
1685 pub rc: f64,
1686 /// Reactive power / voltage measurement filter time constant (s).
1687 pub tfltr: f64,
1688 /// Voltage PI proportional gain.
1689 pub kp: f64,
1690 /// Voltage PI integral gain (1/s).
1691 pub ki: f64,
1692 /// Maximum PI output (pu).
1693 pub vmax: f64,
1694 /// Minimum PI output (pu).
1695 pub vmin: f64,
1696 /// Plant voltage reference (pu).
1697 pub vref: f64,
1698 /// Reactive power reference (pu).
1699 pub qref: f64,
1700 /// Plant-level reactive power max (pu).
1701 pub qmax: f64,
1702 /// Plant-level reactive power min (pu).
1703 pub qmin: f64,
1704
1705 // --- Active power / frequency control ---
1706 /// Frequency deadband lower (Hz, negative).
1707 pub fdbd1: f64,
1708 /// Frequency deadband upper (Hz, positive).
1709 pub fdbd2: f64,
1710 /// Frequency droop down gain.
1711 pub ddn: f64,
1712 /// Frequency droop up gain.
1713 pub dup: f64,
1714 /// Active power measurement filter time constant (s).
1715 pub tp: f64,
1716 /// Active power PI proportional gain.
1717 pub kpg: f64,
1718 /// Active power PI integral gain (1/s).
1719 pub kig: f64,
1720 /// Active power reference (pu).
1721 pub pref: f64,
1722 /// Maximum active power (pu).
1723 pub pmax: f64,
1724 /// Minimum active power (pu).
1725 pub pmin: f64,
1726 /// Active power ramp rate (pu/s).
1727 pub rrpwr: f64,
1728 /// Voltage measurement filter time constant (s) for frequency control.
1729 pub tlag: f64,
1730}
1731
1732// --- ST2CUT -----------------------------------------------------------------
1733
1734/// Dual-input PSS (PSS/E ST2CUT).
1735///
1736/// PSS/E params (11 required; LSMIN, VCU, VCL optional):
1737/// `K1 T1 T2 T3 T4 K2 T5 T6 T7 T8 LSMAX [LSMIN VCU VCL]`
1738#[derive(Debug, Clone, Serialize, Deserialize)]
1739pub struct St2cutParams {
1740 pub k1: f64,
1741 pub t1: f64,
1742 pub t2: f64,
1743 pub t3: f64,
1744 pub t4: f64,
1745 pub k2: f64,
1746 pub t5: f64,
1747 pub t6: f64,
1748 pub t7: f64,
1749 pub t8: f64,
1750 pub lsmax: f64,
1751 #[serde(default, skip_serializing_if = "Option::is_none")]
1752 pub lsmin: Option<f64>,
1753 #[serde(default, skip_serializing_if = "Option::is_none")]
1754 pub vcu: Option<f64>,
1755 #[serde(default, skip_serializing_if = "Option::is_none")]
1756 pub vcl: Option<f64>,
1757}
1758
1759// ---------------------------------------------------------------------------
1760
1761// --- GENTPJ -----------------------------------------------------------------
1762
1763/// GENTPJ — flux-based sixth-order round-rotor generator (WECC standard until Dec 2024).
1764///
1765/// Identical state equations to GENROU; saturation applied to all flux linkages
1766/// simultaneously via Se(ψ) = S1*(ψ/1.0)^2 (quadratic), with additional stator
1767/// current correction term Kii.
1768///
1769/// PSS/E params (14 required + Kii optional):
1770/// `Td0' Td0'' Tq0' Tq0'' H D Xd Xq Xd' Xq' Xd'' Xl S(1.0) S(1.2) [Kii]`
1771#[derive(Debug, Clone, Serialize, Deserialize)]
1772pub struct GentpjParams {
1773 pub td0_prime: f64,
1774 pub td0_pprime: f64,
1775 pub tq0_prime: f64,
1776 pub tq0_pprime: f64,
1777 pub h: f64,
1778 pub d: f64,
1779 pub xd: f64,
1780 pub xq: f64,
1781 pub xd_prime: f64,
1782 pub xq_prime: f64,
1783 pub xd_pprime: f64,
1784 pub xl: f64,
1785 pub s1: f64,
1786 pub s12: f64,
1787 /// Stator current coefficient for saturation (default 0).
1788 #[serde(default, skip_serializing_if = "Option::is_none")]
1789 pub kii: Option<f64>,
1790 #[serde(default, skip_serializing_if = "Option::is_none")]
1791 pub ra: Option<f64>,
1792}
1793
1794// --- GENQEC -----------------------------------------------------------------
1795
1796/// GENQEC — sixth-order round-rotor generator with quadratic saturation.
1797///
1798/// **Mandatory WECC standard from December 2024.**
1799/// Quadratic saturation applied simultaneously to all EMF and impedance terms.
1800/// Same state variables as GENROU.
1801///
1802/// PSS/E params (14 required + Ra optional):
1803/// `Td0' Td0'' Tq0' Tq0'' H D Xd Xq Xd' Xq' Xd'' Xl S(1.0) S(1.2) [Ra]`
1804#[derive(Debug, Clone, Serialize, Deserialize)]
1805pub struct GenqecParams {
1806 pub td0_prime: f64,
1807 pub td0_pprime: f64,
1808 pub tq0_prime: f64,
1809 pub tq0_pprime: f64,
1810 pub h: f64,
1811 pub d: f64,
1812 pub xd: f64,
1813 pub xq: f64,
1814 pub xd_prime: f64,
1815 pub xq_prime: f64,
1816 pub xd_pprime: f64,
1817 pub xl: f64,
1818 pub s1: f64,
1819 pub s12: f64,
1820 #[serde(default, skip_serializing_if = "Option::is_none")]
1821 pub ra: Option<f64>,
1822}
1823
1824// --- ESST1A -----------------------------------------------------------------
1825
1826/// IEEE Type ST1A static exciter (PSS/E ESST1A) — 2005 enhanced standard.
1827///
1828/// PSS/E params: `TR VIMAX VIMIN TC TB TC1 TB1 KA TA VAMAX VAMIN VRMAX VRMIN KC KF TF`
1829#[derive(Debug, Clone, Serialize, Deserialize)]
1830pub struct Esst1aParams {
1831 pub tr: f64,
1832 pub vimax: f64,
1833 pub vimin: f64,
1834 pub tc: f64,
1835 pub tb: f64,
1836 pub tc1: f64,
1837 pub tb1: f64,
1838 pub ka: f64,
1839 pub ta: f64,
1840 pub vamax: f64,
1841 pub vamin: f64,
1842 pub vrmax: f64,
1843 pub vrmin: f64,
1844 pub kc: f64,
1845 pub kf: f64,
1846 pub tf: f64,
1847 pub klr: f64,
1848 pub ilr: f64,
1849}
1850
1851// --- EXAC1 / ESAC1A ---------------------------------------------------------
1852
1853/// IEEE Type AC1A rotating exciter (PSS/E EXAC1 / ESAC1A).
1854///
1855/// AC alternator-fed rectifier exciter. The rectifier regulation is modelled
1856/// via the FEX function (IN = KC * Ifd / Ve).
1857///
1858/// PSS/E params: `TR TB TC KA TA VRMAX VRMIN TE KF TF KE E1 SE1 E2 SE2 KC`
1859#[derive(Debug, Clone, Serialize, Deserialize)]
1860pub struct Exac1Params {
1861 pub tr: f64,
1862 pub tb: f64,
1863 pub tc: f64,
1864 pub ka: f64,
1865 pub ta: f64,
1866 pub vrmax: f64,
1867 pub vrmin: f64,
1868 pub te: f64,
1869 pub kf: f64,
1870 pub tf: f64,
1871 pub kc: f64,
1872 pub kd: f64,
1873 pub ke: f64,
1874 pub e1: f64,
1875 pub se1: f64,
1876 pub e2: f64,
1877 pub se2: f64,
1878}
1879
1880// --- ESAC7B -----------------------------------------------------------------
1881
1882/// IEEE Type AC7B rotating exciter (PSS/E ESAC7B / AC7B).
1883///
1884/// High-performance AC exciter with PI voltage regulator (Hitachi/ABB digital).
1885///
1886/// PSS/E params: `TR KPA KIA VRH VRL KPF VFH TF TE KE E1 SE1 E2 SE2 KD KC KL`
1887#[derive(Debug, Clone, Serialize, Deserialize)]
1888pub struct Esac7bParams {
1889 pub tr: f64,
1890 pub kpa: f64,
1891 pub kia: f64,
1892 pub vrh: f64,
1893 pub vrl: f64,
1894 pub kpf: f64,
1895 pub vfh: f64,
1896 pub tf: f64,
1897 pub te: f64,
1898 pub ke: f64,
1899 pub e1: f64,
1900 pub se1: f64,
1901 pub e2: f64,
1902 pub se2: f64,
1903 pub kd: f64,
1904 pub kc: f64,
1905 pub kl: f64,
1906}
1907
1908// --- ESST4B -----------------------------------------------------------------
1909
1910/// IEEE Type ST4B static exciter (PSS/E ESST4B) — dual-loop PI controller.
1911///
1912/// PSS/E params: `TR KPR KIR VRMAX VRMIN KPM KIM VMMAX VMMIN KG KP KI VBMAX VGMAX`
1913#[derive(Debug, Clone, Serialize, Deserialize)]
1914pub struct Esst4bParams {
1915 pub tr: f64,
1916 pub kpr: f64,
1917 pub kir: f64,
1918 pub vrmax: f64,
1919 pub vrmin: f64,
1920 pub kpm: f64,
1921 pub kim: f64,
1922 pub vmmax: f64,
1923 pub vmmin: f64,
1924 pub kg: f64,
1925 pub kp: f64,
1926 pub ki: f64,
1927 pub vbmax: f64,
1928 pub vgmax: f64,
1929}
1930
1931// --- HYGOV -----------------------------------------------------------------
1932
1933/// WECC hydro turbine governor (PSS/E HYGOV).
1934///
1935/// PID servo + penstock water column + turbine output.
1936///
1937/// PSS/E params: `R TP VELM TG GMAX GMIN TW At Dturb QNLL`
1938#[derive(Debug, Clone, Serialize, Deserialize)]
1939pub struct HygovParams {
1940 /// Droop (pu).
1941 pub r: f64,
1942 /// Pilot valve time constant (s).
1943 pub tp: f64,
1944 /// Gate velocity limit (pu/s).
1945 pub velm: f64,
1946 /// Gate servo time constant (s).
1947 pub tg: f64,
1948 /// Maximum gate position (pu).
1949 pub gmax: f64,
1950 /// Minimum gate position (pu).
1951 pub gmin: f64,
1952 /// Water time constant (s).
1953 pub tw: f64,
1954 /// Turbine gain (pu power / pu gate).
1955 pub at: f64,
1956 /// Turbine damping (pu).
1957 pub dturb: f64,
1958 /// No-load flow (pu).
1959 pub qnl: f64,
1960}
1961
1962// --- HYGOVD ----------------------------------------------------------------
1963
1964/// WECC hydro governor with deadband (PSS/E HYGOVD — WECC recommended).
1965#[derive(Debug, Clone, Serialize, Deserialize)]
1966pub struct HygovdParams {
1967 pub r: f64,
1968 pub tp: f64,
1969 pub velm: f64,
1970 pub tg: f64,
1971 pub gmax: f64,
1972 pub gmin: f64,
1973 pub tw: f64,
1974 pub at: f64,
1975 pub dturb: f64,
1976 pub qnl: f64,
1977 /// Deadband lower limit (pu, negative).
1978 pub db1: f64,
1979 /// Deadband upper limit (pu, positive).
1980 pub db2: f64,
1981}
1982
1983// --- TGOV1D ----------------------------------------------------------------
1984
1985/// Steam turbine governor with speed deadband (PSS/E TGOV1D — WECC recommended).
1986#[derive(Debug, Clone, Serialize, Deserialize)]
1987pub struct Tgov1dParams {
1988 pub r: f64,
1989 pub t1: f64,
1990 pub vmax: f64,
1991 pub vmin: f64,
1992 pub t2: f64,
1993 pub t3: f64,
1994 #[serde(default, skip_serializing_if = "Option::is_none")]
1995 pub dt: Option<f64>,
1996 /// Deadband lower limit (pu, negative).
1997 pub db1: f64,
1998 /// Deadband upper limit (pu, positive).
1999 pub db2: f64,
2000}
2001
2002// --- IEEEG1D ---------------------------------------------------------------
2003
2004/// IEEE Type G1 steam governor with deadband (PSS/E IEEEG1D — WECC recommended).
2005#[derive(Debug, Clone, Serialize, Deserialize)]
2006pub struct Ieeeg1dParams {
2007 pub k: f64,
2008 pub t1: f64,
2009 pub t2: f64,
2010 pub t3: f64,
2011 pub uo: f64,
2012 pub uc: f64,
2013 pub pmax: f64,
2014 pub pmin: f64,
2015 pub t4: f64,
2016 #[serde(default, skip_serializing_if = "Option::is_none")]
2017 pub k1: Option<f64>,
2018 #[serde(default, skip_serializing_if = "Option::is_none")]
2019 pub k2: Option<f64>,
2020 #[serde(default, skip_serializing_if = "Option::is_none")]
2021 pub t5: Option<f64>,
2022 #[serde(default, skip_serializing_if = "Option::is_none")]
2023 pub k3: Option<f64>,
2024 #[serde(default, skip_serializing_if = "Option::is_none")]
2025 pub k4: Option<f64>,
2026 #[serde(default, skip_serializing_if = "Option::is_none")]
2027 pub t6: Option<f64>,
2028 #[serde(default, skip_serializing_if = "Option::is_none")]
2029 pub k5: Option<f64>,
2030 #[serde(default, skip_serializing_if = "Option::is_none")]
2031 pub k6: Option<f64>,
2032 #[serde(default, skip_serializing_if = "Option::is_none")]
2033 pub t7: Option<f64>,
2034 #[serde(default, skip_serializing_if = "Option::is_none")]
2035 pub k7: Option<f64>,
2036 #[serde(default, skip_serializing_if = "Option::is_none")]
2037 pub k8: Option<f64>,
2038 /// Deadband lower limit (pu, negative).
2039 pub db1: f64,
2040 /// Deadband upper limit (pu, positive).
2041 pub db2: f64,
2042}
2043
2044// --- IEEEG2 ----------------------------------------------------------------
2045
2046/// IEEE Type G2 hydro governor with dashpot, gate servo, and water column.
2047///
2048/// Full block diagram: speed error → dashpot (temporary droop) → gate servo
2049/// → water column (non-minimum phase) → Pm.
2050///
2051/// 3 states: x_dashpot, x_gate, x_water.
2052///
2053/// PSS/E params: `K T1 T2 T3 Pmin Pmax At Dturb Qnl`
2054/// Legacy 4-param format: `K T1 T2 PZ` (PZ mapped to Qnl).
2055#[derive(Debug, Clone, Serialize, Deserialize)]
2056pub struct Ieeeg2Params {
2057 /// Governor gain (1/R permanent droop).
2058 pub k: f64,
2059 /// Gate servo time constant Tp (s).
2060 pub t1: f64,
2061 /// Water starting time Tw (s).
2062 pub t2: f64,
2063 /// Dashpot reset time constant Tr (s). 0 = no dashpot.
2064 #[serde(default)]
2065 pub t3: f64,
2066 /// Temporary droop coefficient Rt. 0 = no temporary droop.
2067 #[serde(default)]
2068 pub rt: f64,
2069 /// Minimum gate position (pu).
2070 #[serde(default)]
2071 pub pmin: f64,
2072 /// Maximum gate position (pu).
2073 #[serde(default = "Ieeeg2Params::default_pmax")]
2074 pub pmax: f64,
2075 /// Turbine gain.
2076 #[serde(default = "Ieeeg2Params::default_at")]
2077 pub at: f64,
2078 /// Turbine damping coefficient.
2079 #[serde(default)]
2080 pub dturb: f64,
2081 /// No-load flow (pu). Legacy `pz` field maps here.
2082 #[serde(default)]
2083 pub qnl: f64,
2084}
2085
2086impl Ieeeg2Params {
2087 fn default_pmax() -> f64 {
2088 1.0
2089 }
2090 fn default_at() -> f64 {
2091 1.0
2092 }
2093}
2094
2095// --- PSS2A -----------------------------------------------------------------
2096
2097/// IEEE dual-input PSS (PSS/E PSS2A) — IEEE 421.5-2005 standard.
2098///
2099/// Two inputs: speed (ω) and electrical power (Pe).
2100///
2101/// PSS/E params: `M1 T6 T7 KS2 T8 T9 M2 TW1 TW2 TW3 TW4 T1 T2 T3 T4 KS1 KS3 VSTMAX VSTMIN`
2102#[derive(Debug, Clone, Serialize, Deserialize)]
2103pub struct Pss2aParams {
2104 /// Input 1 signal selector (1=speed, 2=freq, 3=power).
2105 pub m1: f64,
2106 /// Input 1 transducer time constant (s).
2107 pub t6: f64,
2108 /// Input 2 transducer time constant (s).
2109 pub t7: f64,
2110 /// Input 2 gain.
2111 pub ks2: f64,
2112 /// Input 2 ramp tracking filter TC (s).
2113 pub t8: f64,
2114 /// Input 2 ramp tracking filter TB (s).
2115 pub t9: f64,
2116 /// Input 2 signal selector (1=speed, 2=freq, 3=power).
2117 pub m2: f64,
2118 /// Input 1 washout TC 1 (s).
2119 pub tw1: f64,
2120 /// Input 1 washout TC 2 (s).
2121 pub tw2: f64,
2122 /// Input 2 washout TC 1 (s).
2123 pub tw3: f64,
2124 /// Input 2 washout TC 2 (s).
2125 pub tw4: f64,
2126 /// Lead-lag 1 numerator TC (s).
2127 pub t1: f64,
2128 /// Lead-lag 1 denominator TC (s).
2129 pub t2: f64,
2130 /// Lead-lag 2 numerator TC (s).
2131 pub t3: f64,
2132 /// Lead-lag 2 denominator TC (s).
2133 pub t4: f64,
2134 /// PSS gain (pu/pu).
2135 pub ks1: f64,
2136 /// Input signal scaling (usually 1.0).
2137 pub ks3: f64,
2138 /// Maximum PSS output (pu).
2139 pub vstmax: f64,
2140 /// Minimum PSS output (pu).
2141 pub vstmin: f64,
2142}
2143
2144// --- PSS2B -----------------------------------------------------------------
2145
2146/// IEEE dual-input PSS enhanced (PSS/E PSS2B) — additional transducer TC.
2147///
2148/// Identical to PSS2A with additional time constants T10/T11.
2149#[derive(Debug, Clone, Serialize, Deserialize)]
2150pub struct Pss2bParams {
2151 pub m1: f64,
2152 pub t6: f64,
2153 pub t7: f64,
2154 pub ks2: f64,
2155 pub t8: f64,
2156 pub t9: f64,
2157 pub m2: f64,
2158 pub tw1: f64,
2159 pub tw2: f64,
2160 pub tw3: f64,
2161 pub tw4: f64,
2162 pub t1: f64,
2163 pub t2: f64,
2164 pub t3: f64,
2165 pub t4: f64,
2166 pub ks1: f64,
2167 pub ks3: f64,
2168 pub vstmax: f64,
2169 pub vstmin: f64,
2170 /// Additional transducer lead TC (s).
2171 pub t10: f64,
2172 /// Additional transducer lag TC (s).
2173 pub t11: f64,
2174}
2175
2176// --- STAB1 -----------------------------------------------------------------
2177
2178/// WSCC simple stabilizer (PSS/E STAB1).
2179///
2180/// Single-input (speed), one washout, one lead-lag.
2181///
2182/// PSS/E params: `KS T1 T2 T3 T4 HLIM`
2183#[derive(Debug, Clone, Serialize, Deserialize)]
2184pub struct Stab1Params {
2185 /// Stabilizer gain (pu/pu).
2186 pub ks: f64,
2187 /// Washout time constant (s).
2188 pub t1: f64,
2189 /// Lead-lag denominator time constant (s).
2190 pub t2: f64,
2191 /// Lead-lag numerator time constant (s).
2192 pub t3: f64,
2193 /// Second lead-lag denominator TC (s).
2194 pub t4: f64,
2195 /// PSS output limit (pu, symmetric ±HLIM).
2196 pub hlim: f64,
2197}
2198
2199// ---------------------------------------------------------------------------
2200// Phase 14: BESS, remaining exciters, governors, PSS
2201// ---------------------------------------------------------------------------
2202
2203// --- CBEST -----------------------------------------------------------------
2204
2205/// CBEST — PSS/E native BESS model (Phase 14, 4 states).
2206///
2207/// States: p_cmd, q_cmd, soc, e_dc.
2208#[derive(Debug, Clone, Serialize, Deserialize)]
2209pub struct CbestParams {
2210 /// Maximum active power output (pu machine base, typ 1.0).
2211 pub p_max: f64,
2212 /// Minimum active power (pu, can be negative = charging, typ -1.0).
2213 pub p_min: f64,
2214 /// Maximum reactive power (pu, typ 0.5).
2215 pub q_max: f64,
2216 /// Minimum reactive power (pu, typ -0.5).
2217 pub q_min: f64,
2218 /// Active power time constant (s, typ 0.05).
2219 pub tp: f64,
2220 /// Reactive power time constant (s, typ 0.05).
2221 pub tq: f64,
2222 /// Energy capacity (MWh normalized to MVA base).
2223 pub e_cap: f64,
2224 /// Machine MVA base.
2225 pub mbase: f64,
2226 /// Initial state of charge (0..1, default 0.5).
2227 pub soc_init: f64,
2228}
2229
2230// --- CHAAUT ----------------------------------------------------------------
2231
2232/// CHAAUT — BESS active power controller with frequency droop (Phase 14, 2 states).
2233///
2234/// States: p_cmd, freq_state.
2235#[derive(Debug, Clone, Serialize, Deserialize)]
2236pub struct ChaautParams {
2237 /// Frequency droop gain (typ 20.0).
2238 pub kf: f64,
2239 /// Frequency filter time constant (s, typ 0.1).
2240 pub tf: f64,
2241 /// Maximum power output (pu).
2242 pub p_max: f64,
2243 /// Minimum power output (pu, can be negative).
2244 pub p_min: f64,
2245 /// Power time constant (s).
2246 pub tp: f64,
2247 /// Machine MVA base.
2248 pub mbase: f64,
2249}
2250
2251// --- ESAC2A ----------------------------------------------------------------
2252
2253/// ESAC2A — IEEE AC2A high-initial-response rotating exciter (Phase 14, 5 states).
2254///
2255/// States: vm (transducer), vr (voltage regulator), ve (exciter EMF), vf (rate feedback), efd.
2256#[derive(Debug, Clone, Serialize, Deserialize)]
2257pub struct Esac2aParams {
2258 pub tr: f64,
2259 pub tb: f64,
2260 pub tc: f64,
2261 pub ka: f64,
2262 pub ta: f64,
2263 pub vamax: f64,
2264 pub vamin: f64,
2265 pub ke: f64,
2266 pub te: f64,
2267 pub kf: f64,
2268 pub tf: f64,
2269 pub e1: f64,
2270 pub se1: f64,
2271 pub e2: f64,
2272 pub se2: f64,
2273 pub vrmax: f64,
2274 pub vrmin: f64,
2275 pub kb: f64,
2276 pub kc: f64,
2277 pub kd: f64,
2278 pub kh: f64,
2279}
2280
2281// --- ESAC5A ----------------------------------------------------------------
2282
2283/// ESAC5A — IEEE AC5A simplified brushless exciter (Phase 14, 2 states).
2284///
2285/// States: vr (regulator), efd.
2286#[derive(Debug, Clone, Serialize, Deserialize)]
2287pub struct Esac5aParams {
2288 pub ka: f64,
2289 pub ta: f64,
2290 pub ke: f64,
2291 pub te: f64,
2292 pub kf: f64,
2293 pub tf: f64,
2294 pub e1: f64,
2295 pub se1: f64,
2296 pub e2: f64,
2297 pub se2: f64,
2298 pub vrmax: f64,
2299 pub vrmin: f64,
2300}
2301
2302// --- PSS1A -----------------------------------------------------------------
2303
2304/// PSS1A — Single-input single lead-lag PSS (Phase 14, 2 states).
2305///
2306/// States: x1 (washout), x2 (lead-lag).
2307#[derive(Debug, Clone, Serialize, Deserialize)]
2308pub struct Pss1aParams {
2309 /// PSS gain.
2310 pub ks: f64,
2311 /// Washout time constant (s).
2312 pub t1: f64,
2313 /// Second washout / lead-lag denominator TC (s).
2314 pub t2: f64,
2315 /// Lead-lag numerator TC (s).
2316 pub t3: f64,
2317 /// Second lead-lag denominator TC (s).
2318 pub t4: f64,
2319 /// Maximum PSS output (pu).
2320 pub vstmax: f64,
2321 /// Minimum PSS output (pu).
2322 pub vstmin: f64,
2323}
2324
2325// --- PIDGOV ----------------------------------------------------------------
2326
2327/// PIDGOV — PID governor for any prime mover (Phase 14, 3 states).
2328///
2329/// States: x_int (integrator), x_der (derivative filter), pm.
2330#[derive(Debug, Clone, Serialize, Deserialize)]
2331pub struct PidgovParams {
2332 /// Maximum power output (pu).
2333 pub pmax: f64,
2334 /// Minimum power output (pu).
2335 pub pmin: f64,
2336 /// Proportional gain.
2337 pub kp: f64,
2338 /// Integral gain (1/s).
2339 pub ki: f64,
2340 /// Derivative gain.
2341 pub kd: f64,
2342 /// Derivative filter time constant (s).
2343 pub td: f64,
2344 /// Power output time constant (s).
2345 pub tf: f64,
2346}
2347
2348// --- DEGOV1 ----------------------------------------------------------------
2349
2350/// DEGOV1 — Woodward diesel/gas engine governor (6 states).
2351///
2352/// Full PID electronic controller + actuator + 3-stage engine dynamics.
2353///
2354/// States: x_ecl (derivative filter), x_int (integrator), x_act (actuator),
2355/// x1 (engine lag 1), x2 (engine lag 2), x3 (engine lag 3).
2356#[derive(Debug, Clone, Serialize, Deserialize)]
2357pub struct Degov1Params {
2358 /// Droop (pu).
2359 pub r: f64,
2360 /// First engine time constant (s).
2361 pub t1: f64,
2362 /// Second engine time constant (s).
2363 pub t2: f64,
2364 /// Third engine time constant (s).
2365 pub t3: f64,
2366 /// Derivative action time constant (s) — PID controller.
2367 #[serde(default = "default_degov1_t4")]
2368 pub t4: f64,
2369 /// Derivative filter time constant (s) — PID controller.
2370 #[serde(default = "default_degov1_t5")]
2371 pub t5: f64,
2372 /// Actuator time constant (s).
2373 #[serde(default = "default_degov1_t6")]
2374 pub t6: f64,
2375 /// Controller integral time constant (s).
2376 pub td: f64,
2377 /// Controller gain.
2378 #[serde(default = "default_degov1_k")]
2379 pub k: f64,
2380 /// Maximum actuator output (pu).
2381 pub vmax: f64,
2382 /// Minimum actuator output (pu).
2383 pub vmin: f64,
2384 /// Actuator rate limit (pu/s).
2385 #[serde(default = "default_degov1_velm")]
2386 pub velm: f64,
2387 /// Ambient temperature load limit (pu) — engine output gain.
2388 pub at: f64,
2389 /// Exhaust temperature coefficient — engine cross-coupling.
2390 pub kt: f64,
2391}
2392
2393fn default_degov1_t4() -> f64 {
2394 0.0
2395}
2396fn default_degov1_t5() -> f64 {
2397 0.01
2398}
2399fn default_degov1_t6() -> f64 {
2400 0.01
2401}
2402fn default_degov1_k() -> f64 {
2403 1.0
2404}
2405fn default_degov1_velm() -> f64 {
2406 99.0
2407}
2408
2409// ---------------------------------------------------------------------------
2410// Phase 13: FACTS/HVDC dynamic model records
2411// ---------------------------------------------------------------------------
2412
2413/// A FACTS or HVDC dynamic model record — attaches to a bus (shunt) or two buses (branch).
2414#[derive(Debug, Clone, Serialize, Deserialize)]
2415pub struct FACTSDyn {
2416 /// Primary bus number (for shunt devices; rectifier bus for HVDC).
2417 pub bus: u32,
2418 /// Device ID string (matches PSS/E device ID).
2419 pub device_id: String,
2420 /// The specific FACTS/HVDC model and its parameters.
2421 pub model: FACTSModel,
2422 /// Second terminal bus: inverter bus for HVDC, to-bus for series FACTS.
2423 /// Populated from model params (HVDC) or network topology (TCSC/SSSC/UPFC).
2424 #[serde(default)]
2425 pub to_bus: Option<u32>,
2426}
2427
2428/// Discriminated union of supported FACTS/HVDC dynamic models.
2429#[derive(Debug, Clone, Serialize, Deserialize)]
2430#[serde(tag = "type")]
2431pub enum FACTSModel {
2432 /// CSVGN1 — Static VAr Compensator (most common SVC model).
2433 Csvgn1(Csvgn1Params),
2434 /// CSTCON — STATCOM (current-source reactive control).
2435 Cstcon(CstconParams),
2436 /// TCSC — Thyristor-Controlled Series Capacitor.
2437 Tcsc(TcscParams),
2438 /// CDC4T — Generic LCC HVDC Two-Terminal.
2439 Cdc4t(Cdc4tParams),
2440 /// VSCDCT — Generic VSC HVDC Two-Terminal.
2441 Vscdct(VscdctParams),
2442 /// CSVGN3 — SVC with slope/droop regulator (Phase 15, 3 states).
2443 Csvgn3(Csvgn3Params),
2444 /// CDC7T — LCC HVDC + runback + current order controllers (Phase 15, 6 states).
2445 Cdc7t(Cdc7tParams),
2446 // Phase 20
2447 /// CSVGN4 — SVC with 4 states (adds POD) (Phase 20).
2448 Csvgn4(Csvgn4Params),
2449 /// CSVGN5 — SVC with 4 states (voltage support mode) (Phase 20).
2450 Csvgn5(Csvgn5Params),
2451 /// CDC6T — LCC HVDC with enhanced controls (Phase 20).
2452 Cdc6t(Cdc6tParams),
2453 /// CSTCNT — STATCOM with N controls (4 states) (Phase 20).
2454 Cstcnt(CstcntParams),
2455 /// MMC1 — Modular Multilevel Converter (5 states) (Phase 20).
2456 Mmc1(Mmc1Params),
2457 // Phase 26
2458 /// HVDCPLU1 — Siemens HVDC Plus VSC (Phase 26, 6 states, reuses Vscdct layout).
2459 Hvdcplu1(HvdcPlu1Params),
2460 /// CSVGN6 — SVC Variant 6 with Auxiliary Inputs (Phase 26, 5 states).
2461 Csvgn6(Csvgn6Params),
2462 /// STCON1 — STATCOM with Inner Current Control (Phase 26, 4 states).
2463 Stcon1(Stcon1Params),
2464 /// GCSC — Gate-Controlled Series Compensator (Phase 26, 3 states).
2465 Gcsc(GcscParams),
2466 /// SSSC — Static Synchronous Series Compensator (Phase 26, 4 states).
2467 Sssc(SsscParams),
2468 /// UPFC — Unified Power Flow Controller (Phase 26, 6 states).
2469 Upfc(UpfcParams),
2470 /// CDC3T — Three-Terminal LCC HVDC (Phase 26, 8 states).
2471 Cdc3t(Cdc3tParams),
2472 // Wave 34: WECC SVC/STATCOM variants
2473 /// SVSMO1 — WECC Generic SVC voltage regulator (1 state).
2474 Svsmo1(Svsmo1Params),
2475 /// SVSMO2 — WECC Generic STATCOM (1 state).
2476 Svsmo2(Svsmo2Params),
2477 /// SVSMO3 — WECC Advanced SVC (2 states: b_svc + vr).
2478 Svsmo3(Svsmo3Params),
2479}
2480
2481// --- CSVGN1 -----------------------------------------------------------------
2482
2483/// CSVGN1 — Static VAr Compensator (SVC) with lead-lag voltage regulator.
2484///
2485/// PSS/E params: `t1 t2 t3 t4 t5 k vmax vmin bmax bmin /`
2486///
2487/// 3 states: `vr` (regulator), `vfilt` (voltage filter), `b_svc` (susceptance).
2488#[derive(Debug, Clone, Serialize, Deserialize)]
2489pub struct Csvgn1Params {
2490 /// Regulator time constant (s, typ 0.05).
2491 pub t1: f64,
2492 /// Lead time constant (s, typ 0.0).
2493 pub t2: f64,
2494 /// Lag time constant (s, typ 0.1).
2495 pub t3: f64,
2496 /// Filter time constant (s, typ 0.04).
2497 pub t4: f64,
2498 /// Output time constant (s, typ 0.05).
2499 pub t5: f64,
2500 /// Regulator gain (typ 100.0).
2501 pub k: f64,
2502 /// Max voltage reference (pu, typ 1.05).
2503 pub vmax: f64,
2504 /// Min voltage reference (pu, typ 0.95).
2505 pub vmin: f64,
2506 /// Max susceptance (pu, capacitive positive, typ 2.0).
2507 pub bmax: f64,
2508 /// Min susceptance (pu, inductive negative, typ -2.0).
2509 pub bmin: f64,
2510 /// MVA base.
2511 pub mbase: f64,
2512 /// TCR reactor susceptance (pu, inductive). If set, enables firing-angle physics.
2513 /// B_tcr(α) = b_l * (2*(π-α) + sin(2α)) / π
2514 #[serde(default)]
2515 pub b_l: Option<f64>,
2516 /// TSC fixed capacitor susceptance (pu, capacitive positive). Defaults to bmax.
2517 #[serde(default)]
2518 pub b_c: Option<f64>,
2519 /// Firing angle lag time constant (s). Defaults to t5.
2520 #[serde(default)]
2521 pub t_alpha: Option<f64>,
2522}
2523
2524// --- CSTCON -----------------------------------------------------------------
2525
2526/// CSTCON — STATCOM (current-source reactive control).
2527///
2528/// PSS/E params: `tr k tiq imax imin /`
2529///
2530/// 3 states: `vr` (voltage regulator), `vfilt` (filter), `iq_cmd` (current command).
2531#[derive(Debug, Clone, Serialize, Deserialize)]
2532pub struct CstconParams {
2533 /// Regulator time constant (s, typ 0.02).
2534 pub tr: f64,
2535 /// Gain (typ 50.0).
2536 pub k: f64,
2537 /// Current command time constant (s, typ 0.01).
2538 pub tiq: f64,
2539 /// Max current (pu, typ 1.0).
2540 pub imax: f64,
2541 /// Min current (pu, typ -1.0).
2542 pub imin: f64,
2543 /// MVA base.
2544 pub mbase: f64,
2545 /// DC-link capacitance (pu on mbase, typ 0.1). Defaults to 0.1.
2546 #[serde(default)]
2547 pub c_dc: Option<f64>,
2548 /// DC-link voltage reference (pu, typ 1.0). Defaults to 1.0.
2549 #[serde(default)]
2550 pub vdc_ref: Option<f64>,
2551 /// DC-link voltage PI proportional gain. Defaults to 5.0.
2552 #[serde(default)]
2553 pub kp_vdc: Option<f64>,
2554}
2555
2556// --- TCSC -------------------------------------------------------------------
2557
2558/// TCSC — Thyristor-Controlled Series Capacitor.
2559///
2560/// PSS/E params: `t1 t2 t3 xmax xmin k /`
2561///
2562/// 3 states: `x_tcsc` (reactance), `vfilt` (line current filter), `x_order` (order tracking).
2563#[derive(Debug, Clone, Serialize, Deserialize)]
2564pub struct TcscParams {
2565 /// Time constant (s, typ 0.05).
2566 pub t1: f64,
2567 /// Time constant (s, typ 0.02).
2568 pub t2: f64,
2569 /// Time constant (s, typ 0.1).
2570 pub t3: f64,
2571 /// Max reactance (pu, capacitive positive).
2572 pub xmax: f64,
2573 /// Min reactance (pu, can be negative = inductive).
2574 pub xmin: f64,
2575 /// Control gain.
2576 pub k: f64,
2577 /// MVA base.
2578 pub mbase: f64,
2579}
2580
2581// --- CDC4T ------------------------------------------------------------------
2582
2583/// CDC4T — Generic LCC HVDC Two-Terminal.
2584///
2585/// PSS/E params: `setvl vschd tr td alpha_min alpha_max gamma_min rectifier_bus inverter_bus /`
2586///
2587/// 6 states: `id`, `vd_r`, `vd_i`, `alpha`, `gamma`, `p_ord`.
2588#[derive(Debug, Clone, Serialize, Deserialize)]
2589pub struct Cdc4tParams {
2590 /// Power or current setpoint (pu).
2591 pub setvl: f64,
2592 /// Scheduled DC voltage (pu, typ 1.0).
2593 pub vschd: f64,
2594 /// MVA base.
2595 pub mbase: f64,
2596 /// Regulator time constant (s, typ 0.02).
2597 pub tr: f64,
2598 /// DC time constant (s, typ 0.01).
2599 pub td: f64,
2600 /// Min firing angle (deg, typ 5.0).
2601 pub alpha_min: f64,
2602 /// Max firing angle (deg, typ 165.0).
2603 pub alpha_max: f64,
2604 /// Min extinction angle (deg, typ 15.0).
2605 pub gamma_min: f64,
2606 /// Inverter extinction angle reference (rad). Defaults to `gamma_min` in radians.
2607 pub gamma_ref: Option<f64>,
2608 /// Power order ramp rate (pu/s). Defaults to 10.0.
2609 pub ramp: Option<f64>,
2610 /// Rectifier current controller proportional gain (rad/pu). Defaults to 0.5.
2611 #[serde(default)]
2612 pub kp_alpha: Option<f64>,
2613 /// Rectifier current controller integral gain (rad/pu/s). Defaults to 20.0.
2614 #[serde(default)]
2615 pub ki_alpha: Option<f64>,
2616 /// Inverter gamma controller integral gain (1/s). Defaults to 20.0.
2617 #[serde(default)]
2618 pub ki_gamma: Option<f64>,
2619 /// Rectifier terminal bus number.
2620 pub rectifier_bus: u32,
2621 /// Inverter terminal bus number.
2622 pub inverter_bus: u32,
2623 // Phase 2.1: CIGRE control + VDCOL
2624 /// VDCOL breakpoint voltage (pu DC) — below this, current order is reduced.
2625 #[serde(default)]
2626 pub vdcol_v1: Option<f64>,
2627 /// VDCOL breakpoint voltage upper (pu DC).
2628 #[serde(default)]
2629 pub vdcol_v2: Option<f64>,
2630 /// VDCOL current limit at v1 (pu).
2631 #[serde(default)]
2632 pub vdcol_i1: Option<f64>,
2633 /// VDCOL current limit at v2 (pu, typically 1.0 = full current).
2634 #[serde(default)]
2635 pub vdcol_i2: Option<f64>,
2636 /// Current order filter time constant (s).
2637 #[serde(default)]
2638 pub t_iord: Option<f64>,
2639}
2640
2641// --- VSCDCT -----------------------------------------------------------------
2642
2643/// VSCDCT — Generic VSC HVDC Two-Terminal.
2644///
2645/// PSS/E params: `p_order vdc_ref t_dc t_ac imax rectifier_bus inverter_bus /`
2646///
2647/// 6 states: `id`, `iq_r`, `iq_i`, `vd`, `p_ref`, `q_ref`.
2648#[derive(Debug, Clone, Serialize, Deserialize)]
2649pub struct VscdctParams {
2650 /// Power order (pu, positive = rectifier to inverter).
2651 pub p_order: f64,
2652 /// DC voltage reference (pu, typ 1.0).
2653 pub vdc_ref: f64,
2654 /// DC time constant (s, typ 0.02).
2655 pub t_dc: f64,
2656 /// AC time constant (s, typ 0.01).
2657 pub t_ac: f64,
2658 /// Max DC current (pu, typ 1.1).
2659 pub imax: f64,
2660 /// Reactive power order (pu). Defaults to 0.0.
2661 pub q_order: Option<f64>,
2662 /// DC voltage PI proportional gain. Defaults to 2.0.
2663 #[serde(default)]
2664 pub kp_vdc: Option<f64>,
2665 /// DC voltage PI integral gain (1/s). Defaults to 50.0.
2666 #[serde(default)]
2667 pub ki_vdc: Option<f64>,
2668 /// AC voltage/Q PI proportional gain. Defaults to 5.0.
2669 #[serde(default)]
2670 pub kp_q: Option<f64>,
2671 /// AC voltage/Q PI integral gain (1/s). Defaults to 20.0.
2672 #[serde(default)]
2673 pub ki_q: Option<f64>,
2674 /// DC voltage measurement filter time constant (s). Defaults to 0.01.
2675 #[serde(default)]
2676 pub t_vdc_filt: Option<f64>,
2677 /// Inner d-axis current PI proportional gain. Defaults to 1.0.
2678 #[serde(default)]
2679 pub kp_id: Option<f64>,
2680 /// Inner d-axis current PI integral gain (1/s). Defaults to 100.0.
2681 #[serde(default)]
2682 pub ki_id: Option<f64>,
2683 /// Inner q-axis current PI proportional gain. Defaults to 1.0.
2684 #[serde(default)]
2685 pub kp_iq: Option<f64>,
2686 /// Inner q-axis current PI integral gain (1/s). Defaults to 100.0.
2687 #[serde(default)]
2688 pub ki_iq: Option<f64>,
2689 /// MVA base.
2690 pub mbase: f64,
2691 /// Rectifier terminal bus number.
2692 pub rectifier_bus: u32,
2693 /// Inverter terminal bus number.
2694 pub inverter_bus: u32,
2695}
2696
2697// ---------------------------------------------------------------------------
2698// Phase 12: Load dynamic model records
2699// ---------------------------------------------------------------------------
2700
2701/// A load dynamic model record — attaches to a load bus (not a generator bus).
2702#[derive(Debug, Clone, Serialize, Deserialize)]
2703pub struct LoadDyn {
2704 /// Bus number of the associated static load.
2705 pub bus: u32,
2706 /// Load ID (matches PSS/E load record ID, e.g. `"1"`, `"L1"`).
2707 pub load_id: String,
2708 /// The specific load model and its parameters.
2709 pub model: LoadModel,
2710}
2711
2712/// Discriminated union of supported load dynamic models.
2713#[derive(Debug, Clone, Serialize, Deserialize)]
2714#[serde(tag = "type")]
2715pub enum LoadModel {
2716 /// CLOD — PSS/E composite load (large motor, small motor, discharge lighting, non-conforming).
2717 Clod(ClodParams),
2718 /// INDMOT — Generic 3rd-order induction motor aggregate.
2719 Indmot(IndmotParams),
2720 /// MOTOR — Single-phase induction motor / AC compressor (2nd-order).
2721 Motor(MotorParams),
2722 /// CMPLDW — Composite load model with motors (Phase 16).
2723 Cmpldw(CmpldwParams),
2724 /// CMPLDWG — CMPLDW with embedded generation (Phase 16).
2725 Cmpldwg(CmpldwgParams),
2726 /// CMLDBLU2 — Composite load simplified blue model (Phase 16).
2727 Cmldblu2(Cmldblu2Params),
2728 /// CMLDARU2 — Composite load ARU2 model (Phase 16).
2729 Cmldaru2(Cmldblu2Params),
2730 /// MOTORW — Type W induction motor (Phase 16).
2731 Motorw(MotorwParams),
2732 /// CIM5 — Current injection motor model 5th order (Phase 16).
2733 Cim5(Cim5Params),
2734 // Phase 27
2735 /// LCFB1 — Load compensator with frequency bias (Phase 27, 2 states).
2736 Lcfb1(Lcfb1Params),
2737 /// LDFRAL — Dynamic load frequency regulation (Phase 27, 2 states).
2738 Ldfral(LdfralParams),
2739 /// FRQTPLT — Frequency relay trip (Phase 27, 1 state + bool flag).
2740 Frqtplt(FrqtpltParams),
2741 /// LVSHBL — Low-voltage shunt block (Phase 27, 1 state + bool flag).
2742 Lvshbl(LvshblParams),
2743 // Wave 34: Additional load variants
2744 /// CIM6 — 6th-order induction motor (extends CIM5 with q-axis transient state).
2745 Cim6(Cim6Params),
2746 /// CIMW — Composite Wind Induction Motor (alias to INDMOT dynamics).
2747 Cimw(IndmotParams),
2748 /// EXTL — External Load (simplified composite, 2 states).
2749 Extl(ExtlParams),
2750 /// IEELAR — IEEE Load Aggregation (alias to EXTL structure).
2751 Ieelar(ExtlParams),
2752 /// CMLDOWU2 — CLM Owner variant (alias to CMPLDW).
2753 Cmldowu2(CmpldwParams),
2754 /// CMLDXNU2 — CLM Zone variant (alias to CMPLDW).
2755 Cmldxnu2(CmpldwParams),
2756 /// CMLDALU2 — CLM All-utilities variant (alias to CMPLDW).
2757 Cmldalu2(CmpldwParams),
2758 /// CMLDBLU2W — CLM Blue with wind (alias to CMLDBLU2).
2759 Cmldblu2w(Cmldblu2Params),
2760 /// CMLDARU2W — CLM ARU2 with wind (alias to CMLDARU2).
2761 Cmldaru2w(Cmldblu2Params),
2762 // Wave 35: Generator protection relays
2763 /// VTGTPAT — Voltage-Time Generator Protection Trip (continuous).
2764 Vtgtpat(VtgtpatParams),
2765 /// VTGDCAT — Voltage-Time Discrete Generator Protection (alias to VTGTPAT dynamics).
2766 Vtgdcat(VtgtpatParams),
2767 /// FRQTPAT — Frequency-Time Generator Protection Trip (continuous).
2768 Frqtpat(FrqtpatParams),
2769 /// FRQDCAT — Frequency-Time Discrete Generator Protection (alias to FRQTPAT dynamics).
2770 Frqdcat(FrqtpatParams),
2771 // Wave 36: protection models
2772 /// DISTR1 — Distance relay (line protection, Wave 36).
2773 Distr1(Distr1Params),
2774 /// BFR50 — Breaker failure relay (ANSI 50BF).
2775 Bfr50(Bfr50Params),
2776 /// LVSHC1 — Low voltage shunt capacitor (Wave 36, alias LvshblParams).
2777 Lvshc1(LvshblParams),
2778 // Wave 7 (B10): additional protection relay models
2779 /// 87T — Transformer differential relay.
2780 TransDiff87(TransDiff87Params),
2781 /// 87L — Line differential relay (trips branch, not generator).
2782 LineDiff87l(LineDiff87lParams),
2783 /// 79 — Automatic recloser (trips + auto-reclose sequence).
2784 Recloser79(Recloser79Params),
2785 // Wave 37: CLM DG variants
2786 /// CMLDDGU2 — CMPLDW with embedded distributed generation.
2787 Cmlddgu2(CmpldwParams),
2788 /// CMLDDGGU2 — CMPLDWG with embedded distributed generation.
2789 Cmlddggu2(CmpldwgParams),
2790 /// CMLDOWDGU2 — CMLDOWU2 with embedded distributed generation.
2791 Cmldowdgu2(CmpldwParams),
2792 /// CMLDXNDGU2 — CMLDXNU2 with embedded distributed generation.
2793 Cmldxndgu2(CmpldwParams),
2794 /// UVLS1 — Under-Voltage Load Shedding relay (single stage, per-bus).
2795 Uvls1(Uvls1Params),
2796}
2797
2798// --- CLOD -------------------------------------------------------------------
2799
2800/// PSS/E composite load model (CLOD).
2801///
2802/// Models a mix of load components at a load bus: large motors, small motors,
2803/// discharge lighting, and non-conforming constant-power loads.
2804///
2805/// PSS/E params: `lfac rfrac xfrac lfrac nfrac dsli tv tf vtd vtu ftd ftu td`
2806#[derive(Debug, Clone, Serialize, Deserialize)]
2807pub struct ClodParams {
2808 /// MVA base (from load record; used to scale power).
2809 pub mbase: f64,
2810 /// Load factor — fraction of total bus load this model represents (0..1].
2811 pub lfac: f64,
2812 /// Large motor fraction (of modelled load).
2813 pub rfrac: f64,
2814 /// Small motor fraction (of modelled load).
2815 pub xfrac: f64,
2816 /// Discharge lighting fraction (of modelled load).
2817 pub lfrac_dl: f64,
2818 /// Non-conforming constant power fraction (of modelled load).
2819 pub nfrac: f64,
2820 /// Discharge lighting initial state.
2821 pub dsli: f64,
2822 /// Voltage transient time constant (s) — motor slip recovery (typ 0.025 s).
2823 pub tv: f64,
2824 /// Frequency transient time constant (s) — lighting recovery (typ 0.02 s).
2825 pub tf: f64,
2826 /// Low voltage trip threshold (pu, typ 0.75).
2827 pub vtd: f64,
2828 /// High voltage trip threshold (pu, typ 1.2).
2829 pub vtu: f64,
2830 /// Low frequency trip threshold (Hz, typ 57.5).
2831 pub ftd: f64,
2832 /// High frequency trip threshold (Hz, typ 61.5).
2833 pub ftu: f64,
2834 /// Trip delay (s, typ 0.05).
2835 pub td: f64,
2836}
2837
2838// --- INDMOT -----------------------------------------------------------------
2839
2840/// Generic 3rd-order induction motor aggregate (PSS/E INDMOT).
2841///
2842/// Single-cage rotor with slip dynamics — represents a group of similar
2843/// induction motors aggregated to a single equivalent.
2844///
2845/// PSS/E params: `h d ra xs xr xm rr mbase lfac`
2846#[derive(Debug, Clone, Serialize, Deserialize)]
2847pub struct IndmotParams {
2848 /// Inertia constant (s).
2849 pub h: f64,
2850 /// Damping coefficient.
2851 pub d: f64,
2852 /// Stator resistance (pu machine base).
2853 pub ra: f64,
2854 /// Stator leakage reactance (pu machine base).
2855 pub xs: f64,
2856 /// Rotor leakage reactance (pu machine base).
2857 pub xr: f64,
2858 /// Magnetizing reactance (pu machine base).
2859 pub xm: f64,
2860 /// Rotor resistance (pu machine base).
2861 pub rr: f64,
2862 /// Transient time constant: `t0p = (xr + xm) / (omega0 * rr)` (s).
2863 pub t0p: f64,
2864 /// Transient reactance: `x0p = xs + xr*xm/(xr+xm)` (pu machine base).
2865 pub x0p: f64,
2866 /// MVA base of the motor aggregate.
2867 pub mbase: f64,
2868 /// Load fraction at this bus (0..1].
2869 pub lfac: f64,
2870 /// Initial (rated) slip — computed during init from power flow solution.
2871 pub slip0: f64,
2872 /// Initial electrical torque — computed during init for torque normalization.
2873 pub te0: f64,
2874}
2875
2876// --- MOTOR ------------------------------------------------------------------
2877
2878/// Single-phase induction motor / AC compressor — 2nd-order (PSS/E MOTOR).
2879///
2880/// Simplified model capturing the dominant dynamics of residential AC
2881/// compressors and single-phase induction motors.
2882///
2883/// PSS/E params: `h ra xs x0p t0p mbase lfac`
2884#[derive(Debug, Clone, Serialize, Deserialize)]
2885pub struct MotorParams {
2886 /// Inertia constant (s).
2887 pub h: f64,
2888 /// Stator resistance (pu machine base).
2889 pub ra: f64,
2890 /// Stator+rotor synchronous reactance (pu machine base).
2891 pub xs: f64,
2892 /// Transient reactance (pu machine base).
2893 pub x0p: f64,
2894 /// Transient time constant (s).
2895 pub t0p: f64,
2896 /// MVA base.
2897 pub mbase: f64,
2898 /// Load fraction at this bus (0..1].
2899 pub lfac: f64,
2900}
2901
2902// Unknown / fallback
2903// ---------------------------------------------------------------------------
2904
2905// ---------------------------------------------------------------------------
2906// Phase 15: Exciter param structs
2907// ---------------------------------------------------------------------------
2908
2909/// ESST5B — IEEE ST5B static exciter (Phase 15, 3 states: vr, vfilt, efd).
2910#[derive(Debug, Clone, Serialize, Deserialize)]
2911pub struct Esst5bParams {
2912 pub tr: f64,
2913 pub kc: f64,
2914 pub kf: f64,
2915 pub tf: f64,
2916 pub ka: f64,
2917 pub tb: f64,
2918 pub tc: f64,
2919 pub vrmax: f64,
2920 pub vrmin: f64,
2921 pub t1: f64,
2922 pub t2: f64,
2923}
2924
2925/// EXAC4 / AC4A — IEEE AC4A controlled-rectifier exciter (Phase 15, 2 states: vr, efd).
2926#[derive(Debug, Clone, Serialize, Deserialize)]
2927pub struct Exac4Params {
2928 pub tr: f64,
2929 pub tc: f64,
2930 pub tb: f64,
2931 pub ka: f64,
2932 pub ta: f64,
2933 pub vrmax: f64,
2934 pub vrmin: f64,
2935 pub kc: f64,
2936}
2937
2938// ---------------------------------------------------------------------------
2939// Phase 15: Governor param structs
2940// ---------------------------------------------------------------------------
2941
2942/// TGOV5 — Multi-reheat steam governor HP+IP (Phase 15, 4 states).
2943#[derive(Debug, Clone, Serialize, Deserialize)]
2944pub struct Tgov5Params {
2945 /// Droop (speed regulation, pu).
2946 pub r: f64,
2947 /// Governor valve time constant (s).
2948 pub t1: f64,
2949 /// HP stage time constant (s).
2950 pub t2: f64,
2951 /// IP+LP stage time constant (s).
2952 pub t3: f64,
2953 /// Output time constant (s).
2954 pub t4: f64,
2955 /// HP power fraction.
2956 pub k1: f64,
2957 /// IP power fraction.
2958 pub k2: f64,
2959 /// LP power fraction.
2960 pub k3: f64,
2961 /// Maximum power output (pu).
2962 pub pmax: f64,
2963 /// Minimum power output (pu).
2964 pub pmin: f64,
2965}
2966
2967/// GAST2A — Advanced Rowen gas turbine governor (Phase 15, 4 states).
2968///
2969/// Extension of GAST with ambient temperature (radiation loss) state.
2970#[derive(Debug, Clone, Serialize, Deserialize)]
2971pub struct Gast2aParams {
2972 /// Droop (speed regulation, pu).
2973 pub r: f64,
2974 /// Governor valve time constant (s).
2975 pub t1: f64,
2976 /// Turbine output time constant (s).
2977 pub t2: f64,
2978 /// Exhaust temperature time constant (s).
2979 pub t3: f64,
2980 /// Ambient temperature time constant (s).
2981 pub t4: f64,
2982 /// Ambient temperature load limit (pu).
2983 pub at: f64,
2984 /// Exhaust temperature coefficient.
2985 pub kt: f64,
2986 /// Minimum governor output (pu).
2987 pub vmin: f64,
2988 /// Maximum governor output (pu).
2989 pub vmax: f64,
2990}
2991
2992// ---------------------------------------------------------------------------
2993// Phase 15: PSS param structs
2994// ---------------------------------------------------------------------------
2995
2996/// STAB2A — WSCC stabilizer variant A (Phase 15, 3 states: x1, x2, x3).
2997///
2998/// Double lead-lag washout stabilizer.
2999#[derive(Debug, Clone, Serialize, Deserialize)]
3000pub struct Stab2aParams {
3001 /// Stabilizer gain.
3002 pub ks: f64,
3003 /// Washout time constant (s).
3004 pub t1: f64,
3005 /// Lead-lag 1 numerator (s).
3006 pub t2: f64,
3007 /// Lead-lag 1 denominator (s).
3008 pub t3: f64,
3009 /// Lead-lag 2 numerator (s).
3010 pub t4: f64,
3011 /// Lead-lag 2 denominator (s).
3012 pub t5: f64,
3013 /// Output limit (pu, symmetric ±HLIM).
3014 pub hlim: f64,
3015}
3016
3017/// PSS4B — Four-band multi-frequency PSS (Phase 15, 4 states).
3018#[derive(Debug, Clone, Serialize, Deserialize)]
3019pub struct Pss4bParams {
3020 /// Low-band gain.
3021 pub kl: f64,
3022 /// High-band gain.
3023 pub kh: f64,
3024 /// Low-band washout time constant (s).
3025 pub tw1: f64,
3026 /// High-band washout time constant (s).
3027 pub tw2: f64,
3028 /// Lead-lag 1 numerator (s).
3029 pub t1: f64,
3030 /// Lead-lag 1 denominator (s).
3031 pub t2: f64,
3032 /// Lead-lag 2 numerator (s).
3033 pub t3: f64,
3034 /// Lead-lag 2 denominator (s).
3035 pub t4: f64,
3036 /// Maximum PSS output (pu).
3037 pub vstmax: f64,
3038 /// Minimum PSS output (pu).
3039 pub vstmin: f64,
3040}
3041
3042// ---------------------------------------------------------------------------
3043// Phase 15: FACTS param structs
3044// ---------------------------------------------------------------------------
3045
3046/// CSVGN3 — SVC with slope/droop regulator (Phase 15, 3 states, same as CSVGN1 + slope).
3047#[derive(Debug, Clone, Serialize, Deserialize)]
3048pub struct Csvgn3Params {
3049 pub t1: f64,
3050 pub t2: f64,
3051 pub t3: f64,
3052 pub t4: f64,
3053 pub t5: f64,
3054 pub k: f64,
3055 /// Slope (droop) coefficient: Vref = Vref_base + slope*b_svc.
3056 pub slope: f64,
3057 pub vmax: f64,
3058 pub vmin: f64,
3059 pub bmax: f64,
3060 pub bmin: f64,
3061 pub mbase: f64,
3062}
3063
3064/// CDC7T — LCC HVDC + runback + current order controllers (Phase 15, 6 states).
3065///
3066/// Extends CDC4T with runback rate and current order max.
3067#[derive(Debug, Clone, Serialize, Deserialize)]
3068pub struct Cdc7tParams {
3069 pub setvl: f64,
3070 pub vschd: f64,
3071 pub mbase: f64,
3072 pub tr: f64,
3073 pub td: f64,
3074 pub alpha_min: f64,
3075 pub alpha_max: f64,
3076 pub gamma_min: f64,
3077 pub rectifier_bus: u32,
3078 pub inverter_bus: u32,
3079 /// Runback rate (pu/s).
3080 pub runback_rate: f64,
3081 /// Maximum current order (pu).
3082 pub current_order_max: f64,
3083}
3084
3085// ---------------------------------------------------------------------------
3086// Phase 16: Composite Load param structs
3087// ---------------------------------------------------------------------------
3088
3089/// Per-motor circuit parameters for WECC CMPLDW composite load model.
3090#[derive(Debug, Clone, Serialize, Deserialize)]
3091pub struct CmpldwMotorParams {
3092 /// Stator resistance (pu).
3093 pub ra: f64,
3094 /// Magnetizing reactance (pu).
3095 pub xm: f64,
3096 /// Rotor resistance (pu).
3097 pub r1: f64,
3098 /// Rotor reactance (pu).
3099 pub x1: f64,
3100 /// Second cage rotor resistance (pu, 0 = single-cage).
3101 pub r2: f64,
3102 /// Second cage rotor reactance (pu, 0 = single-cage).
3103 pub x2: f64,
3104 /// Motor inertia constant H (s). Default 0.5.
3105 pub h: f64,
3106 /// Voltage trip threshold (pu). Motor trips below this voltage.
3107 pub vtr: f64,
3108 /// Motor load torque exponent (0=constant torque, 2=fan/pump).
3109 pub etrq: f64,
3110}
3111
3112impl Default for CmpldwMotorParams {
3113 fn default() -> Self {
3114 Self {
3115 ra: 0.0,
3116 xm: 3.0,
3117 r1: 0.04,
3118 x1: 0.1,
3119 r2: 0.04,
3120 x2: 0.1,
3121 h: 0.5,
3122 vtr: 0.0,
3123 etrq: 0.0,
3124 }
3125 }
3126}
3127
3128/// CMPLDW — Full WECC composite load model with 3 motors (Phase 4.1, 10 states).
3129///
3130/// The model represents a composite load bus with three induction motor types
3131/// (A=large industrial, B=small commercial, C=A/C compressor) plus static ZIP
3132/// and electronic load fractions. Each motor has independent slip/flux dynamics.
3133///
3134/// # States (10 total)
3135/// - Motor A: slip_a, ed_a, eq_a (3)
3136/// - Motor B: slip_b, ed_b, eq_b (3)
3137/// - Motor C: slip_c, ed_c, eq_c (3)
3138/// - Voltage filter: vfilt (1)
3139#[derive(Debug, Clone, Serialize, Deserialize)]
3140pub struct CmpldwParams {
3141 /// Load fraction: Motor A (large 3-phase industrial).
3142 pub lfma: f64,
3143 /// Load fraction: Motor B (small 3-phase commercial).
3144 pub lfmb: f64,
3145 /// Load fraction: Motor C (1-phase A/C compressor).
3146 pub lfmc: f64,
3147 /// Static load P coefficient 1.
3148 pub kp1: f64,
3149 /// Static load P exponent 1.
3150 pub np1: f64,
3151 /// Static load P coefficient 2.
3152 pub kp2: f64,
3153 /// Static load P exponent 2.
3154 pub np2: f64,
3155 /// Static load Q coefficient 1.
3156 pub kq1: f64,
3157 /// Static load Q exponent 1.
3158 pub nq1: f64,
3159 /// Static load Q coefficient 2.
3160 pub kq2: f64,
3161 /// Static load Q exponent 2.
3162 pub nq2: f64,
3163 // Legacy single-motor fields (kept for backward compat with existing DYR files).
3164 // Used as Motor A defaults when per-motor params are None.
3165 pub ra: f64,
3166 pub xm: f64,
3167 pub r1: f64,
3168 pub x1: f64,
3169 pub r2: f64,
3170 pub x2: f64,
3171 pub vtr1: f64,
3172 pub vtr2: f64,
3173 pub mbase: f64,
3174 /// Per-motor parameters for Motor A (overrides ra/xm/r1/x1 if present).
3175 #[serde(default)]
3176 pub motor_a: Option<CmpldwMotorParams>,
3177 /// Per-motor parameters for Motor B.
3178 #[serde(default)]
3179 pub motor_b: Option<CmpldwMotorParams>,
3180 /// Per-motor parameters for Motor C.
3181 #[serde(default)]
3182 pub motor_c: Option<CmpldwMotorParams>,
3183 /// Voltage filter time constant (s). Default 0.02.
3184 #[serde(default = "default_tv")]
3185 pub tv: f64,
3186 /// Electronic load fraction. Default 0.0.
3187 #[serde(default)]
3188 pub fel: f64,
3189 /// Frequency sensitivity of P (pu/Hz). Default 0.0.
3190 #[serde(default)]
3191 pub pfreq: f64,
3192}
3193
3194fn default_tv() -> f64 {
3195 0.02
3196}
3197
3198impl CmpldwParams {
3199 /// Get Motor A parameters (uses per-motor if set, else legacy single-motor fields).
3200 pub fn motor_a_params(&self) -> CmpldwMotorParams {
3201 self.motor_a.clone().unwrap_or(CmpldwMotorParams {
3202 ra: self.ra,
3203 xm: self.xm,
3204 r1: self.r1,
3205 x1: self.x1,
3206 r2: self.r2,
3207 x2: self.x2,
3208 h: 0.5,
3209 vtr: self.vtr1,
3210 etrq: 0.0,
3211 })
3212 }
3213
3214 /// Get Motor B parameters (uses per-motor if set, else default small motor).
3215 pub fn motor_b_params(&self) -> CmpldwMotorParams {
3216 self.motor_b.clone().unwrap_or(CmpldwMotorParams {
3217 ra: self.ra,
3218 xm: self.xm * 1.5, // higher Xm for small motor
3219 r1: self.r1 * 1.2,
3220 x1: self.x1 * 1.2,
3221 r2: self.r2 * 1.2,
3222 x2: self.x2 * 1.2,
3223 h: 0.3, // lower inertia
3224 vtr: self.vtr2,
3225 etrq: 0.0,
3226 })
3227 }
3228
3229 /// Get Motor C parameters (uses per-motor if set, else default A/C compressor).
3230 pub fn motor_c_params(&self) -> CmpldwMotorParams {
3231 self.motor_c.clone().unwrap_or(CmpldwMotorParams {
3232 ra: self.ra * 0.8,
3233 xm: self.xm * 2.0, // higher Xm for single-phase
3234 r1: self.r1 * 0.8,
3235 x1: self.x1 * 0.8,
3236 r2: self.r2 * 0.8,
3237 x2: self.x2 * 0.8,
3238 h: 0.1, // very low inertia (compressor)
3239 vtr: self.vtr2,
3240 etrq: 2.0, // fan/pump torque
3241 })
3242 }
3243}
3244
3245/// CMPLDWG — CMPLDW with embedded generation (Phase 16, 10 states).
3246#[derive(Debug, Clone, Serialize, Deserialize)]
3247pub struct CmpldwgParams {
3248 pub lfma: f64,
3249 pub lfmb: f64,
3250 pub lfmc: f64,
3251 pub kp1: f64,
3252 pub np1: f64,
3253 pub kp2: f64,
3254 pub np2: f64,
3255 pub kq1: f64,
3256 pub nq1: f64,
3257 pub kq2: f64,
3258 pub nq2: f64,
3259 pub ra: f64,
3260 pub xm: f64,
3261 pub r1: f64,
3262 pub x1: f64,
3263 pub r2: f64,
3264 pub x2: f64,
3265 pub vtr1: f64,
3266 pub vtr2: f64,
3267 pub mbase: f64,
3268 pub gen_mw: f64,
3269 /// Per-motor parameters for Motor A.
3270 #[serde(default)]
3271 pub motor_a: Option<CmpldwMotorParams>,
3272 /// Per-motor parameters for Motor B.
3273 #[serde(default)]
3274 pub motor_b: Option<CmpldwMotorParams>,
3275 /// Per-motor parameters for Motor C.
3276 #[serde(default)]
3277 pub motor_c: Option<CmpldwMotorParams>,
3278 /// Voltage filter time constant (s). Default 0.02.
3279 #[serde(default = "default_tv")]
3280 pub tv: f64,
3281 /// Electronic load fraction. Default 0.0.
3282 #[serde(default)]
3283 pub fel: f64,
3284 /// Frequency sensitivity of P (pu/Hz). Default 0.0.
3285 #[serde(default)]
3286 pub pfreq: f64,
3287}
3288
3289impl CmpldwgParams {
3290 /// Get Motor A parameters.
3291 pub fn motor_a_params(&self) -> CmpldwMotorParams {
3292 self.motor_a.clone().unwrap_or(CmpldwMotorParams {
3293 ra: self.ra,
3294 xm: self.xm,
3295 r1: self.r1,
3296 x1: self.x1,
3297 r2: self.r2,
3298 x2: self.x2,
3299 h: 0.5,
3300 vtr: self.vtr1,
3301 etrq: 0.0,
3302 })
3303 }
3304 /// Get Motor B parameters.
3305 pub fn motor_b_params(&self) -> CmpldwMotorParams {
3306 self.motor_b.clone().unwrap_or(CmpldwMotorParams {
3307 ra: self.ra,
3308 xm: self.xm * 1.5,
3309 r1: self.r1 * 1.2,
3310 x1: self.x1 * 1.2,
3311 r2: self.r2 * 1.2,
3312 x2: self.x2 * 1.2,
3313 h: 0.3,
3314 vtr: self.vtr2,
3315 etrq: 0.0,
3316 })
3317 }
3318 /// Get Motor C parameters.
3319 pub fn motor_c_params(&self) -> CmpldwMotorParams {
3320 self.motor_c.clone().unwrap_or(CmpldwMotorParams {
3321 ra: self.ra * 0.8,
3322 xm: self.xm * 2.0,
3323 r1: self.r1 * 0.8,
3324 x1: self.x1 * 0.8,
3325 r2: self.r2 * 0.8,
3326 x2: self.x2 * 0.8,
3327 h: 0.1,
3328 vtr: self.vtr2,
3329 etrq: 2.0,
3330 })
3331 }
3332}
3333
3334/// CMLDBLU2 — Composite load simplified blue model (Phase 16).
3335#[derive(Debug, Clone, Serialize, Deserialize)]
3336pub struct Cmldblu2Params {
3337 pub t1: f64,
3338 pub t2: f64,
3339 pub k1: f64,
3340 pub k2: f64,
3341 pub pf: f64,
3342 pub kp: f64,
3343 pub kq: f64,
3344 pub vmin: f64,
3345 pub vmax: f64,
3346 pub mbase: f64,
3347}
3348
3349/// CMLDARU2 — Composite load ARU2 model (Phase 16, same params as CMLDBLU2).
3350pub type Cmldaru2Params = Cmldblu2Params;
3351
3352/// MOTORW — Type W induction motor (Phase 16).
3353#[derive(Debug, Clone, Serialize, Deserialize)]
3354pub struct MotorwParams {
3355 pub ra: f64,
3356 pub xm: f64,
3357 pub r1: f64,
3358 pub x1: f64,
3359 pub r2: f64,
3360 pub x2: f64,
3361 pub h: f64,
3362 pub vtr1: f64,
3363 pub vtr2: f64,
3364 pub mbase: f64,
3365}
3366
3367/// CIM5 — Current injection motor model 5th order (Phase 16).
3368#[derive(Debug, Clone, Serialize, Deserialize)]
3369pub struct Cim5Params {
3370 pub ra: f64,
3371 pub xs: f64,
3372 pub xm: f64,
3373 pub xr1: f64,
3374 pub xr2: f64,
3375 pub rr1: f64,
3376 pub rr2: f64,
3377 pub h: f64,
3378 pub e1: f64,
3379 pub s1: f64,
3380 pub e2: f64,
3381 pub s2: f64,
3382 pub mbase: f64,
3383}
3384
3385// ---------------------------------------------------------------------------
3386// Phase 17: Exciter param structs
3387// ---------------------------------------------------------------------------
3388
3389/// ESST6B — IEEE ST6B Static Exciter (Phase 17).
3390#[derive(Debug, Clone, Serialize, Deserialize)]
3391pub struct Esst6bParams {
3392 pub tr: f64,
3393 pub ilr: f64,
3394 pub klr: f64,
3395 pub ka: f64,
3396 pub ta: f64,
3397 pub kc: f64,
3398 pub vrmax: f64,
3399 pub vrmin: f64,
3400 pub kff: f64,
3401 pub kgff: f64,
3402 pub t1: f64,
3403 pub t2: f64,
3404}
3405
3406/// ESST7B — IEEE ST7B Static Exciter (Phase 17).
3407#[derive(Debug, Clone, Serialize, Deserialize)]
3408pub struct Esst7bParams {
3409 pub tr: f64,
3410 pub kpa: f64,
3411 pub kia: f64,
3412 pub vrmax: f64,
3413 pub vrmin: f64,
3414 pub kpff: f64,
3415 pub kh: f64,
3416 pub vmax: f64,
3417 pub vmin: f64,
3418 pub t1: f64,
3419 pub t2: f64,
3420 pub t3: f64,
3421 pub t4: f64,
3422 pub kl: f64,
3423}
3424
3425/// ESAC6A — AC6A Rotating Exciter (Phase 17).
3426#[derive(Debug, Clone, Serialize, Deserialize)]
3427pub struct Esac6aParams {
3428 pub tr: f64,
3429 pub ka: f64,
3430 pub ta: f64,
3431 pub tk: f64,
3432 pub tb: f64,
3433 pub tc: f64,
3434 pub vamax: f64,
3435 pub vamin: f64,
3436 pub vrmax: f64,
3437 pub vrmin: f64,
3438 pub te: f64,
3439 pub kh: f64,
3440 pub kf: f64,
3441 pub tf: f64,
3442 pub kc: f64,
3443 pub kd: f64,
3444 pub ke: f64,
3445}
3446
3447/// ESDC1A — DC1A Rotating Exciter (Phase 17).
3448#[derive(Debug, Clone, Serialize, Deserialize)]
3449pub struct Esdc1aParams {
3450 pub tr: f64,
3451 pub ka: f64,
3452 pub ta: f64,
3453 pub kf: f64,
3454 pub tf: f64,
3455 pub ke: f64,
3456 pub te: f64,
3457 pub se1: f64,
3458 pub e1: f64,
3459 pub se2: f64,
3460 pub e2: f64,
3461 pub vrmax: f64,
3462 pub vrmin: f64,
3463}
3464
3465/// EXST2 — Static Exciter Type ST2 (Phase 17).
3466#[derive(Debug, Clone, Serialize, Deserialize)]
3467pub struct Exst2Params {
3468 pub tr: f64,
3469 pub ka: f64,
3470 pub ta: f64,
3471 pub vrmax: f64,
3472 pub vrmin: f64,
3473 pub kc: f64,
3474 pub ki: f64,
3475 pub ke: f64,
3476 pub te: f64,
3477}
3478
3479/// AC8B — IEEE AC8B High Initial Response Exciter (Phase 17).
3480#[derive(Debug, Clone, Serialize, Deserialize)]
3481pub struct Ac8bParams {
3482 pub tr: f64,
3483 pub ka: f64,
3484 pub ta: f64,
3485 pub kc: f64,
3486 pub vrmax: f64,
3487 pub vrmin: f64,
3488 pub kd: f64,
3489 pub ke: f64,
3490 pub te: f64,
3491 pub pid_kp: f64,
3492 pub pid_ki: f64,
3493 pub pid_kd: f64,
3494}
3495
3496/// BBSEX1 — Bus-Branch Static Exciter 1 (Phase 17).
3497#[derive(Debug, Clone, Serialize, Deserialize)]
3498pub struct Bbsex1Params {
3499 pub t1r: f64,
3500 pub t2r: f64,
3501 pub t3r: f64,
3502 pub t4r: f64,
3503 pub t1i: f64,
3504 pub t2i: f64,
3505 pub ka: f64,
3506 pub ta: f64,
3507 pub vrmax: f64,
3508 pub vrmin: f64,
3509}
3510
3511/// IEEET3 — IEEE Type 3 Rotating Exciter (Phase 17).
3512#[derive(Debug, Clone, Serialize, Deserialize)]
3513pub struct Ieeet3Params {
3514 pub tr: f64,
3515 pub ka: f64,
3516 pub ta: f64,
3517 pub vrmax: f64,
3518 pub vrmin: f64,
3519 pub kf: f64,
3520 pub tf: f64,
3521 pub ke: f64,
3522 pub te: f64,
3523 pub e1: f64,
3524 pub se1: f64,
3525 pub e2: f64,
3526 pub se2: f64,
3527 pub kp: f64,
3528 pub ki: f64,
3529 pub kc: f64,
3530}
3531
3532// ---------------------------------------------------------------------------
3533// Phase 18: Governor + PSS param structs
3534// ---------------------------------------------------------------------------
3535
3536/// H6E — Hydro Governor 6 Elements (Phase 18).
3537#[derive(Debug, Clone, Serialize, Deserialize)]
3538pub struct H6eParams {
3539 pub r: f64,
3540 pub tr: f64,
3541 pub tf: f64,
3542 pub tg: f64,
3543 pub tw: f64,
3544 pub t1: f64,
3545 pub t2: f64,
3546 pub t3: f64,
3547 pub t4: f64,
3548 pub t5: f64,
3549 pub dt: f64,
3550 pub pmax: f64,
3551 pub pmin: f64,
3552}
3553
3554/// WSHYGP — Wind-Synchronous Hydro Governor+Pitch (Phase 18).
3555#[derive(Debug, Clone, Serialize, Deserialize)]
3556pub struct WshygpParams {
3557 pub r: f64,
3558 pub tf: f64,
3559 pub tg: f64,
3560 pub tw: f64,
3561 pub kd: f64,
3562 pub pmax: f64,
3563 pub pmin: f64,
3564 pub kp: f64,
3565 pub ki: f64,
3566}
3567
3568/// STAB3 — Three-Band PSS (Phase 18).
3569#[derive(Debug, Clone, Serialize, Deserialize)]
3570pub struct Stab3Params {
3571 pub ks: f64,
3572 pub t1: f64,
3573 pub t2: f64,
3574 pub t3: f64,
3575 pub t4: f64,
3576 pub t5: f64,
3577 pub t6: f64,
3578 pub vstmax: f64,
3579 pub vstmin: f64,
3580}
3581
3582/// PSS3B — Three-Input Power System Stabilizer (Phase 18).
3583#[derive(Debug, Clone, Serialize, Deserialize)]
3584pub struct Pss3bParams {
3585 pub a1: f64,
3586 pub a2: f64,
3587 pub a3: f64,
3588 pub a4: f64,
3589 pub a5: f64,
3590 pub a6: f64,
3591 pub a7: f64,
3592 pub a8: f64,
3593 pub vsi1max: f64,
3594 pub vsi1min: f64,
3595 pub vsi2max: f64,
3596 pub vsi2min: f64,
3597 pub vstmax: f64,
3598 pub vstmin: f64,
3599}
3600
3601// ---------------------------------------------------------------------------
3602// Phase 19: IBR Wind Controller param structs (go in exciter slot)
3603// ---------------------------------------------------------------------------
3604
3605/// WT3E1 — Type 3 Wind Electrical Controller (Phase 19).
3606#[derive(Debug, Clone, Serialize, Deserialize)]
3607pub struct Wt3e1Params {
3608 pub kpv: f64,
3609 pub kiv: f64,
3610 pub kqv: f64,
3611 pub xd: f64,
3612 pub kpq: f64,
3613 pub kiq: f64,
3614 pub tpe: f64,
3615 pub pmin: f64,
3616 pub pmax: f64,
3617 pub qmin: f64,
3618 pub qmax: f64,
3619 pub imax: f64,
3620 /// Voltage measurement filter time constant (s, default 0.05).
3621 pub tv: f64,
3622}
3623
3624/// WT3E2 — Type 3 Wind Electrical Controller Variant 2 (Phase 19).
3625#[derive(Debug, Clone, Serialize, Deserialize)]
3626pub struct Wt3e2Params {
3627 pub kpv: f64,
3628 pub kiv: f64,
3629 pub kqv: f64,
3630 pub xd: f64,
3631 pub kpq: f64,
3632 pub kiq: f64,
3633 pub tpe: f64,
3634 pub pmin: f64,
3635 pub pmax: f64,
3636 pub qmin: f64,
3637 pub qmax: f64,
3638 pub imax: f64,
3639 pub tiq: f64,
3640 /// Voltage measurement filter time constant (s, default 0.05).
3641 pub tv: f64,
3642}
3643
3644/// WT4E1 — Type 4 Wind Electrical Controller (Phase 19).
3645#[derive(Debug, Clone, Serialize, Deserialize)]
3646pub struct Wt4e1Params {
3647 pub kpv: f64,
3648 pub kiv: f64,
3649 pub tpe: f64,
3650 pub pmin: f64,
3651 pub pmax: f64,
3652 pub qmin: f64,
3653 pub qmax: f64,
3654 pub imax: f64,
3655}
3656
3657/// WT4E2 — Type 4 Wind Electrical Controller Variant 2 (Phase 19, same as WT4E1).
3658pub type Wt4e2Params = Wt4e1Params;
3659
3660/// REPCB — REPCA Variant B (Phase 19).
3661#[derive(Debug, Clone, Serialize, Deserialize)]
3662pub struct RepcbParams {
3663 pub tp: f64,
3664 pub tfltr: f64,
3665 pub kp: f64,
3666 pub ki: f64,
3667 pub tft: f64,
3668 pub tfv: f64,
3669 pub qmax: f64,
3670 pub qmin: f64,
3671 pub vmax: f64,
3672 pub vmin: f64,
3673 pub kc: f64,
3674 pub refs: f64,
3675}
3676
3677// ---------------------------------------------------------------------------
3678// Phase 20: FACTS param structs
3679// ---------------------------------------------------------------------------
3680
3681/// CSVGN4 — SVC with 4 states (adds POD) (Phase 20).
3682#[derive(Debug, Clone, Serialize, Deserialize)]
3683pub struct Csvgn4Params {
3684 pub t1: f64,
3685 pub t2: f64,
3686 pub t3: f64,
3687 pub t4: f64,
3688 pub t5: f64,
3689 pub k: f64,
3690 pub slope: f64,
3691 pub kpod: f64,
3692 pub tpod: f64,
3693 pub vmax: f64,
3694 pub vmin: f64,
3695 pub bmax: f64,
3696 pub bmin: f64,
3697 pub mbase: f64,
3698}
3699
3700/// CSVGN5 — SVC with 4 states (voltage support mode) (Phase 20).
3701#[derive(Debug, Clone, Serialize, Deserialize)]
3702pub struct Csvgn5Params {
3703 pub t1: f64,
3704 pub t2: f64,
3705 pub t3: f64,
3706 pub t4: f64,
3707 pub t5: f64,
3708 pub k: f64,
3709 pub kv: f64,
3710 pub kpod: f64,
3711 pub tpod: f64,
3712 pub vmax: f64,
3713 pub vmin: f64,
3714 pub bmax: f64,
3715 pub bmin: f64,
3716 pub mbase: f64,
3717}
3718
3719/// CDC6T — LCC HVDC with enhanced controls (Phase 20).
3720#[derive(Debug, Clone, Serialize, Deserialize)]
3721pub struct Cdc6tParams {
3722 pub setvl: f64,
3723 pub vschd: f64,
3724 pub mbase: f64,
3725 pub tr: f64,
3726 pub td: f64,
3727 pub alpha_min: f64,
3728 pub alpha_max: f64,
3729 pub gamma_min: f64,
3730 pub rectifier_bus: u32,
3731 pub inverter_bus: u32,
3732 pub i_limit: f64,
3733}
3734
3735/// CSTCNT — STATCOM with N controls (4 states) (Phase 20).
3736#[derive(Debug, Clone, Serialize, Deserialize)]
3737pub struct CstcntParams {
3738 pub t1: f64,
3739 pub t2: f64,
3740 pub t3: f64,
3741 pub ka: f64,
3742 pub ta: f64,
3743 pub iqmax: f64,
3744 pub iqmin: f64,
3745 pub mbase: f64,
3746}
3747
3748/// MMC1 — Modular Multilevel Converter (5 states) (Phase 20).
3749#[derive(Debug, Clone, Serialize, Deserialize)]
3750pub struct Mmc1Params {
3751 pub tr: f64,
3752 pub kp_v: f64,
3753 pub ki_v: f64,
3754 pub kp_i: f64,
3755 pub ki_i: f64,
3756 pub vdc: f64,
3757 pub larm: f64,
3758 pub pmax: f64,
3759 pub pmin: f64,
3760 pub qmax: f64,
3761 pub qmin: f64,
3762 pub mbase: f64,
3763}
3764
3765// ---------------------------------------------------------------------------
3766// Phase 21: EXST3 + BESS param structs
3767// ---------------------------------------------------------------------------
3768
3769/// EXST3 — Static Exciter Type ST3 (Phase 21).
3770#[derive(Debug, Clone, Serialize, Deserialize)]
3771pub struct Exst3Params {
3772 pub tr: f64,
3773 pub ka: f64,
3774 pub ta: f64,
3775 pub tb: f64,
3776 pub tc: f64,
3777 pub vrmax: f64,
3778 pub vrmin: f64,
3779 pub kc: f64,
3780 pub ki: f64,
3781 pub km: f64,
3782 pub vmmax: f64,
3783 pub vmmin: f64,
3784 pub xm: f64,
3785}
3786
3787/// CBUFR — Buffer-Frequency-Regulated BESS (Phase 21).
3788#[derive(Debug, Clone, Serialize, Deserialize)]
3789pub struct CbufrParams {
3790 pub kf: f64,
3791 pub tf: f64,
3792 pub tp: f64,
3793 pub p_base: f64,
3794 pub p_min: f64,
3795 pub p_max: f64,
3796 pub e_cap: f64,
3797 /// Initial state of charge (0..1, default 0.5).
3798 pub soc_init: f64,
3799}
3800
3801/// CBUFD — Buffer-Frequency-Dependent BESS (Phase 21).
3802#[derive(Debug, Clone, Serialize, Deserialize)]
3803pub struct CbufdParams {
3804 pub kf: f64,
3805 pub tf: f64,
3806 pub tp: f64,
3807 pub tq: f64,
3808 pub p_base: f64,
3809 pub p_min: f64,
3810 pub p_max: f64,
3811 pub q_base: f64,
3812 pub q_min: f64,
3813 pub q_max: f64,
3814 pub e_cap: f64,
3815 /// Initial state of charge (0..1, default 0.5).
3816 pub soc_init: f64,
3817}
3818
3819/// REGFM_C1 — Grid-forming inverter C1 (Phase 21).
3820#[derive(Debug, Clone, Serialize, Deserialize)]
3821pub struct RegfmC1Params {
3822 pub kd: f64,
3823 pub ki: f64,
3824 pub kq: f64,
3825 pub tg: f64,
3826 pub ddn: f64,
3827 pub dup: f64,
3828 pub pmax: f64,
3829 pub pmin: f64,
3830 pub qmax: f64,
3831 pub qmin: f64,
3832 pub mbase: f64,
3833}
3834
3835// ---------------------------------------------------------------------------
3836// Phase 22: Solar PV Models
3837// ---------------------------------------------------------------------------
3838
3839/// PVGU1 — WECC 1st-gen photovoltaic converter unit.
3840/// Norton current injection, reuses RegcaState (4 fields: ip_cmd, iq_cmd, v_filt, x_eq/pm0).
3841#[derive(Debug, Clone, Serialize, Deserialize)]
3842pub struct Pvgu1Params {
3843 pub lvplsw: f64,
3844 pub rrpwr: f64,
3845 pub brkpt: f64,
3846 pub zerox: f64,
3847 pub lvpl1: f64,
3848 pub volim: f64,
3849 pub lvpnt1: f64,
3850 pub lvpnt0: f64,
3851 pub iolim: f64,
3852 pub tfltr: f64,
3853 pub khv: f64,
3854 pub iqrmax: f64,
3855 pub iqrmin: f64,
3856 pub accel: f64,
3857 pub vsmax: f64,
3858 pub mbase: f64,
3859}
3860
3861/// PVEU1 — WECC 1st-gen PV electrical control unit (maps to exciter slot).
3862#[derive(Debug, Clone, Serialize, Deserialize)]
3863pub struct Pveu1Params {
3864 pub tiq: f64,
3865 pub dflag: f64,
3866 pub vref0: f64,
3867 pub tv: f64,
3868 pub dbd: f64,
3869 pub kqv: f64,
3870 pub iqhl: f64,
3871 pub iqll: f64,
3872 pub pmax: f64,
3873 pub pmin: f64,
3874 pub qmax: f64,
3875 pub qmin: f64,
3876 pub vmax: f64,
3877 pub vmin: f64,
3878 pub tpord: f64,
3879 pub mbase: f64,
3880}
3881
3882/// PVDG — Distributed/rooftop PV aggregate model.
3883#[derive(Debug, Clone, Serialize, Deserialize)]
3884pub struct PvdgParams {
3885 pub tp: f64,
3886 pub tq: f64,
3887 pub vtrip1: f64,
3888 pub vtrip2: f64,
3889 pub vtrip3: f64,
3890 pub ftrip1: f64,
3891 pub ftrip2: f64,
3892 pub pmax: f64,
3893 pub qmax: f64,
3894 pub qmin: f64,
3895 pub mbase: f64,
3896}
3897
3898// ---------------------------------------------------------------------------
3899// Phase 23: Exciter param structs
3900// ---------------------------------------------------------------------------
3901
3902/// IEEET2 — IEEE Type 2 rotating-machine exciter.
3903#[derive(Debug, Clone, Serialize, Deserialize)]
3904pub struct Ieeet2Params {
3905 pub tr: f64,
3906 pub ka: f64,
3907 pub ta: f64,
3908 pub vrmax: f64,
3909 pub vrmin: f64,
3910 pub ke: f64,
3911 pub te: f64,
3912 pub e1: f64,
3913 pub se1: f64,
3914 pub e2: f64,
3915 pub se2: f64,
3916 pub kf: f64,
3917 pub tf: f64,
3918}
3919
3920/// EXAC2 — IEEE AC2A high initial response rotating exciter.
3921#[derive(Debug, Clone, Serialize, Deserialize)]
3922pub struct Exac2Params {
3923 pub tr: f64,
3924 pub tb: f64,
3925 pub tc: f64,
3926 pub ka: f64,
3927 pub ta: f64,
3928 pub vamax: f64,
3929 pub vamin: f64,
3930 pub te: f64,
3931 pub kf: f64,
3932 pub tf: f64,
3933 pub ke: f64,
3934 pub e1: f64,
3935 pub se1: f64,
3936 pub e2: f64,
3937 pub se2: f64,
3938 pub kc: f64,
3939 pub kd: f64,
3940 pub kh: f64,
3941}
3942
3943/// EXAC3 — IEEE AC3A controlled-rectifier exciter.
3944#[derive(Debug, Clone, Serialize, Deserialize)]
3945pub struct Exac3Params {
3946 pub tr: f64,
3947 pub kc: f64,
3948 pub ki: f64,
3949 pub vmin: f64,
3950 pub vmax: f64,
3951 pub ke: f64,
3952 pub te: f64,
3953 pub kf: f64,
3954 pub tf: f64,
3955 pub e1: f64,
3956 pub se1: f64,
3957 pub e2: f64,
3958 pub se2: f64,
3959 pub ka: f64,
3960 pub ta: f64,
3961 pub efdn: f64,
3962}
3963
3964/// ESAC3A — IEEE 421.5-2005 AC3A exciter update.
3965#[derive(Debug, Clone, Serialize, Deserialize)]
3966pub struct Esac3aParams {
3967 pub tr: f64,
3968 pub tb: f64,
3969 pub tc: f64,
3970 pub ka: f64,
3971 pub ta: f64,
3972 pub vamax: f64,
3973 pub vamin: f64,
3974 pub te: f64,
3975 pub ke: f64,
3976 pub kf1: f64,
3977 pub tf: f64,
3978 pub e1: f64,
3979 pub se1: f64,
3980 pub e2: f64,
3981 pub se2: f64,
3982 pub kc: f64,
3983 pub kd: f64,
3984 pub ki: f64,
3985 pub efdn: f64,
3986 pub kn: f64,
3987 pub vfemax: f64,
3988}
3989
3990/// ESST8C — IEEE 421.5-2016 ST8C static exciter (PID voltage regulator).
3991#[derive(Debug, Clone, Serialize, Deserialize)]
3992pub struct Esst8cParams {
3993 pub tr: f64,
3994 pub kpr: f64,
3995 pub kir: f64,
3996 pub vrmax: f64,
3997 pub vrmin: f64,
3998 pub ka: f64,
3999 pub ta: f64,
4000 pub kc: f64,
4001 pub vbmax: f64,
4002 pub xl: f64,
4003 pub kf: f64,
4004 pub tf: f64,
4005}
4006
4007/// ESST9B — IEEE 421.5-2016 ST9B static exciter (simplified ST8C variant).
4008#[derive(Debug, Clone, Serialize, Deserialize)]
4009pub struct Esst9bParams {
4010 pub tr: f64,
4011 pub kpa: f64,
4012 pub kia: f64,
4013 pub vrmax: f64,
4014 pub vrmin: f64,
4015 pub ka: f64,
4016 pub ta: f64,
4017 pub vbmax: f64,
4018 pub kc: f64,
4019 pub t1: f64,
4020 pub t2: f64,
4021 pub t3: f64,
4022 pub t4: f64,
4023}
4024
4025/// ESST10C — IEEE 421.5-2016 ST10C static exciter (multi-stage PI with UEL/OEL).
4026#[derive(Debug, Clone, Serialize, Deserialize)]
4027pub struct Esst10cParams {
4028 pub tr: f64,
4029 pub kpa: f64,
4030 pub kia: f64,
4031 pub kpb: f64,
4032 pub kib: f64,
4033 pub vrmax: f64,
4034 pub vrmin: f64,
4035 pub ka: f64,
4036 pub ta: f64,
4037 pub vbmax: f64,
4038 pub kc: f64,
4039 pub t1: f64,
4040 pub t2: f64,
4041}
4042
4043/// ESDC3A — IEEE 421.5-2005 DC3A rotating-machine exciter.
4044#[derive(Debug, Clone, Serialize, Deserialize)]
4045pub struct Esdc3aParams {
4046 pub tr: f64,
4047 pub ka: f64,
4048 pub ta: f64,
4049 pub vrmax: f64,
4050 pub vrmin: f64,
4051 pub te: f64,
4052 pub ke: f64,
4053 pub e1: f64,
4054 pub se1: f64,
4055 pub e2: f64,
4056 pub se2: f64,
4057 pub kp: f64,
4058 pub ki: f64,
4059 pub kf: f64,
4060 pub tf: f64,
4061}
4062
4063// ---------------------------------------------------------------------------
4064// Wave 32: EXDC1 + ESST2A param structs
4065// ---------------------------------------------------------------------------
4066
4067/// EXDC1 — IEEE Type DC1A rotating-machine exciter (legacy 13-param form).
4068///
4069/// PSS/E format: TR KA TA VRMAX VRMIN KE TE KF TF E1 SE1 E2 SE2
4070#[derive(Debug, Clone, Serialize, Deserialize)]
4071pub struct Exdc1Params {
4072 pub tr: f64,
4073 pub ka: f64,
4074 pub ta: f64,
4075 pub vrmax: f64,
4076 pub vrmin: f64,
4077 pub ke: f64,
4078 pub te: f64,
4079 pub kf: f64,
4080 pub tf: f64,
4081 pub e1: f64,
4082 pub se1: f64,
4083 pub e2: f64,
4084 pub se2: f64,
4085}
4086
4087/// ESST2A — IEEE 421.5-2016 Type ST2A static exciter.
4088///
4089/// PSS/E format: TR KA TA TB TC KE TE KF TF VRMAX VRMIN EFD1 SE1 EFD2 SE2 KC KP KI \[TP\]
4090#[derive(Debug, Clone, Serialize, Deserialize)]
4091pub struct Esst2aParams {
4092 pub tr: f64,
4093 pub ka: f64,
4094 pub ta: f64,
4095 pub tb: f64,
4096 pub tc: f64,
4097 pub ke: f64,
4098 pub te: f64,
4099 pub kf: f64,
4100 pub tf: f64,
4101 pub vrmax: f64,
4102 pub vrmin: f64,
4103 pub e1: f64, // EFD1 — first saturation breakpoint (pu)
4104 pub se1: f64, // SE(EFD1)
4105 pub e2: f64, // EFD2 — second saturation breakpoint (pu)
4106 pub se2: f64, // SE(EFD2)
4107 pub kc: f64, // rectifier loading factor
4108 pub kp: f64, // potential circuit gain (terminal voltage)
4109 pub ki: f64, // current circuit gain
4110 pub tp: f64, // potential-circuit transducer time constant (s)
4111}
4112
4113// Wave 33: EXDC3 param struct
4114// ---------------------------------------------------------------------------
4115
4116/// EXDC3 — PSS/E non-continuously-acting (relay-type) DC exciter.
4117///
4118/// PSS/E format: TR KV TSTALL TCON TB TC VRMAX VRMIN VEFF TLIM VLIM KE TE
4119#[derive(Debug, Clone, Serialize, Deserialize)]
4120pub struct Exdc3Params {
4121 pub tr: f64,
4122 pub kv: f64, // regulator deadband threshold (pu)
4123 pub tstall: f64, // stalling/feedback time constant (s)
4124 pub tcon: f64, // relay control time constant (s)
4125 pub tb: f64,
4126 pub tc: f64,
4127 pub vrmax: f64,
4128 pub vrmin: f64,
4129 pub veff: f64,
4130 pub tlim: f64,
4131 pub vlim: f64,
4132 pub ke: f64,
4133 pub te: f64,
4134}
4135
4136// ---------------------------------------------------------------------------
4137// Phase 24: PSS variant param structs
4138// ---------------------------------------------------------------------------
4139
4140/// PSS2C — PSS2B with ramp-tracking filter on input 2.
4141#[derive(Debug, Clone, Serialize, Deserialize)]
4142pub struct Pss2cParams {
4143 pub m1: f64,
4144 pub t6: f64,
4145 pub m2: f64,
4146 pub t7: f64,
4147 pub tw1: f64,
4148 pub tw2: f64,
4149 pub tw3: f64,
4150 pub tw4: f64,
4151 pub t1: f64,
4152 pub t2: f64,
4153 pub t3: f64,
4154 pub t4: f64,
4155 pub t8: f64,
4156 pub t9: f64,
4157 pub n: i32,
4158 pub ks1: f64,
4159 pub ks2: f64,
4160 pub ks3: f64,
4161 pub vstmax: f64,
4162 pub vstmin: f64,
4163}
4164
4165/// PSS5 — Five-band multi-frequency power system stabilizer.
4166#[derive(Debug, Clone, Serialize, Deserialize)]
4167pub struct Pss5Params {
4168 pub kl: f64,
4169 pub km: f64,
4170 pub kh: f64,
4171 pub tw1: f64,
4172 pub tw2: f64,
4173 pub tw3: f64,
4174 pub t1: f64,
4175 pub t2: f64,
4176 pub t3: f64,
4177 pub t4: f64,
4178 pub t5: f64,
4179 pub t6: f64,
4180 pub vstmax: f64,
4181 pub vstmin: f64,
4182}
4183
4184/// PSS6C — Six-input multi-band PSS.
4185#[derive(Debug, Clone, Serialize, Deserialize)]
4186pub struct Pss6cParams {
4187 pub kl: f64,
4188 pub km: f64,
4189 pub kh: f64,
4190 pub kl2: f64,
4191 pub km2: f64,
4192 pub kh2: f64,
4193 pub tw1: f64,
4194 pub tw2: f64,
4195 pub tw3: f64,
4196 pub tw4: f64,
4197 pub tw5: f64,
4198 pub tw6: f64,
4199 pub t1: f64,
4200 pub t2: f64,
4201 pub t3: f64,
4202 pub t4: f64,
4203 pub vstmax: f64,
4204 pub vstmin: f64,
4205}
4206
4207/// PSSSB — WSCC/BPA simple power system stabilizer (vendor variant B).
4208#[derive(Debug, Clone, Serialize, Deserialize)]
4209pub struct PsssbParams {
4210 pub ks: f64,
4211 pub t1: f64,
4212 pub t2: f64,
4213 pub t3: f64,
4214 pub t4: f64,
4215 pub t5: f64,
4216 pub t6: f64,
4217 pub tw: f64,
4218 pub vstmax: f64,
4219 pub vstmin: f64,
4220}
4221
4222/// STAB4 — WSCC power system stabilizer variant 4.
4223#[derive(Debug, Clone, Serialize, Deserialize)]
4224pub struct Stab4Params {
4225 pub ks: f64,
4226 pub t1: f64,
4227 pub t2: f64,
4228 pub t3: f64,
4229 pub t4: f64,
4230 pub t5: f64,
4231 pub t6: f64,
4232 pub t7: f64,
4233 pub t8: f64,
4234 pub hlim: f64,
4235}
4236
4237/// STAB5 — WSCC power system stabilizer variant 5.
4238#[derive(Debug, Clone, Serialize, Deserialize)]
4239pub struct Stab5Params {
4240 pub ks: f64,
4241 pub t1: f64,
4242 pub t2: f64,
4243 pub t3: f64,
4244 pub t4: f64,
4245 pub t5: f64,
4246 pub t6: f64,
4247 pub t7: f64,
4248 pub t8: f64,
4249 pub t9: f64,
4250 pub t10: f64,
4251 pub hlim: f64,
4252}
4253
4254// ---------------------------------------------------------------------------
4255// Phase 25: Governor variant param structs
4256// ---------------------------------------------------------------------------
4257
4258/// GGOV2 — GE GGOV1 variant 2 with supplemental load reference input.
4259#[derive(Debug, Clone, Serialize, Deserialize)]
4260pub struct Ggov2Params {
4261 pub r: f64,
4262 pub rselect: f64,
4263 pub tpelec: f64,
4264 pub maxerr: f64,
4265 pub minerr: f64,
4266 pub kpgov: f64,
4267 pub kigov: f64,
4268 pub kdgov: f64,
4269 pub tdgov: f64,
4270 pub vmax: f64,
4271 pub vmin: f64,
4272 pub tact: f64,
4273 pub kturb: f64,
4274 pub wfnl: f64,
4275 pub tb: f64,
4276 pub tc: f64,
4277 pub flag: f64,
4278 pub teng: f64,
4279 pub tfload: f64,
4280 pub kpload: f64,
4281 pub kiload: f64,
4282 pub ldref: f64,
4283 pub dm: f64,
4284 pub ropen: f64,
4285 pub rclose: f64,
4286 pub kimw: f64,
4287 pub pmwset: f64,
4288 pub aset: f64,
4289 pub ka: f64,
4290 pub ta: f64,
4291 pub db: f64,
4292 pub tsa: f64,
4293 pub tsb: f64,
4294 pub rup: f64,
4295 pub rdown: f64,
4296 pub pmax: f64,
4297 pub pmin: f64,
4298}
4299
4300/// GGOV3 — GE GGOV1 variant 3 with washout filter on speed signal.
4301#[derive(Debug, Clone, Serialize, Deserialize)]
4302pub struct Ggov3Params {
4303 pub r: f64,
4304 pub rselect: f64,
4305 pub tpelec: f64,
4306 pub maxerr: f64,
4307 pub minerr: f64,
4308 pub kpgov: f64,
4309 pub kigov: f64,
4310 pub kdgov: f64,
4311 pub tdgov: f64,
4312 pub vmax: f64,
4313 pub vmin: f64,
4314 pub tact: f64,
4315 pub kturb: f64,
4316 pub wfnl: f64,
4317 pub tb: f64,
4318 pub tc: f64,
4319 pub flag: f64,
4320 pub teng: f64,
4321 pub tfload: f64,
4322 pub kpload: f64,
4323 pub kiload: f64,
4324 pub ldref: f64,
4325 pub dm: f64,
4326 pub ropen: f64,
4327 pub rclose: f64,
4328 pub kimw: f64,
4329 pub pmwset: f64,
4330 pub aset: f64,
4331 pub ka: f64,
4332 pub ta: f64,
4333 pub db: f64,
4334 pub tsa: f64,
4335 pub tsb: f64,
4336 pub tw: f64,
4337 pub rup: f64,
4338 pub rdown: f64,
4339 pub pmax: f64,
4340 pub pmin: f64,
4341}
4342
4343/// WPIDHY — Woodward PID Hydro Governor.
4344#[derive(Debug, Clone, Serialize, Deserialize)]
4345pub struct WpidhyParams {
4346 pub gatmax: f64,
4347 pub gatmin: f64,
4348 pub reg: f64,
4349 pub kp: f64,
4350 pub ki: f64,
4351 pub kd: f64,
4352 pub ta: f64,
4353 pub tb: f64,
4354 pub tw: f64,
4355 pub at: f64,
4356 pub dturb: f64,
4357 pub gmax: f64,
4358 pub gmin: f64,
4359 pub pmax: f64,
4360 pub pmin: f64,
4361}
4362
4363/// H6B — Six-State Hydro Governor Variant B.
4364#[derive(Debug, Clone, Serialize, Deserialize)]
4365pub struct H6bParams {
4366 pub tg: f64, // governor time constant
4367 pub tp: f64, // pilot valve time constant
4368 pub uo: f64, // max gate opening rate
4369 pub uc: f64, // max gate closing rate
4370 pub pmax: f64,
4371 pub pmin: f64,
4372 pub beta: f64, // turbine gain
4373 pub tw: f64, // water starting time
4374 pub dbinf: f64, // dead band inferior
4375 pub dbsup: f64, // dead band superior
4376}
4377
4378/// WSHYDD — WSHYGP with speed deadband.
4379#[derive(Debug, Clone, Serialize, Deserialize)]
4380pub struct WshyddParams {
4381 pub r: f64,
4382 pub tf: f64,
4383 pub tg: f64,
4384 pub tw: f64,
4385 pub db: f64, // speed deadband (pu)
4386 pub kd: f64,
4387 pub pmax: f64,
4388 pub pmin: f64,
4389 pub kp: f64,
4390 pub ki: f64,
4391}
4392
4393// ---------------------------------------------------------------------------
4394// Phase 26: HVDC/FACTS Advanced param structs
4395// ---------------------------------------------------------------------------
4396
4397/// HVDCPLU1 — PSS/E LCC (line-commutated converter) HVDC two-terminal model.
4398///
4399/// Implements 6-pulse bridge firing-angle / extinction-angle physics with constant-current
4400/// control at the rectifier, CEA control at the inverter, VDCOL, and a DC circuit ODE.
4401/// This replaces the former VSC proxy (which was wrong physics).
4402#[derive(Debug, Clone, Serialize, Deserialize)]
4403pub struct HvdcPlu1Params {
4404 /// Scheduled DC power (pu on mbase).
4405 pub setvl: f64,
4406 /// Scheduled DC voltage (pu on system base).
4407 pub vschd: f64,
4408 /// MVA base of the HVDC link.
4409 pub mbase: f64,
4410 /// Commutation reactance at rectifier (pu).
4411 pub xcr: f64,
4412 /// Commutation reactance at inverter (pu).
4413 pub xci: f64,
4414 /// DC line resistance (pu).
4415 pub rdc: f64,
4416 /// DC circuit time constant (s).
4417 pub td: f64,
4418 /// Measurement / control filter time constant (s).
4419 pub tr: f64,
4420 /// Minimum firing angle at rectifier (rad).
4421 pub alpha_min: f64,
4422 /// Maximum firing angle at rectifier (rad).
4423 pub alpha_max: f64,
4424 /// Minimum extinction angle at inverter (rad).
4425 pub gamma_min: f64,
4426 /// CC control proportional gain.
4427 pub kp_id: f64,
4428 /// CC control integral gain.
4429 pub ki_id: f64,
4430 /// Power order ramp time constant (s).
4431 pub t_ramp: f64,
4432 /// Max power (pu).
4433 pub pmax: f64,
4434 /// Min power (pu, usually 0 or small positive).
4435 pub pmin: f64,
4436 /// Rectifier AC bus number.
4437 pub rectifier_bus: u32,
4438 /// Inverter AC bus number.
4439 pub inverter_bus: u32,
4440}
4441
4442/// CSVGN6 — SVC Variant 6 with Auxiliary Inputs.
4443#[derive(Debug, Clone, Serialize, Deserialize)]
4444pub struct Csvgn6Params {
4445 pub t1: f64,
4446 pub t2: f64,
4447 pub t3: f64,
4448 pub t4: f64,
4449 pub t5: f64,
4450 pub k: f64,
4451 pub k_aux: f64,
4452 pub t_aux: f64,
4453 pub vmax: f64,
4454 pub vmin: f64,
4455 pub bmax: f64,
4456 pub bmin: f64,
4457}
4458
4459/// STCON1 — STATCOM with Inner Current Control.
4460#[derive(Debug, Clone, Serialize, Deserialize)]
4461pub struct Stcon1Params {
4462 pub tr: f64,
4463 pub kp: f64,
4464 pub ki: f64,
4465 pub kp_i: f64,
4466 pub ki_i: f64,
4467 pub vmax: f64,
4468 pub vmin: f64,
4469 pub iqmax: f64,
4470 pub iqmin: f64,
4471 pub mbase: f64,
4472}
4473
4474/// GCSC — Gate-Controlled Series Compensator.
4475#[derive(Debug, Clone, Serialize, Deserialize)]
4476pub struct GcscParams {
4477 pub tr: f64,
4478 pub kp: f64,
4479 pub ki: f64,
4480 pub xmax: f64,
4481 pub xmin: f64,
4482 pub mbase: f64,
4483}
4484
4485/// SSSC — Static Synchronous Series Compensator.
4486#[derive(Debug, Clone, Serialize, Deserialize)]
4487pub struct SsscParams {
4488 pub tr: f64,
4489 pub kp: f64,
4490 pub ki: f64,
4491 pub kp_i: f64,
4492 pub ki_i: f64,
4493 pub vqmax: f64,
4494 pub vqmin: f64,
4495 pub mbase: f64,
4496}
4497
4498/// UPFC — Unified Power Flow Controller.
4499#[derive(Debug, Clone, Serialize, Deserialize)]
4500pub struct UpfcParams {
4501 pub tr: f64,
4502 pub kp_p: f64,
4503 pub ki_p: f64,
4504 pub kp_q: f64,
4505 pub ki_q: f64,
4506 pub kp_v: f64,
4507 pub ki_v: f64,
4508 pub pmax: f64,
4509 pub pmin: f64,
4510 pub qmax: f64,
4511 pub qmin: f64,
4512 pub mbase: f64,
4513}
4514
4515/// CDC3T — Three-Terminal LCC HVDC (extends CDC4T with third terminal).
4516#[derive(Debug, Clone, Serialize, Deserialize)]
4517pub struct Cdc3tParams {
4518 pub tr: f64,
4519 pub kp1: f64,
4520 pub ki1: f64,
4521 pub kp2: f64,
4522 pub ki2: f64,
4523 pub kp3: f64,
4524 pub ki3: f64,
4525 pub pmax: f64,
4526 pub pmin: f64,
4527 pub mbase: f64,
4528}
4529
4530// ---------------------------------------------------------------------------
4531// Phase 27: Generator / Load / Protection param structs
4532// ---------------------------------------------------------------------------
4533
4534/// REGCO1 — Grid-following converter generator (4 states).
4535#[derive(Debug, Clone, Serialize, Deserialize)]
4536pub struct Regco1Params {
4537 pub tr: f64,
4538 pub kp_v: f64,
4539 pub ki_v: f64,
4540 pub kp_i: f64,
4541 pub ki_i: f64,
4542 pub vmax: f64,
4543 pub vmin: f64,
4544 pub iqmax: f64,
4545 pub iqmin: f64,
4546 pub pmax: f64,
4547 pub pmin: f64,
4548 pub mbase: f64,
4549}
4550
4551/// GENSAL3 — Third-order salient-pole synchronous generator (3 dynamic states).
4552#[derive(Debug, Clone, Serialize, Deserialize)]
4553pub struct Gensal3Params {
4554 pub td0_prime: f64,
4555 pub h: f64,
4556 pub d: f64,
4557 pub xd: f64,
4558 pub xq: f64,
4559 pub xd_prime: f64,
4560 pub xl: f64,
4561 pub s1: f64,
4562 pub s12: f64,
4563}
4564
4565/// LCFB1 — Load compensator with frequency bias (2 states).
4566#[derive(Debug, Clone, Serialize, Deserialize)]
4567pub struct Lcfb1Params {
4568 pub tc: f64,
4569 pub tb: f64,
4570 pub kf: f64,
4571 pub pmax: f64,
4572 pub pmin: f64,
4573 pub mbase: f64,
4574}
4575
4576/// LDFRAL — Dynamic load frequency regulation (2 states).
4577#[derive(Debug, Clone, Serialize, Deserialize)]
4578pub struct LdfralParams {
4579 pub tc: f64,
4580 pub tb: f64,
4581 pub kf: f64,
4582 pub kp: f64,
4583 pub pmax: f64,
4584 pub pmin: f64,
4585 pub mbase: f64,
4586}
4587
4588/// FRQTPLT — Frequency relay trip (1 state + bool flag).
4589#[derive(Debug, Clone, Serialize, Deserialize)]
4590pub struct FrqtpltParams {
4591 pub tf: f64,
4592 pub fmin: f64,
4593 pub fmax: f64,
4594 pub p_trip: f64,
4595}
4596
4597/// LVSHBL — Low-voltage shunt block (1 state + bool flag).
4598#[derive(Debug, Clone, Serialize, Deserialize)]
4599pub struct LvshblParams {
4600 pub tv: f64,
4601 pub vmin: f64,
4602 pub p_block: f64,
4603}
4604
4605// ---------------------------------------------------------------------------
4606
4607/// UVLS1 — Under-Voltage Load Shedding relay (single stage, per-bus).
4608/// Multi-stage UVLS via multiple UVLS1 records at the same bus.
4609/// DYR: UVLS1 bus 'id' tv vmin t_delay p_shed v_reconnect t_reconnect /
4610#[derive(Debug, Clone, Serialize, Deserialize)]
4611pub struct Uvls1Params {
4612 /// Voltage measurement filter time constant (seconds).
4613 pub tv: f64,
4614 /// Undervoltage threshold (pu).
4615 pub vmin: f64,
4616 /// Trip delay after continuous undervoltage (seconds).
4617 pub t_delay: f64,
4618 /// Fraction of load to shed (0.0–1.0).
4619 pub p_shed: f64,
4620 /// Voltage threshold for reconnection (pu); 0.0 disables reconnection.
4621 pub v_reconnect: f64,
4622 /// Reconnection delay (seconds).
4623 pub t_reconnect: f64,
4624}
4625
4626// ---------------------------------------------------------------------------
4627
4628/// A `.dyr` record with an unrecognised model name — stored verbatim.
4629#[derive(Debug, Clone, Serialize, Deserialize)]
4630pub struct UnknownDyrRecord {
4631 /// Bus number extracted from the record (0 if the bus field was not numeric).
4632 pub bus: u32,
4633 /// Raw model name as read from the file.
4634 pub model_name: String,
4635 /// Machine ID string.
4636 pub machine_id: String,
4637 /// All numeric parameter tokens from the record.
4638 pub params: Vec<f64>,
4639}
4640
4641// ---------------------------------------------------------------------------
4642// Phase 28: REPCGFM_C1 / DERP / REGFM_D1 / WTDTA1 / WTARA1 / WTPTA1
4643// ---------------------------------------------------------------------------
4644
4645/// REPCGFM_C1 — GFM plant-level Volt/Var controller (3 states).
4646///
4647/// Plant-level companion to REGFM_C1. Integrating PI loops for voltage and
4648/// reactive power, plus a frequency droop state.
4649#[derive(Debug, Clone, Serialize, Deserialize)]
4650pub struct Repcgfmc1Params {
4651 pub kp_v: f64,
4652 pub ki_v: f64,
4653 pub vmax: f64,
4654 pub vmin: f64,
4655 pub kp_q: f64,
4656 pub ki_q: f64,
4657 pub qmax: f64,
4658 pub qmin: f64,
4659 pub tlag: f64,
4660 pub fdroop: f64,
4661 pub dbd1: f64,
4662 pub dbd2: f64,
4663}
4664
4665/// DERP — DER with Protection (2 states).
4666///
4667/// DER_A variant with explicit frequency and voltage protection relay
4668/// trip logic on top of the DERA inverter output.
4669#[derive(Debug, Clone, Serialize, Deserialize)]
4670pub struct DerpParams {
4671 pub x_eq: f64,
4672 pub trf: f64,
4673 pub imax: f64,
4674 pub trv: f64,
4675 /// PLL filter time constant (s).
4676 pub tpll: f64,
4677 /// Lower frequency trip threshold (pu).
4678 pub flow: f64,
4679 /// Upper frequency trip threshold (pu).
4680 pub fhigh: f64,
4681 /// Lower voltage trip threshold (pu).
4682 pub vlow: f64,
4683 /// Upper voltage trip threshold (pu).
4684 pub vhigh: f64,
4685 /// Protection trip time constant (s).
4686 pub trip: f64,
4687 /// Reconnect time constant (s).
4688 pub treconnect: f64,
4689}
4690
4691/// REGFM_D1 — WECC Sep-2025 hybrid GFM/GFL converter (8 states).
4692///
4693/// Droop-based voltage/frequency forming with current-limit handoff to GFL
4694/// mode. Structurally extends REGFM_C1 with 2 extra VOC + anti-windup states.
4695#[derive(Debug, Clone, Serialize, Deserialize)]
4696pub struct Regfmd1Params {
4697 pub rrv: f64,
4698 pub lrv: f64,
4699 pub kpv: f64,
4700 pub kiv: f64,
4701 pub kpg: f64,
4702 pub kig: f64,
4703 pub kdroop: f64,
4704 pub kvir: f64,
4705 pub kfir: f64,
4706 pub imax: f64,
4707 pub dpf: f64,
4708 pub dqf: f64,
4709 pub x_eq: f64,
4710 pub mbase: f64,
4711 /// PLL tracking filter time constant (s, default 0.02).
4712 pub tpll: f64,
4713 /// Voltage measurement filter time constant (s, default 0.02).
4714 pub tv: f64,
4715}
4716
4717/// WTDTA1 — Wind turbine two-mass drive-train (2 states).
4718///
4719/// ωr (rotor speed deviation) and θtwist (shaft twist angle).
4720/// Works alongside REGCA/WT3G2U generators.
4721#[derive(Debug, Clone, Serialize, Deserialize)]
4722pub struct Wtdta1Params {
4723 /// Inertia constant of the rotor (s).
4724 pub h: f64,
4725 /// Shaft damping coefficient (pu).
4726 pub dshaft: f64,
4727 /// Shaft stiffness coefficient (pu/rad).
4728 pub kshaft: f64,
4729 /// Second mass damping.
4730 pub d2: f64,
4731}
4732
4733/// WTARA1 — Wind turbine aerodynamic aggregation (2 states).
4734///
4735/// State: Paero (aerodynamic power), Pmech (mechanical power output).
4736/// Cp-lambda power curve simplified as first-order lag.
4737#[derive(Debug, Clone, Serialize, Deserialize)]
4738pub struct Wtara1Params {
4739 /// Aerodynamic power gain.
4740 pub ka: f64,
4741 /// Aerodynamic time constant (s).
4742 pub ta: f64,
4743 /// Mechanical power gain.
4744 pub km: f64,
4745 /// Mechanical time constant (s).
4746 pub tm: f64,
4747 /// Maximum power output (pu).
4748 pub pmax: f64,
4749 /// Minimum power output (pu).
4750 pub pmin: f64,
4751}
4752
4753/// WTPTA1 — Wind turbine pitch angle control (2 states).
4754///
4755/// States: θcmd (pitch command), θact (actual pitch, rate-limited servo).
4756#[derive(Debug, Clone, Serialize, Deserialize)]
4757pub struct Wtpta1Params {
4758 /// Proportional gain of pitch PI controller.
4759 pub kpp: f64,
4760 /// Integral gain of pitch PI controller.
4761 pub kip: f64,
4762 /// Maximum pitch angle (deg).
4763 pub theta_max: f64,
4764 /// Minimum pitch angle (deg).
4765 pub theta_min: f64,
4766 /// Maximum pitch rate (deg/s).
4767 pub rate_max: f64,
4768 /// Minimum pitch rate (deg/s) — typically negative.
4769 pub rate_min: f64,
4770 /// Servo time constant (s).
4771 pub te: f64,
4772 /// Pitch-to-power gain (pu MW per deg).
4773 pub kp_pitch: f64,
4774}
4775
4776/// Cp(λ,β) lookup table for full aerodynamic wind turbine models.
4777///
4778/// Power coefficient Cp is tabulated as a function of tip-speed ratio λ
4779/// (lambda) and blade pitch angle β (beta). Values are stored row-major
4780/// in `cp_values[i_lambda * n_beta + i_beta]`.
4781#[derive(Debug, Clone, Serialize, Deserialize)]
4782pub struct CpTable {
4783 /// Tip-speed ratio breakpoints (dimensionless).
4784 pub lambda_bp: Vec<f64>,
4785 /// Pitch angle breakpoints (degrees).
4786 pub beta_bp: Vec<f64>,
4787 /// Cp values, row-major: `[n_lambda × n_beta]`.
4788 pub cp_values: Vec<f64>,
4789}
4790
4791impl CpTable {
4792 /// Bilinear interpolation of Cp at given (lambda, beta).
4793 pub fn interpolate(&self, lambda: f64, beta: f64) -> f64 {
4794 let (il, il1, fl) = Self::find_bracket(&self.lambda_bp, lambda);
4795 let (ib, ib1, fb) = Self::find_bracket(&self.beta_bp, beta);
4796 let nb = self.beta_bp.len();
4797
4798 let c00 = self.cp_values[il * nb + ib];
4799 let c01 = self.cp_values[il * nb + ib1];
4800 let c10 = self.cp_values[il1 * nb + ib];
4801 let c11 = self.cp_values[il1 * nb + ib1];
4802
4803 let c0 = c00 + fb * (c01 - c00);
4804 let c1 = c10 + fb * (c11 - c10);
4805 (c0 + fl * (c1 - c0)).max(0.0)
4806 }
4807
4808 /// NREL 5-MW reference turbine Cp table (public domain data).
4809 ///
4810 /// Simplified 8×6 table covering λ ∈ [2, 16] and β ∈ [0, 25]°.
4811 pub fn nrel_5mw() -> Self {
4812 let lambda_bp = vec![2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0];
4813 let beta_bp = vec![0.0, 5.0, 10.0, 15.0, 20.0, 25.0];
4814 #[rustfmt::skip]
4815 let cp_values = vec![
4816 // β=0 β=5 β=10 β=15 β=20 β=25
4817 0.10, 0.06, 0.02, 0.01, 0.00, 0.00, // λ=2
4818 0.30, 0.20, 0.10, 0.04, 0.01, 0.00, // λ=4
4819 0.42, 0.32, 0.18, 0.08, 0.03, 0.01, // λ=6
4820 0.48, 0.38, 0.22, 0.11, 0.04, 0.01, // λ=8
4821 0.44, 0.34, 0.20, 0.10, 0.04, 0.01, // λ=10
4822 0.35, 0.26, 0.15, 0.07, 0.03, 0.01, // λ=12
4823 0.22, 0.16, 0.09, 0.04, 0.02, 0.01, // λ=14
4824 0.10, 0.07, 0.04, 0.02, 0.01, 0.00, // λ=16
4825 ];
4826 Self {
4827 lambda_bp,
4828 beta_bp,
4829 cp_values,
4830 }
4831 }
4832
4833 /// Find bracketing indices and interpolation fraction.
4834 fn find_bracket(bp: &[f64], val: f64) -> (usize, usize, f64) {
4835 if bp.len() < 2 {
4836 return (0, 0, 0.0);
4837 }
4838 if val <= bp[0] {
4839 return (0, 0, 0.0);
4840 }
4841 if val >= bp[bp.len() - 1] {
4842 let n = bp.len() - 1;
4843 return (n, n, 0.0);
4844 }
4845 // Binary search for bracket.
4846 let pos = bp.partition_point(|&x| x <= val);
4847 let i = if pos > 0 { pos - 1 } else { 0 };
4848 let i1 = (i + 1).min(bp.len() - 1);
4849 let span = bp[i1] - bp[i];
4850 let frac = if span.abs() > 1e-15 {
4851 (val - bp[i]) / span
4852 } else {
4853 0.0
4854 };
4855 (i, i1, frac)
4856 }
4857}
4858
4859/// WTAERO — Full aerodynamic wind turbine model with Cp(λ,β) table.
4860///
4861/// Computes aerodynamic power from wind speed, rotor speed, and pitch angle
4862/// using a tabulated power coefficient surface. Optionally models the
4863/// two-mass drive train (rotor + generator) with shaft flexibility.
4864///
4865/// States (single-mass): p_aero (aerodynamic power, filtered).
4866/// States (two-mass): omega_r (rotor speed), theta_tw (shaft twist), p_aero.
4867#[derive(Debug, Clone, Serialize, Deserialize)]
4868pub struct WtaeroParams {
4869 /// Air density (kg/m³). Default: 1.225 (ISA sea level).
4870 pub rho: f64,
4871 /// Rotor radius (m).
4872 pub r_rotor: f64,
4873 /// Gear ratio (generator_speed / rotor_speed).
4874 pub gear_ratio: f64,
4875 /// Cp(λ,β) lookup table.
4876 pub cp_table: CpTable,
4877 /// Base wind speed for steady-state initialization (m/s).
4878 pub v_wind_base: f64,
4879 /// Generator MVA base (for per-unit conversion).
4880 pub mbase_mw: f64,
4881 /// Two-mass rotor inertia (s). None = single-mass.
4882 pub h_rotor: Option<f64>,
4883 /// Shaft stiffness (pu/rad). Required for two-mass.
4884 pub k_shaft: Option<f64>,
4885 /// Shaft damping (pu). Required for two-mass.
4886 pub d_shaft: Option<f64>,
4887}
4888
4889// ---------------------------------------------------------------------------
4890// Wave 34: New generator, governor, load, FACTS param structs
4891// ---------------------------------------------------------------------------
4892
4893/// IEESGO — IEEE Standard Governor (simplified 5-state steam turbine governor).
4894///
4895/// PSS/E params: `T1 T2 T3 T4 T5 T6 K1 K2 K3 PMAX PMIN`
4896///
4897/// T1=lead TC, T2=lag TC (lead-lag), T3=valve TC,
4898/// T4=HP TC, T5=reheat TC, T6=LP TC; K1+K2+K3=1 (HP/IP/LP fractions).
4899#[derive(Debug, Clone, Serialize, Deserialize)]
4900pub struct IeesgoParams {
4901 pub t1: f64,
4902 pub t2: f64,
4903 pub t3: f64,
4904 pub t4: f64,
4905 pub t5: f64,
4906 pub t6: f64,
4907 pub k1: f64,
4908 pub k2: f64,
4909 pub k3: f64,
4910 pub pmax: f64,
4911 pub pmin: f64,
4912}
4913
4914/// WTTQA1 — WECC Type 2 Wind Torque Controller (2 states, governor slot).
4915///
4916/// PSS/E params: `Kp Ki Tp Pmax Pmin`
4917#[derive(Debug, Clone, Serialize, Deserialize)]
4918pub struct Wttqa1Params {
4919 pub kp: f64,
4920 pub ki: f64,
4921 pub tp: f64,
4922 pub pmax: f64,
4923 pub pmin: f64,
4924 /// Torque mode flag: 0 = speed error mode, 1 = power error mode.
4925 pub tflag: i32,
4926 /// Speed reference filter time constant (s).
4927 pub twref: f64,
4928 /// Maximum torque (pu).
4929 pub temax: f64,
4930 /// Minimum torque (pu).
4931 pub temin: f64,
4932 /// Speed-power lookup breakpoints: (power, speed_ref) pairs.
4933 /// Piecewise linear mapping from measured power to speed reference.
4934 pub spl: [(f64, f64); 4],
4935}
4936
4937/// CIM6 — 6th-order induction motor (extends CIM5 with q-axis transient).
4938///
4939/// Uses same 3-state structure as CIM5 (slip, ed_prime, eq_prime) but adds
4940/// `tq0p` and `xq_prime` for q-axis transient dynamics.
4941///
4942/// PSS/E params: `RA XS XM XR1 XR2 RR1 RR2 [H E1 S1 E2 S2 MBASE TQ0P XQP]`
4943#[derive(Debug, Clone, Serialize, Deserialize)]
4944pub struct Cim6Params {
4945 pub ra: f64,
4946 pub xs: f64,
4947 pub xm: f64,
4948 pub xr1: f64,
4949 pub xr2: f64,
4950 pub rr1: f64,
4951 pub rr2: f64,
4952 pub h: f64,
4953 pub e1: f64,
4954 pub s1: f64,
4955 pub e2: f64,
4956 pub s2: f64,
4957 pub mbase: f64,
4958 pub tq0p: f64,
4959 pub xq_prime: f64,
4960}
4961
4962/// EXTL — External Load (simplified composite 2-state load model).
4963///
4964/// Models voltage/frequency-dependent load with first-order filters.
4965///
4966/// PSS/E params: `Tp Tq Kpv Kqv Kpf Kqf mbase lfac`
4967#[derive(Debug, Clone, Serialize, Deserialize)]
4968pub struct ExtlParams {
4969 pub tp: f64,
4970 pub tq: f64,
4971 pub kpv: f64,
4972 pub kqv: f64,
4973 pub kpf: f64,
4974 pub kqf: f64,
4975 pub mbase: f64,
4976 pub lfac: f64,
4977}
4978
4979/// SVSMO1 — WECC Generic SVC voltage regulator (1-state, FACTS slot).
4980///
4981/// Simple first-order SVC model. PSS/E params: `Tr K Ta Bmin Bmax`
4982#[derive(Debug, Clone, Serialize, Deserialize)]
4983pub struct Svsmo1Params {
4984 pub tr: f64,
4985 pub k: f64,
4986 pub ta: f64,
4987 pub b_min: f64,
4988 pub b_max: f64,
4989}
4990
4991/// SVSMO2 — WECC Generic STATCOM (1-state, FACTS slot).
4992///
4993/// Similar to CSTCON. PSS/E params: `Tr K Ta IqMin IqMax`
4994#[derive(Debug, Clone, Serialize, Deserialize)]
4995pub struct Svsmo2Params {
4996 pub tr: f64,
4997 pub k: f64,
4998 pub ta: f64,
4999 pub iq_min: f64,
5000 pub iq_max: f64,
5001}
5002
5003/// SVSMO3 — WECC Advanced SVC (2-state: b_svc + vr, FACTS slot).
5004///
5005/// Lead-lag voltage regulator driving susceptance.
5006/// PSS/E params: `Tr Ka Ta Tb Bmin Bmax`
5007#[derive(Debug, Clone, Serialize, Deserialize)]
5008pub struct Svsmo3Params {
5009 pub tr: f64,
5010 pub ka: f64,
5011 pub ta: f64,
5012 pub tb: f64,
5013 pub b_min: f64,
5014 pub b_max: f64,
5015}
5016
5017// ---------------------------------------------------------------------------
5018// Wave 35: New param structs
5019// ---------------------------------------------------------------------------
5020
5021// --- Generator protection relays -------------------------------------------
5022
5023/// VTGTPAT / VTGDCAT — Voltage-Time Generator Protection Trip params.
5024#[derive(Debug, Clone, Serialize, Deserialize)]
5025pub struct VtgtpatParams {
5026 /// Voltage filter time constant (s).
5027 pub tv: f64,
5028 /// Trip voltage threshold (pu, below which generator trips).
5029 pub vtrip: f64,
5030 /// Reset voltage threshold (pu, above which relay resets).
5031 pub vreset: f64,
5032}
5033
5034/// FRQTPAT / FRQDCAT — Frequency-Time Generator Protection Trip params.
5035#[derive(Debug, Clone, Serialize, Deserialize)]
5036pub struct FrqtpatParams {
5037 /// Frequency filter time constant (s).
5038 pub tf: f64,
5039 /// High-frequency trip threshold (pu, above which generator trips).
5040 pub ftrip_hi: f64,
5041 /// Low-frequency trip threshold (pu, below which generator trips).
5042 pub ftrip_lo: f64,
5043 /// Reset frequency threshold (pu).
5044 pub freset: f64,
5045}
5046
5047// --- Hydro governors -------------------------------------------------------
5048
5049/// HYGOV4 — Hydro Governor with Surge Tank (5 states).
5050///
5051/// PSS/E params: `R TF TG TR HDAM TW QNL AT DG GMAX GMIN TS KS PMAX PMIN`
5052#[derive(Debug, Clone, Serialize, Deserialize)]
5053pub struct Hygov4Params {
5054 /// Governor time constant (pilot valve, s).
5055 pub tr: f64,
5056 /// Pilot filter time constant (s).
5057 pub tf: f64,
5058 /// Turbine damping (pu).
5059 pub dturb: f64,
5060 /// Head at zero flow (pu).
5061 pub hdam: f64,
5062 /// Penstock water time constant (s).
5063 pub tw: f64,
5064 /// No-load flow at nominal head (pu).
5065 pub qnl: f64,
5066 /// Turbine gain (pu).
5067 pub at: f64,
5068 /// Governor servo gain (pu/pu).
5069 pub dg: f64,
5070 /// Maximum gate position (pu).
5071 pub gmax: f64,
5072 /// Minimum gate position (pu).
5073 pub gmin: f64,
5074 /// Surge tank time constant (s).
5075 pub ts: f64,
5076 /// Surge tank orifice loss coefficient (pu).
5077 pub ks: f64,
5078 /// Maximum power output (pu).
5079 pub pmax: f64,
5080 /// Minimum power output (pu).
5081 pub pmin: f64,
5082}
5083
5084/// WEHGOV — WECC Enhanced Hydro Governor (4 states).
5085///
5086/// PSS/E params: `R TR TF TG TW AT DTURB QNL GMAX GMIN DBD1 DBD2 PMAX PMIN`
5087#[derive(Debug, Clone, Serialize, Deserialize)]
5088pub struct WehgovParams {
5089 /// Droop (pu).
5090 pub r: f64,
5091 /// Governor filter time constant (s).
5092 pub tr: f64,
5093 /// Pilot filter time constant (s).
5094 pub tf: f64,
5095 /// Gate servo time constant (s).
5096 pub tg: f64,
5097 /// Penstock water time constant (s).
5098 pub tw: f64,
5099 /// Turbine gain (pu).
5100 pub at: f64,
5101 /// Turbine damping (pu).
5102 pub dturb: f64,
5103 /// No-load flow (pu).
5104 pub qnl: f64,
5105 /// Maximum gate position (pu).
5106 pub gmax: f64,
5107 /// Minimum gate position (pu).
5108 pub gmin: f64,
5109 /// Speed deadband lower limit (pu, negative).
5110 pub dbd1: f64,
5111 /// Speed deadband upper limit (pu, positive).
5112 pub dbd2: f64,
5113 /// Maximum power output (pu).
5114 pub pmax: f64,
5115 /// Minimum power output (pu).
5116 pub pmin: f64,
5117}
5118
5119/// IEEEG3 — IEEE Type G3 Hydro Governor (3 states).
5120///
5121/// PSS/E params: `TG TP UO UC PMAX PMIN TW AT DTURB QNL`
5122#[derive(Debug, Clone, Serialize, Deserialize)]
5123pub struct Ieeeg3Params {
5124 /// Gate servo time constant (s).
5125 pub tg: f64,
5126 /// Pilot valve time constant (s).
5127 pub tp: f64,
5128 /// Maximum gate opening rate (pu/s).
5129 pub uo: f64,
5130 /// Maximum gate closing rate (pu/s, negative in PSS/E).
5131 pub uc: f64,
5132 /// Maximum power output (pu).
5133 pub pmax: f64,
5134 /// Minimum power output (pu).
5135 pub pmin: f64,
5136 /// Water time constant (s).
5137 pub tw: f64,
5138 /// Turbine gain (pu).
5139 pub at: f64,
5140 /// Turbine damping (pu).
5141 pub dturb: f64,
5142 /// No-load flow (pu).
5143 pub qnl: f64,
5144}
5145
5146/// IEEEG4 — IEEE Type G4 Hydro Governor (3 states, lead-lag form).
5147///
5148/// PSS/E params: `T1 T2 T3 KI PMAX PMIN TW AT DTURB QNL`
5149#[derive(Debug, Clone, Serialize, Deserialize)]
5150pub struct Ieeeg4Params {
5151 /// Lead-lag time constant 1 (s).
5152 pub t1: f64,
5153 /// Lead-lag time constant 2 (s).
5154 pub t2: f64,
5155 /// Lead-lag time constant 3 (s).
5156 pub t3: f64,
5157 /// Integral gain (pu/pu/s).
5158 pub ki: f64,
5159 /// Maximum power output (pu).
5160 pub pmax: f64,
5161 /// Minimum power output (pu).
5162 pub pmin: f64,
5163 /// Water time constant (s).
5164 pub tw: f64,
5165 /// Turbine gain (pu).
5166 pub at: f64,
5167 /// Turbine damping (pu).
5168 pub dturb: f64,
5169 /// No-load flow (pu).
5170 pub qnl: f64,
5171}
5172
5173// --- IEEE 421.5-2016 exciters (C-series) -----------------------------------
5174
5175/// ESAC7C — IEEE 421.5-2016 AC7C exciter params (6 states).
5176///
5177/// Structurally identical to ESAC7B; used as a C-series alias.
5178/// PSS/E params same as ESAC7B.
5179#[derive(Debug, Clone, Serialize, Deserialize)]
5180pub struct Esac7cParams {
5181 pub tr: f64,
5182 pub kpr: f64,
5183 pub kir: f64,
5184 pub kdr: f64,
5185 pub tdr: f64,
5186 pub vrmax: f64,
5187 pub vrmin: f64,
5188 pub ka: f64,
5189 pub ta: f64,
5190 pub kp: f64,
5191 pub kl: f64,
5192 pub te: f64,
5193 pub ke: f64,
5194 pub vfemax: f64,
5195 pub vemin: f64,
5196 pub e1: f64,
5197 pub se1: f64,
5198 pub e2: f64,
5199 pub se2: f64,
5200}
5201
5202/// ESDC4C — IEEE 421.5-2016 DC4C exciter params (3 states).
5203///
5204/// PSS/E params: `TR KA TA KPR KIR KDR TDR VRMAX VRMIN KE TE KF TF E1 SE1 E2 SE2`
5205#[derive(Debug, Clone, Serialize, Deserialize)]
5206pub struct Esdc4cParams {
5207 pub tr: f64,
5208 pub ka: f64,
5209 pub ta: f64,
5210 pub kpr: f64,
5211 pub kir: f64,
5212 pub kdr: f64,
5213 pub tdr: f64,
5214 pub vrmax: f64,
5215 pub vrmin: f64,
5216 pub ke: f64,
5217 pub te: f64,
5218 pub kf: f64,
5219 pub tf: f64,
5220 pub e1: f64,
5221 pub se1: f64,
5222 pub e2: f64,
5223 pub se2: f64,
5224}
5225
5226// --- IEEE 421.5-2016 PSS (C-series) ----------------------------------------
5227
5228/// PSS7C — IEEE 421.5-2016 multi-band PSS (6 states).
5229///
5230/// Three frequency bands (low / intermediate / high), each with a washout
5231/// filter and a lead-lag compensator. Output is the gain-weighted sum of
5232/// all three bands, clamped to `[vstmin, vstmax]`.
5233///
5234/// DYR params (extended): `KL TWL T1L T2L KI TWI T1I T2I KH TWH T1H T2H VSTMAX VSTMIN`
5235///
5236/// Legacy 9-param form (`KSS TW1 TW2 T1 T2 T3 T4 VSMAX VSMIN`) is still
5237/// accepted — the old fields are mapped to the intermediate band and the
5238/// low/high bands default to zero gain.
5239#[derive(Debug, Clone, Serialize, Deserialize)]
5240pub struct Pss7cParams {
5241 // --- legacy fields (kept for DYR round-trip / serde compat) -------------
5242 /// Legacy overall gain — mapped to intermediate band if per-band gains
5243 /// are all zero.
5244 #[serde(default)]
5245 pub kss: f64,
5246 /// Legacy washout time constant 1 (s).
5247 #[serde(default)]
5248 pub tw1: f64,
5249 /// Legacy washout time constant 2 (s).
5250 #[serde(default)]
5251 pub tw2: f64,
5252 /// Legacy lead time constant 1 (s).
5253 #[serde(default)]
5254 pub t1: f64,
5255 /// Legacy lag time constant 1 (s).
5256 #[serde(default)]
5257 pub t2: f64,
5258 /// Legacy lead time constant 2 (s).
5259 #[serde(default)]
5260 pub t3: f64,
5261 /// Legacy lag time constant 2 (s).
5262 #[serde(default)]
5263 pub t4: f64,
5264 /// Maximum PSS output (pu) — legacy alias for `vstmax`.
5265 #[serde(default = "default_vsmax")]
5266 pub vsmax: f64,
5267 /// Minimum PSS output (pu) — legacy alias for `vstmin`.
5268 #[serde(default = "default_vsmin")]
5269 pub vsmin: f64,
5270
5271 // --- per-band parameters (multi-band PSS) ------------------------------
5272 /// Low-frequency band gain (pu).
5273 #[serde(default)]
5274 pub kl: f64,
5275 /// Low-frequency washout time constant (s).
5276 #[serde(default = "default_tw")]
5277 pub tw_l: f64,
5278 /// Low-frequency lead time constant (s).
5279 #[serde(default)]
5280 pub t1_l: f64,
5281 /// Low-frequency lag time constant (s).
5282 #[serde(default = "default_tlag")]
5283 pub t2_l: f64,
5284
5285 /// Intermediate-frequency band gain (pu).
5286 #[serde(default)]
5287 pub ki: f64,
5288 /// Intermediate-frequency washout time constant (s).
5289 #[serde(default = "default_tw")]
5290 pub tw_i: f64,
5291 /// Intermediate-frequency lead time constant (s).
5292 #[serde(default)]
5293 pub t1_i: f64,
5294 /// Intermediate-frequency lag time constant (s).
5295 #[serde(default = "default_tlag")]
5296 pub t2_i: f64,
5297
5298 /// High-frequency band gain (pu).
5299 #[serde(default)]
5300 pub kh: f64,
5301 /// High-frequency washout time constant (s).
5302 #[serde(default = "default_tw")]
5303 pub tw_h: f64,
5304 /// High-frequency lead time constant (s).
5305 #[serde(default)]
5306 pub t1_h: f64,
5307 /// High-frequency lag time constant (s).
5308 #[serde(default = "default_tlag")]
5309 pub t2_h: f64,
5310
5311 /// Multi-band maximum PSS output (pu).
5312 #[serde(default = "default_vsmax")]
5313 pub vstmax: f64,
5314 /// Multi-band minimum PSS output (pu).
5315 #[serde(default = "default_vsmin")]
5316 pub vstmin: f64,
5317}
5318
5319fn default_vsmax() -> f64 {
5320 0.1
5321}
5322fn default_vsmin() -> f64 {
5323 -0.1
5324}
5325fn default_tw() -> f64 {
5326 10.0
5327}
5328fn default_tlag() -> f64 {
5329 0.04
5330}
5331
5332impl Pss7cParams {
5333 /// Effective per-band parameters. When the new per-band gains are all
5334 /// zero **and** `kss != 0`, fall back to the legacy single-band mapping
5335 /// (intermediate band only).
5336 pub fn effective_bands(&self) -> Pss7cBands {
5337 if self.kl == 0.0 && self.ki == 0.0 && self.kh == 0.0 && self.kss != 0.0 {
5338 // Legacy mode: map kss → intermediate band.
5339 Pss7cBands {
5340 kl: 0.0,
5341 tw_l: self.tw1,
5342 t1_l: 0.0,
5343 t2_l: 0.04,
5344 ki: self.kss,
5345 tw_i: self.tw1,
5346 t1_i: self.t1,
5347 t2_i: self.t2,
5348 kh: 0.0,
5349 tw_h: self.tw2,
5350 t1_h: 0.0,
5351 t2_h: 0.04,
5352 vstmax: self.vsmax,
5353 vstmin: self.vsmin,
5354 }
5355 } else {
5356 Pss7cBands {
5357 kl: self.kl,
5358 tw_l: self.tw_l,
5359 t1_l: self.t1_l,
5360 t2_l: self.t2_l,
5361 ki: self.ki,
5362 tw_i: self.tw_i,
5363 t1_i: self.t1_i,
5364 t2_i: self.t2_i,
5365 kh: self.kh,
5366 tw_h: self.tw_h,
5367 t1_h: self.t1_h,
5368 t2_h: self.t2_h,
5369 vstmax: self.vstmax,
5370 vstmin: self.vstmin,
5371 }
5372 }
5373 }
5374}
5375
5376/// Resolved per-band parameters for PSS7C evaluation.
5377#[derive(Debug, Clone)]
5378pub struct Pss7cBands {
5379 pub kl: f64,
5380 pub tw_l: f64,
5381 pub t1_l: f64,
5382 pub t2_l: f64,
5383 pub ki: f64,
5384 pub tw_i: f64,
5385 pub t1_i: f64,
5386 pub t2_i: f64,
5387 pub kh: f64,
5388 pub tw_h: f64,
5389 pub t1_h: f64,
5390 pub t2_h: f64,
5391 pub vstmax: f64,
5392 pub vstmin: f64,
5393}
5394
5395// ---------------------------------------------------------------------------
5396// Wave 36: New governor, generator, exciter, and load model structs
5397// ---------------------------------------------------------------------------
5398
5399// --- Combined Cycle Governors ---
5400
5401/// GOVCT1 — Single-shaft combined cycle turbine governor (common in ERCOT/WECC).
5402///
5403/// PSS/E params: `R T1 VMAX VMIN T2 T3 K1 K2 K3 T4 T5 T6 K7 K8 PMAX PMIN [TD]`
5404#[derive(Debug, Clone, Serialize, Deserialize)]
5405pub struct Govct1Params {
5406 /// Speed regulation (droop, pu).
5407 pub r: f64,
5408 /// Governor time constant (s).
5409 pub t1: f64,
5410 /// Maximum valve position (pu).
5411 pub vmax: f64,
5412 /// Minimum valve position (pu).
5413 pub vmin: f64,
5414 /// Lead time constant (s).
5415 pub t2: f64,
5416 /// Lag time constant (s).
5417 pub t3: f64,
5418 /// HP turbine fraction.
5419 pub k1: f64,
5420 /// LP1 turbine fraction.
5421 pub k2: f64,
5422 /// LP2 turbine fraction (= 1-k1-k2).
5423 pub k3: f64,
5424 /// HP turbine time constant (s).
5425 pub t4: f64,
5426 /// LP1 time constant (s).
5427 pub t5: f64,
5428 /// LP2 time constant (s).
5429 pub t6: f64,
5430 /// Gas turbine coefficient 1.
5431 pub k7: f64,
5432 /// Gas turbine coefficient 2.
5433 pub k8: f64,
5434 /// Maximum power output (pu).
5435 pub pmax: f64,
5436 /// Minimum power output (pu).
5437 pub pmin: f64,
5438 /// Governor deadband (optional, default 0).
5439 #[serde(default)]
5440 pub td: f64,
5441}
5442
5443/// GOVCT2 — Two-shaft combined cycle gas turbine governor (7 states).
5444///
5445/// Models a gas turbine (GT) driving one generator plus a steam turbine (ST)
5446/// driven by heat recovery from the GT exhaust via an HRSG.
5447///
5448/// PSS/E params: `R T1 VMAX VMIN T2 T3 K1 K2 K3 T4 T5 T6 K7 K8 PMAX PMIN [TD T_HRSG K_ST T_ST]`
5449///
5450/// States x1–x5 are the gas turbine (identical to GOVCT1).
5451/// State x_hrsg captures HRSG steam generation dynamics.
5452/// State x_st captures steam turbine output dynamics.
5453/// Total Pm = Pm_gt + x_st.
5454#[derive(Debug, Clone, Serialize, Deserialize)]
5455pub struct Govct2Params {
5456 // --- Gas turbine fields (same as Govct1Params) ---
5457 /// Speed regulation (droop, pu).
5458 pub r: f64,
5459 /// Governor time constant (s).
5460 pub t1: f64,
5461 /// Maximum valve position (pu).
5462 pub vmax: f64,
5463 /// Minimum valve position (pu).
5464 pub vmin: f64,
5465 /// Lead time constant (s).
5466 pub t2: f64,
5467 /// Lag time constant (s).
5468 pub t3: f64,
5469 /// HP turbine fraction.
5470 pub k1: f64,
5471 /// LP1 turbine fraction.
5472 pub k2: f64,
5473 /// LP2 turbine fraction (= 1-k1-k2).
5474 pub k3: f64,
5475 /// HP turbine time constant (s).
5476 pub t4: f64,
5477 /// LP1 time constant (s).
5478 pub t5: f64,
5479 /// LP2 time constant (s).
5480 pub t6: f64,
5481 /// Gas turbine coefficient 1.
5482 pub k7: f64,
5483 /// Gas turbine coefficient 2.
5484 pub k8: f64,
5485 /// Maximum power output (pu).
5486 pub pmax: f64,
5487 /// Minimum power output (pu).
5488 pub pmin: f64,
5489 /// Governor deadband (optional, default 0).
5490 #[serde(default)]
5491 pub td: f64,
5492 // --- Steam turbine / HRSG fields (GOVCT2-specific) ---
5493 /// HRSG time constant (s) — typically 60-120s.
5494 pub t_hrsg: f64,
5495 /// Steam-to-gas power ratio — typically 0.33-0.5.
5496 pub k_st: f64,
5497 /// Steam turbine lag time constant (s) — typically 5-15s.
5498 pub t_st: f64,
5499}
5500
5501// --- Advanced Steam Governors ---
5502
5503/// TGOV3 — TGOV1 variant with two-reheat steam turbine (3 states).
5504///
5505/// PSS/E params: `R T1 VMAX VMIN T2 T3 DT KD`
5506#[derive(Debug, Clone, Serialize, Deserialize)]
5507pub struct Tgov3Params {
5508 /// Speed regulation (droop, pu).
5509 pub r: f64,
5510 /// Governor time constant (s).
5511 pub t1: f64,
5512 /// Maximum valve position (pu).
5513 pub vmax: f64,
5514 /// Minimum valve position (pu).
5515 pub vmin: f64,
5516 /// First reheat time constant (s).
5517 pub t2: f64,
5518 /// Second reheat time constant (s).
5519 pub t3: f64,
5520 /// Turbine damping (pu).
5521 pub dt: f64,
5522 /// Derivative gain.
5523 pub kd: f64,
5524}
5525
5526// --- Legacy Wind Generator Params ---
5527
5528/// WT1G1 / WT2G1 — Type 1/2 induction-machine wind generator (3rd-order model).
5529///
5530/// PSS/E DYR record: `H D RA X_EQ IMAX`
5531///
5532/// WT1G1 is a squirrel-cage induction generator (Type 1) directly coupled to
5533/// the grid with no power electronics. WT2G1 adds external rotor resistance
5534/// control via the WT2E1 governor.
5535///
5536/// The 3rd-order model tracks transient EMFs (E'_d, E'_q) and rotor slip:
5537/// ```text
5538/// dE'_q/dt = -s·ω_s·E'_d - (E'_q + (X - X')·I_d) / T'_0
5539/// dE'_d/dt = s·ω_s·E'_q - (E'_d - (X - X')·I_q) / T'_0
5540/// ds/dt = (T_e - T_m) / (2H)
5541/// ```
5542///
5543/// # Decomposition from PSS/E X_EQ
5544///
5545/// PSS/E provides only the transient reactance X' = X_EQ. The full IM circuit
5546/// parameters (Xs, Xm, Xr, Rr) are derived using standard decomposition defaults:
5547/// - Xs = 0.10 · X' (stator leakage)
5548/// - Xm = 3.0 (magnetizing reactance)
5549/// - Xr = Xs (rotor leakage ≈ stator leakage)
5550/// - Rr = 0.01 (rotor resistance)
5551/// - X = Xs + Xm (open-circuit reactance)
5552/// - T'_0 = (Xm + Xr) / (ω_s · Rr)
5553#[derive(Debug, Clone, Serialize, Deserialize)]
5554pub struct Wt1g1Params {
5555 /// Inertia constant (s).
5556 pub h: f64,
5557 /// Damping coefficient (pu).
5558 pub d: f64,
5559 /// Stator resistance Rs (pu). PSS/E field `RA`.
5560 pub ra: f64,
5561 /// Transient reactance X' (pu). PSS/E field `X_EQ`.
5562 /// Equal to Xs + Xm·Xr/(Xm+Xr).
5563 pub x_eq: f64,
5564 /// Current limit (pu).
5565 pub imax: f64,
5566 /// Stator leakage reactance (pu). Derived: 0.10 × X_EQ.
5567 pub xs: f64,
5568 /// Magnetizing reactance (pu). Default 3.0.
5569 pub xm: f64,
5570 /// Rotor leakage reactance (pu). Derived ≈ Xs.
5571 pub xr: f64,
5572 /// Rotor resistance (pu). Default 0.01.
5573 pub rr: f64,
5574}
5575
5576/// WT2E1 — Type 2 wind electrical controller (governor slot).
5577///
5578/// PSS/E params: `KP KI PMAX PMIN TE`
5579#[derive(Debug, Clone, Serialize, Deserialize)]
5580pub struct Wt2e1Params {
5581 /// Proportional gain.
5582 pub kp: f64,
5583 /// Integral gain.
5584 pub ki: f64,
5585 /// Maximum active power (pu).
5586 pub pmax: f64,
5587 /// Minimum active power (pu).
5588 pub pmin: f64,
5589 /// Electrical control time constant (s).
5590 pub te: f64,
5591}
5592
5593/// DISTR1 — Distance relay (line protection, attaches to bus in load slot).
5594///
5595/// PSS/E params: `Z1 Z2 T1 T2 MBASE LFAC`
5596///
5597/// Extended with Zone 3, Mho circle angle, protected branch info, and
5598/// measurement filter time constant for proper impedance-measuring relay.
5599#[derive(Debug, Clone, Serialize, Deserialize)]
5600pub struct Distr1Params {
5601 /// Zone 1 impedance magnitude (pu).
5602 pub z1: f64,
5603 /// Zone 2 impedance magnitude (pu).
5604 pub z2: f64,
5605 /// Zone 3 impedance magnitude (pu). Default: 1.5 × z2.
5606 pub z3: f64,
5607 /// Zone 1 trip delay (s). Typically ~0 (instantaneous).
5608 pub t1: f64,
5609 /// Zone 2 trip delay (s). Typically 0.3–0.5 s.
5610 pub t2: f64,
5611 /// Zone 3 trip delay (s). Typically 0.8–1.2 s.
5612 pub t3: f64,
5613 /// Mho circle reach angle (degrees). Typical: 60–85°.
5614 pub reach_angle_deg: f64,
5615 /// MVA base of protected element.
5616 pub mbase: f64,
5617 /// Load fraction this relay monitors.
5618 pub lfac: f64,
5619 /// From-bus of the protected branch.
5620 pub branch_from: u32,
5621 /// To-bus of the protected branch.
5622 pub branch_to: u32,
5623 /// Protected branch resistance (pu).
5624 pub branch_r: f64,
5625 /// Protected branch reactance (pu).
5626 pub branch_x: f64,
5627 /// Measurement filter time constant (s). Default: 0.02 s (1.2 cycles).
5628 pub tf: f64,
5629}
5630
5631/// BFR50 — Breaker failure relay (ANSI 50BF).
5632///
5633/// DYR params: `T_BFR I_SUP BRANCH_IDX`
5634///
5635/// Monitors the breaker on the protected branch. When a trip command is active
5636/// and current exceeds the supervision threshold for `t_bfr` seconds, the BFR
5637/// issues a backup trip to adjacent generators.
5638#[derive(Debug, Clone, Serialize, Deserialize)]
5639pub struct Bfr50Params {
5640 /// BFR timer duration (s). Typical: 5-10 cycles (83-167ms @ 60Hz).
5641 pub t_bfr: f64,
5642 /// Current supervision threshold (pu). BFR only active if I > this.
5643 pub i_sup: f64,
5644 /// Internal branch index of the monitored breaker.
5645 pub branch_idx: usize,
5646}
5647
5648// ---------------------------------------------------------------------------
5649// Wave 7 (B10): Additional protection relay parameter types
5650// ---------------------------------------------------------------------------
5651
5652/// 87T — Transformer differential relay.
5653///
5654/// Compares high-side and low-side currents of a transformer. Trips when the
5655/// differential current `|I_H - I_L/ratio|` exceeds the restraint characteristic
5656/// `slope × I_restraint + I_pickup`.
5657///
5658/// DYR params: `SLOPE1 SLOPE2 I_PICKUP HARMONIC_RESTRAINT FROM_BUS TO_BUS CKT TURNS_RATIO TF`
5659#[derive(Debug, Clone, Serialize, Deserialize)]
5660pub struct TransDiff87Params {
5661 /// Slope 1 of restraint characteristic (typical 0.2–0.3).
5662 pub slope1: f64,
5663 /// Slope 2 (high-current region, typical 0.6–0.8).
5664 pub slope2: f64,
5665 /// Minimum pickup current (pu).
5666 pub i_pickup: f64,
5667 /// 2nd harmonic blocking ratio (typical 0.15–0.20). Trip blocked if
5668 /// 2nd-harmonic content > ratio × fundamental.
5669 pub harmonic_restraint: f64,
5670 /// High-side bus number.
5671 pub from_bus: u32,
5672 /// Low-side bus number.
5673 pub to_bus: u32,
5674 /// Circuit identifier.
5675 pub circuit: String,
5676 /// Turns ratio (high-side / low-side rated voltage).
5677 pub turns_ratio: f64,
5678 /// Measurement filter time constant (s). Default: 0.01 (10ms).
5679 pub tf: f64,
5680}
5681
5682/// 87L — Line differential relay.
5683///
5684/// Compares currents at both ends of a transmission line. Trips the branch
5685/// (not a generator) when the differential current exceeds the restraint.
5686///
5687/// DYR params: `SLOPE1 SLOPE2 I_PICKUP FROM_BUS TO_BUS CKT TF`
5688#[derive(Debug, Clone, Serialize, Deserialize)]
5689pub struct LineDiff87lParams {
5690 /// Slope 1 of restraint characteristic (typical 0.2–0.3).
5691 pub slope1: f64,
5692 /// Slope 2 (high-current region, typical 0.6–0.8).
5693 pub slope2: f64,
5694 /// Minimum pickup current (pu).
5695 pub i_pickup: f64,
5696 /// From-bus of protected line.
5697 pub from_bus: u32,
5698 /// To-bus of protected line.
5699 pub to_bus: u32,
5700 /// Circuit identifier.
5701 pub circuit: String,
5702 /// Measurement filter time constant (s). Default: 0.01 (10ms).
5703 pub tf: f64,
5704}
5705
5706/// 79 — Automatic recloser.
5707///
5708/// After a relay trips a branch, the recloser waits a dead-time delay then
5709/// recloses the branch. If the fault persists, it re-trips and repeats up to
5710/// `max_attempts` times before locking out.
5711///
5712/// DYR params: `DEAD1 DEAD2 DEAD3 MAX_ATTEMPTS FROM_BUS TO_BUS CKT RESET_TIME`
5713#[derive(Debug, Clone, Serialize, Deserialize)]
5714pub struct Recloser79Params {
5715 /// First reclose dead-time delay (s).
5716 pub dead_time_1: f64,
5717 /// Second reclose dead-time delay (s).
5718 pub dead_time_2: f64,
5719 /// Third reclose dead-time delay (s).
5720 pub dead_time_3: f64,
5721 /// Maximum reclose attempts before lockout (1–3).
5722 pub max_attempts: u32,
5723 /// From-bus of reclosable branch.
5724 pub from_bus: u32,
5725 /// To-bus of reclosable branch.
5726 pub to_bus: u32,
5727 /// Circuit identifier.
5728 pub circuit: String,
5729 /// Time after successful reclose to reset attempt counter (s).
5730 pub reset_time: f64,
5731}
5732
5733// ---------------------------------------------------------------------------
5734// Wave 37: OEL/UEL Limiter types
5735// ---------------------------------------------------------------------------
5736
5737/// OEL1B — Over-Excitation Limiter Type 1B (inverse-time ramp limiter).
5738///
5739/// PSS/E params: `IFDMAX IFDLIM VRMAX VAMIN KRAMP TFF`
5740#[derive(Debug, Clone, Serialize, Deserialize)]
5741pub struct Oel1bParams {
5742 /// Maximum continuous field current (pu) — ramp starts above this.
5743 pub ifdmax: f64,
5744 /// Instantaneous trip limit (pu).
5745 pub ifdlim: f64,
5746 /// Maximum regulator output (pu).
5747 pub vrmax: f64,
5748 /// Minimum amplifier output (pu, negative).
5749 pub vamin: f64,
5750 /// Limiter ramp rate (pu/s).
5751 pub kramp: f64,
5752 /// Field current filter time constant (s).
5753 pub tff: f64,
5754}
5755
5756/// OEL2C — Over-Excitation Limiter Type 2C (fixed-current with time delay).
5757///
5758/// PSS/E params: `IFDMAX T_OEL VAMIN VRMAX K_OEL`
5759#[derive(Debug, Clone, Serialize, Deserialize)]
5760pub struct Oel2cParams {
5761 /// Maximum field current (pu).
5762 pub ifdmax: f64,
5763 /// Time delay before limiting (s).
5764 pub t_oel: f64,
5765 /// Minimum output (pu, negative).
5766 pub vamin: f64,
5767 /// Maximum regulator output (pu).
5768 pub vrmax: f64,
5769 /// Gain.
5770 pub k_oel: f64,
5771}
5772
5773/// SCL1C — Stator Current Limiter Type 1C.
5774///
5775/// PSS/E params: `IRATED KR TR VCLMAX VCLMIN`
5776#[derive(Debug, Clone, Serialize, Deserialize)]
5777pub struct Scl1cParams {
5778 /// Rated stator current (pu).
5779 pub irated: f64,
5780 /// Gain.
5781 pub kr: f64,
5782 /// Current filter time constant (s).
5783 pub tr: f64,
5784 /// Maximum clamp output (pu).
5785 pub vclmax: f64,
5786 /// Minimum clamp output (pu, negative).
5787 pub vclmin: f64,
5788}
5789
5790/// UEL1 — Under-Excitation Limiter Type 1 (single-input integrator).
5791///
5792/// PSS/E params: `KUL TU1 VUCMAX VUCMIN KUR`
5793#[derive(Debug, Clone, Serialize, Deserialize)]
5794pub struct Uel1Params {
5795 /// UEL gain.
5796 pub kul: f64,
5797 /// UEL time constant (s).
5798 pub tu1: f64,
5799 /// Maximum UEL output (pu).
5800 pub vucmax: f64,
5801 /// Minimum UEL output (pu).
5802 pub vucmin: f64,
5803 /// Reactive power sensitivity.
5804 pub kur: f64,
5805}
5806
5807/// UEL2C — Under-Excitation Limiter Type 2C (P-Q plane limiter).
5808///
5809/// PSS/E params: `KUL TU1 TU2 TU3 TU4 VUIMAX VUIMIN P0 Q0`
5810#[derive(Debug, Clone, Serialize, Deserialize)]
5811pub struct Uel2cParams {
5812 /// UEL gain.
5813 pub kul: f64,
5814 /// Filter time constant 1 (s).
5815 pub tu1: f64,
5816 /// Filter time constant 2 (s).
5817 pub tu2: f64,
5818 /// Filter time constant 3 (s).
5819 pub tu3: f64,
5820 /// Filter time constant 4 (s).
5821 pub tu4: f64,
5822 /// Maximum integrator output (pu).
5823 pub vuimax: f64,
5824 /// Minimum integrator output (pu).
5825 pub vuimin: f64,
5826 /// Reference active power (pu).
5827 pub p0: f64,
5828 /// Reference reactive power (pu).
5829 pub q0: f64,
5830}
5831
5832/// OEL dynamic record — over-excitation limiter attached to a generator.
5833#[derive(Debug, Clone, Serialize, Deserialize)]
5834pub struct OelDyn {
5835 /// Bus number.
5836 pub bus: u32,
5837 /// Machine ID string (matches the generator record).
5838 pub machine_id: String,
5839 /// OEL model and parameters.
5840 pub model: OelModel,
5841}
5842
5843/// UEL dynamic record — under-excitation limiter attached to a generator.
5844#[derive(Debug, Clone, Serialize, Deserialize)]
5845pub struct UelDyn {
5846 /// Bus number.
5847 pub bus: u32,
5848 /// Machine ID string (matches the generator record).
5849 pub machine_id: String,
5850 /// UEL model and parameters.
5851 pub model: UelModel,
5852}
5853
5854/// Discriminated union of OEL models.
5855#[derive(Debug, Clone, Serialize, Deserialize)]
5856#[serde(tag = "type")]
5857pub enum OelModel {
5858 /// OEL1B — inverse-time ramp limiter.
5859 Oel1b(Oel1bParams),
5860 /// OEL2C — fixed current + time delay limiter.
5861 Oel2c(Oel2cParams),
5862 /// OEL3C — alias to OEL2C (C-series 2016 standard).
5863 Oel3c(Oel2cParams),
5864 /// OEL4C — alias to OEL2C (C-series 2016 standard).
5865 Oel4c(Oel2cParams),
5866 /// OEL5C — alias to OEL2C (C-series 2016 standard).
5867 Oel5c(Oel2cParams),
5868 /// SCL1C — stator current limiter (uses OEL slot).
5869 Scl1c(Scl1cParams),
5870}
5871
5872/// Discriminated union of UEL models.
5873#[derive(Debug, Clone, Serialize, Deserialize)]
5874#[serde(tag = "type")]
5875pub enum UelModel {
5876 /// UEL1 — single-input integrator UEL.
5877 Uel1(Uel1Params),
5878 /// UEL2C — P-Q plane limiter (two-state filter).
5879 Uel2c(Uel2cParams),
5880}
5881
5882/// Shaft dynamic model assignment — keyed by (bus, machine_id).
5883/// Follows the same pattern as ExciterDyn, GovernorDyn, PssDyn, OelDyn, UelDyn.
5884#[derive(Debug, Clone, Serialize, Deserialize)]
5885pub struct ShaftDyn {
5886 /// Bus number of the associated generator.
5887 pub bus: u32,
5888 /// Machine ID (matches the generator record).
5889 pub machine_id: String,
5890 /// N-mass torsional shaft model.
5891 pub model: crate::dynamics::shaft::ShaftModel,
5892}
5893
5894#[cfg(test)]
5895mod tests {
5896 use super::*;
5897
5898 fn empty_dm() -> DynamicModel {
5899 DynamicModel::default()
5900 }
5901
5902 #[test]
5903 fn test_coverage_all_supported() {
5904 let mut dm = empty_dm();
5905 dm.generators.push(GeneratorDyn {
5906 bus: 1,
5907 machine_id: "1".into(),
5908 model: GeneratorModel::Gencls(GenclsParams { h: 3.0, d: 0.0 }),
5909 });
5910 let (n_sup, n_tot, pct) = dm.coverage();
5911 assert_eq!(n_sup, 1);
5912 assert_eq!(n_tot, 1);
5913 assert!((pct - 100.0).abs() < 1e-10);
5914 }
5915
5916 #[test]
5917 fn test_coverage_with_unknown() {
5918 let mut dm = empty_dm();
5919 dm.generators.push(GeneratorDyn {
5920 bus: 1,
5921 machine_id: "1".into(),
5922 model: GeneratorModel::Gencls(GenclsParams { h: 3.0, d: 0.0 }),
5923 });
5924 dm.unknown_records.push(UnknownDyrRecord {
5925 bus: 2,
5926 model_name: "GENCC".into(),
5927 machine_id: "1".into(),
5928 params: vec![1.0, 2.0],
5929 });
5930 let (n_sup, n_tot, pct) = dm.coverage();
5931 assert_eq!(n_sup, 1);
5932 assert_eq!(n_tot, 2);
5933 assert!((pct - 50.0).abs() < 1e-10);
5934 }
5935
5936 #[test]
5937 fn test_coverage_empty() {
5938 let dm = empty_dm();
5939 let (n_sup, n_tot, pct) = dm.coverage();
5940 assert_eq!(n_sup, 0);
5941 assert_eq!(n_tot, 0);
5942 assert!((pct - 100.0).abs() < 1e-10);
5943 }
5944}