Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions GridKit/Model/PhasorDynamics/Exciter/IEEET1/Ieeet1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ namespace GridKit
OMEGA, ///< Generator speed deviation
VREAL, ///< Real bus voltage
VIMAG, ///< Imaginary bus voltage
VREF, ///< Voltage reference
VS, ///< Stabilizer output signal
VUEL, ///< Under-excitation limiter signal
VOEL, ///< Over-excitation limiter signal
MAXIMUM,
};

Expand Down Expand Up @@ -153,11 +156,15 @@ namespace GridKit
RealT SA_{0};
RealT SB_{0};

// External Variables that don't have models yet.
// They are constants until then.
ScalarT vref_{0}; // (Setpoint voltage, can be different from terminal voltage)
ScalarT vUEL_{0};
ScalarT vOEL_{0};
// Runtime connection masks keep the summing junction Enzyme sparse-solvable
RealT uel_on_{0};
RealT oel_on_{0};

ScalarT omega_set_{0};
ScalarT vref_set_{0};
ScalarT vs_set_{0};
ScalarT vuel_set_{0};
ScalarT voel_set_{0};

/// Component signal extension
ComponentSignals<ScalarT, IdxT, Ieeet1InternalVariables, Ieeet1ExternalVariables> signals_;
Expand Down
3 changes: 3 additions & 0 deletions GridKit/Model/PhasorDynamics/Exciter/IEEET1/Ieeet1Data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ namespace GridKit
enum class Ieeet1SignalInputs : size_t
{
speed, ///< Unique ID of the generator speed signal
vref, ///< Unique ID of the voltage reference signal (optional)
vs, ///< Unique ID of the stabilizer output signal (optional)
vuel, ///< Unique ID of the under-excitation limiter signal (optional)
voel, ///< Unique ID of the over-excitation limiter signal (optional)
SIZE
};

Expand Down
122 changes: 77 additions & 45 deletions GridKit/Model/PhasorDynamics/Exciter/IEEET1/Ieeet1Impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,9 @@ namespace GridKit
wb_.resize(2);

// Resize signal variable data
ws_.resize(2);
ws_indices_.resize(2);
ws_[0] = 0.0;
ws_indices_[0] = INVALID_INDEX<IdxT>;
ws_[1] = 0.0;
ws_indices_[1] = INVALID_INDEX<IdxT>;
const auto signal_size = static_cast<size_t>(Ieeet1ExternalVariables::MAXIMUM);
ws_.assign(signal_size, ScalarT{0});
ws_indices_.assign(signal_size, INVALID_INDEX<IdxT>);

// Set output signals
if (signals_.template isAssigned<Ieeet1InternalVariables::EFD>())
Expand All @@ -124,9 +121,6 @@ namespace GridKit
template <typename scalar_type, typename index_type>
int Ieeet1<scalar_type, index_type>::verify() const
{
static constexpr auto OMEGA = Ieeet1ExternalVariables::OMEGA;
static constexpr auto VS = Ieeet1ExternalVariables::VS;

int ret = 0;

auto check = [&](bool condition, const char* message)
Expand Down Expand Up @@ -157,23 +151,22 @@ namespace GridKit
check(sat_ordered, "E1/E2 and Se1/Se2 must be ordered consistently");
}

if (signals_.template isAttached<OMEGA>())
auto check_attached_signal =
[&]<Ieeet1ExternalVariables variable>(const char* name)
{
if (!signals_.template isLinked<OMEGA>())
if (signals_.template isAttached<variable>()
&& !signals_.template isLinked<variable>())
{
Log::error() << "Ieeet1: omega signal attached with no linked generator\n";
Log::error() << "Ieeet1: " << name << " signal attached with no linked source\n";
ret += 1;
}
}
};

