DPsim
Loading...
Searching...
No Matches
HydroTurbineGovernor.cpp
1// SPDX-FileCopyrightText: 2026 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University
2// SPDX-License-Identifier: MPL-2.0
3
4#include <dpsim-models/Signal/HydroTurbineGovernor.h>
5
6using namespace CPS;
7using namespace CPS::Signal;
8
9Signal::HydroTurbineGovernor::HydroTurbineGovernor(const String &name,
10 CPS::Logger::Level logLevel)
11 : SimSignalComp(name, name, logLevel),
12 mDelOm(mAttributes->create<Real>("DelOm")),
13 mX1(mAttributes->create<Real>("X1")),
14 mX2(mAttributes->create<Real>("X2")),
15 mPgv(mAttributes->create<Real>("Pgv")) {}
16
17void HydroTurbineGovernor::setParameters(
18 std::shared_ptr<Base::GovernorParameters> parameters) {
19 auto params =
20 std::dynamic_pointer_cast<Signal::HydroGovernorParameters>(parameters);
21 if (!params) {
22 SPDLOG_LOGGER_ERROR(
23 mSLog,
24 "Type of parameters class of {} has to be HydroGovernorParameters!",
25 this->name());
26 throw CPS::TypeException();
27 }
28 if (params->R <= 0) {
29 SPDLOG_LOGGER_ERROR(mSLog, "R must be positive for {}", this->name());
30 throw CPS::InvalidArgumentException();
31 }
32 if (params->T1 <= 0) {
33 SPDLOG_LOGGER_ERROR(mSLog, "T1 must be positive for {}", this->name());
34 throw CPS::InvalidArgumentException();
35 }
36 if (params->T3 <= 0) {
37 SPDLOG_LOGGER_ERROR(mSLog, "T3 must be positive for {}", this->name());
38 throw CPS::InvalidArgumentException();
39 }
40 if (params->T1 == params->T3) {
41 SPDLOG_LOGGER_ERROR(mSLog, "T1 must not equal T3 for {}", this->name());
42 throw CPS::InvalidArgumentException();
43 }
44 mParameters = params;
45
46 SPDLOG_LOGGER_INFO(mSLog,
47 "\nHydro Governor parameters:"
48 "\nOmRef: {:e}"
49 "\nR: {:e}"
50 "\nT1: {:e}"
51 "\nT2: {:e}"
52 "\nT3: {:e}"
53 "\nPmax: {:e}"
54 "\nPmin: {:e}\n",
55 mParameters->OmRef, mParameters->R, mParameters->T1,
56 mParameters->T2, mParameters->T3, mParameters->Pmax,
57 mParameters->Pmin);
58 mSLog->flush();
59}
60
62 if (Pref < mParameters->Pmin || Pref > mParameters->Pmax) {
63 SPDLOG_LOGGER_ERROR(
64 mSLog,
65 "Pref of hydro governor {} must be in [Pmin, Pmax] = [{:f}, {:f}] pu",
66 this->name(), mParameters->Pmin, mParameters->Pmax);
68 }
69 mPref = Pref;
70 **mDelOm = 0;
71 mDelOm_prev = 0;
72 **mX1 = 0;
73 mX1_prev = 0;
74 **mX2 = 0;
75 mX2_prev = 0;
76 **mPgv = Pref;
77
78 mCa =
79 (mParameters->T1 - mParameters->T2) / (mParameters->T1 - mParameters->T3);
80 mCb =
81 (mParameters->T2 - mParameters->T3) / (mParameters->T1 - mParameters->T3);
82
83 SPDLOG_LOGGER_INFO(mSLog,
84 "\nHydro Governor initial values:"
85 "\nPref: {:f}"
86 "\nDelOm: {:f}"
87 "\nX1: {:f}"
88 "\nX2: {:f}"
89 "\nPgv: {:f}",
90 mPref, **mDelOm, **mX1, **mX2, **mPgv);
91 mSLog->flush();
92}
93
94Real HydroTurbineGovernor::step(Real Omega, Real dt) {
95 // Shift state variables one step back
96 mDelOm_prev = **mDelOm;
97 mX1_prev = **mX1;
98 mX2_prev = **mX2;
99
100 // Compute input deviation
101 **mDelOm = mParameters->OmRef - Omega;
102
103 // Update PT1 states with forward Euler
104 **mX1 = mX1_prev + (dt / mParameters->T1) * (mDelOm_prev - mX1_prev);
105 **mX2 = mX2_prev + (dt / mParameters->T3) * (mDelOm_prev - mX2_prev);
106
107 // Compute governor output before limiter
108 Real Pgv_raw = mPref + (1.0 / mParameters->R) * (**mX1 * mCa + **mX2 * mCb);
109
110 // Apply output limiter
111 if (Pgv_raw > mParameters->Pmax)
112 **mPgv = mParameters->Pmax;
113 else if (Pgv_raw < mParameters->Pmin)
114 **mPgv = mParameters->Pmin;
115 else
116 **mPgv = Pgv_raw;
117
118 return **mPgv;
119}
Real step(Real Omega, Real dt) final
Step the governor and return the valve/gate opening signal Pgv.
void initializeStates(Real Pref) final
Set steady-state initial values (call after setParameters, before first step)
Logger::Log mSLog
Component logger.