if (signals_.template isAttached<VS>())
{
if (!signals_.template isLinked<VS>())
{
Log::error() << "Ieeet1: VS signal attached with no linked source\n";
ret += 1;
}
}
check_attached_signal.template operator()<Ieeet1ExternalVariables::OMEGA>("speed");
check_attached_signal.template operator()<Ieeet1ExternalVariables::VREF>("vref");
check_attached_signal.template operator()<Ieeet1ExternalVariables::VS>("vs");
check_attached_signal.template operator()<Ieeet1ExternalVariables::VUEL>("vuel");
check_attached_signal.template operator()<Ieeet1ExternalVariables::VOEL>("voel");

return ret;
}
Expand All @@ -187,9 +180,10 @@ namespace GridKit
* Inputs:
* - EFD assigned by the generator.
* - Bus voltage, used to form the sensed terminal voltage magnitude.
* - Attached external signals (omega, V_S)
* - Attached external signals (omega, V_S, V_UEL, V_OEL)
*
* Enabled saturation is included via ksat computed from efdp and SA, SB.
* The resolved V_ref is written to an attached vref signal.
*
* @warning IEEE Std 421.5-2016 states: “In some programs, if
* \f$K_{E}\f$ is entered as zero, \f$K_{E}\f$ is automatically
Expand Down Expand Up @@ -226,15 +220,30 @@ namespace GridKit
efd0 = y[7]; ///<- generator needs to be initialized first
}

ScalarT omega{0};
ScalarT vs{0};
if (signals_.template isAttached<Ieeet1ExternalVariables::OMEGA>())
auto read_attached = [&]<Ieeet1ExternalVariables variable>() -> ScalarT
{
if (signals_.template isAttached<variable>())
{
return signals_.template readExternalVariable<variable>();
}
return ScalarT{0};
};

const ScalarT omega = read_attached.template operator()<Ieeet1ExternalVariables::OMEGA>();
const ScalarT vs = read_attached.template operator()<Ieeet1ExternalVariables::VS>();
const ScalarT vuel = read_attached.template operator()<Ieeet1ExternalVariables::VUEL>();
const ScalarT voel = read_attached.template operator()<Ieeet1ExternalVariables::VOEL>();

uel_on_ = ZERO<RealT>;
if (signals_.template isAttached<Ieeet1ExternalVariables::VUEL>())
{
omega = signals_.template readExternalVariable<Ieeet1ExternalVariables::OMEGA>();
uel_on_ = ONE<RealT>;
}
if (signals_.template isAttached<Ieeet1ExternalVariables::VS>())

oel_on_ = ZERO<RealT>;
if (signals_.template isAttached<Ieeet1ExternalVariables::VOEL>())
{
vs = signals_.template readExternalVariable<Ieeet1ExternalVariables::VS>();
oel_on_ = ONE<RealT>;
}

// Terminal Voltage
Expand Down Expand Up @@ -266,7 +275,7 @@ namespace GridKit
ScalarT vf{0};
ScalarT vfx = (Kf_ / Tf_) * efdp;

vref_ = Ec + vtr + vf - vUEL_ - vOEL_ - vs;
const ScalarT vref = Ec + vtr + vf - vs - uel_on_ * vuel - oel_on_ * voel;

y[0] = Ec; // y0 - vts - Sensed term volt
y[1] = vr; // y1 - vr - Voltage reg
Expand All @@ -283,6 +292,17 @@ namespace GridKit
yp[i] = 0.0;
}

omega_set_ = omega;
vref_set_ = vref;
vs_set_ = vs;
vuel_set_ = vuel;
voel_set_ = voel;

if (signals_.template isAttached<Ieeet1ExternalVariables::VREF>())
{
signals_.template writeExternalVariable<Ieeet1ExternalVariables::VREF>(vref_set_);
}

y_.setDataUpdated();
yp_.setDataUpdated();

Expand Down Expand Up @@ -341,6 +361,12 @@ namespace GridKit
const ScalarT* ws,
ScalarT* f)
{
const auto OMEGA = static_cast<size_t>(Ieeet1ExternalVariables::OMEGA);
const auto VREF = static_cast<size_t>(Ieeet1ExternalVariables::VREF);
const auto VS = static_cast<size_t>(Ieeet1ExternalVariables::VS);
const auto VUEL = static_cast<size_t>(Ieeet1ExternalVariables::VUEL);
const auto VOEL = static_cast<size_t>(Ieeet1ExternalVariables::VOEL);

// Read bus voltage components
ScalarT vreal = wb[0];
ScalarT vimag = wb[1];
Expand All @@ -364,8 +390,11 @@ namespace GridKit
ScalarT vfx_dot = yp[3];

// Set signal variable aliases
ScalarT omega = ws[0];
ScalarT vs_signal = ws[1];
ScalarT omega = ws[OMEGA];
ScalarT vref = ws[VREF];
ScalarT vs = ws[VS];
ScalarT vuel = ws[VUEL];
ScalarT voel = ws[VOEL];

// The 'pre-limit' derivative of Vr.
ScalarT func = (-vr + Ka_ * vtr) / Ta_;
Expand All @@ -377,7 +406,7 @@ namespace GridKit
f[3] = -vfx_dot + vf / Tf_;

// Internal Algebraic Equations
f[4] = -vts + vref_ + vUEL_ + vOEL_ + vs_signal - vtr - vf;
f[4] = -vts + vref + vs + uel_on_ * vuel + oel_on_ * voel - vtr - vf;
f[5] = -Tf_ * (vf + vfx) + Kf_ * efdp;
f[6] = -ve + ksat;
f[7] = -efd + efdp + omega * efdp * Ispdlim_;
Expand All @@ -393,21 +422,24 @@ namespace GridKit
template <typename scalar_type, typename index_type>
int Ieeet1<scalar_type, index_type>::evaluateResidual()
{
// Set input variables.
if (signals_.template isAttached<Ieeet1ExternalVariables::OMEGA>())
// Attached signals are read live; unattached ones keep the latched value.
auto read_signal = [&]<Ieeet1ExternalVariables variable>(const ScalarT& latched)
{
ws_[0] = signals_.template readExternalVariable<Ieeet1ExternalVariables::OMEGA>();
ws_indices_[0] = signals_.template readExternalVariableIndex<Ieeet1ExternalVariables::OMEGA>();
}
const auto index = static_cast<size_t>(variable);
ws_[index] = latched;
ws_indices_[index] = INVALID_INDEX<IdxT>;
if (signals_.template isAttached<variable>())
{
ws_[index] = signals_.template readExternalVariable<variable>();
ws_indices_[index] = signals_.template readExternalVariableIndex<variable>();
}
};

// VS signal (stabilizer output, optional)
ws_[1] = 0.0;
ws_indices_[1] = INVALID_INDEX<IdxT>;
if (signals_.template isAttached<Ieeet1ExternalVariables::VS>())
{
ws_[1] = signals_.template readExternalVariable<Ieeet1ExternalVariables::VS>();
ws_indices_[1] = signals_.template readExternalVariableIndex<Ieeet1ExternalVariables::VS>();
}
read_signal.template operator()<Ieeet1ExternalVariables::OMEGA>(omega_set_);
read_signal.template operator()<Ieeet1ExternalVariables::VREF>(vref_set_);
read_signal.template operator()<Ieeet1ExternalVariables::VS>(vs_set_);
read_signal.template operator()<Ieeet1ExternalVariables::VUEL>(vuel_set_);
read_signal.template operator()<Ieeet1ExternalVariables::VOEL>(voel_set_);

// Bus voltages
wb_[0] = bus_->Vr();
Expand Down
38 changes: 29 additions & 9 deletions GridKit/Model/PhasorDynamics/Exciter/IEEET1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ $I_{\mathrm{spdlim}}$ | [binary] | Speed limit flag indicator | 0 |
### Parameter Validation

Invalid IEEET1 parameter sets are rejected by the following checks. Let $\epsilon_T=10^{-3}$.
Time constants below $\epsilon_T$ are raised to $\epsilon_T$ and logged as a warning;
every other condition is a configuration error.

```math
\begin{aligned}
Expand Down Expand Up @@ -135,6 +137,15 @@ K_E^{\mathrm{eff}}
Thus $K_E^{\mathrm{eff}}$ is the resolved value of the same exciter
coefficient, not an additional model input.

## Model Ports

Name | Port | Init | Description
--------|--------|-------|------------
`bus` | Bus | Known | Terminal bus voltage
`speed` | Input | Known | Optional machine speed deviation; defaults to zero
`vs` | Input | Known | Optional stabilizer input signal; defaults to zero
`efd` | Output | Known | Field-voltage output seeded by the machine

## Model Variables

### Internal Variables
Expand All @@ -145,7 +156,7 @@ Symbol | Units | Description | Note
----------|--------|------------------------------------|-------
$V_{ts}$ | [p.u.] | Sensed terminal voltage |
$V_R$ | [p.u.] | Voltage regulator |
$E_{fd}'$ | [p.u.] | Field-current pre-speed multiplier |
$E_{fd}'$ | [p.u.] | Field voltage before the speed multiplier |
$V_{fx}$ | [p.u.] | Exciter feedback internal state |


Expand All @@ -162,11 +173,17 @@ $k_\text{sat}$ | [p.u.] | Scaled-quadratic saturation contribution | $E_{fd}'S(

### External Variables

#### Differential

None.

#### Algebraic

Symbol | Units | Description | Note
----------------|--------|-----------------------------------|-------
$V_r$ | [p.u.] | Real bus voltage component |
$V_i$ | [p.u.] | Imaginary bus voltage component |
$V_\text{ref}$ | [p.u.] | Reference terminal voltage |
$V_\text{ref}$ | [p.u.] | Reference terminal voltage | Set during initialization; constant thereafter
$V_{UEL}$ | [p.u.] | Input from under excitation limiter | Constant zero until modeled
$V_{OEL}$ | [p.u.] | Input from over excitation limiter | Constant zero until modeled
$V_S$ | [p.u.] | Input from stabilizer controller | Optional, defaults to zero
Expand All @@ -175,7 +192,9 @@ $\omega$ | [p.u.] | Machine speed deviation | Opti

## Model Equations

### Differential Equations
### Internal Equations

#### Differential

For readability, define the pre-limit derivative of $V_R$ and voltage-sensing input:

Expand All @@ -201,7 +220,7 @@ The IEEET1 differential equations, as derived from the model diagram, are:

CommonMath defines the smooth [Anti-Windup](../../../../CommonMath.md#antiwindup) target and approximation.

### Algebraic Equations
#### Algebraic

The algebraic equations of the exciter.
```math
Expand All @@ -214,13 +233,14 @@ The algebraic equations of the exciter.
\end{aligned}
```

Here $q$ is GridKit's [Quadratic Ramp](../../../../CommonMath.md#primitives).
Here $q$ is GridKit's [Quadratic Ramp](../../../../CommonMath.md#quadratic-ramp).

### External Equations

None.

## Initialization

The implementation first applies $T \leftarrow \max(T, 10^{-3})$ for
$T \in \{T_R, T_A, T_E, T_F\}$. This should be replaced with a structural template change in the future.
The machine initializes $E_{fd}$ first. IEEET1
reads that value, along with any attached $\omega$ and $V_S$, and
solves the steady-state algebraic chain so all residuals vanish with
Expand All @@ -246,9 +266,9 @@ with the current input values.

All internal derivatives initialize to zero.

## Monitorable Variables
## Monitors

Variable | Units | Description | Note
Monitor | Units | Description | Note
---------|--------|-----------------------------------|------
`efd` | [p.u.] | Field winding voltage |
`ksat` | [p.u.] | Scaled-quadratic saturation contribution | $S_B\,q(E_{fd}'-S_A)$
Loading
Loading