StateSpaceShield Class¶
- class automationshield.StateSpaceShield(n_states: int, discretisation: str | None = None)[source]¶
Bases:
BaseDummyShieldThis class can be used to simulate a general state-space model and control it using a
automationshield.ShieldControllerinstance. The state-space system must be a SISO system.Create a class that inherits from
StateSpaceShieldand override the following methods:calculate_a(),calculate_b(),calculate_c(),calculate_d(): These methods should return state-space matrices A, B, C and D, respectively. They take the current state vector as input, which makes it possible to update the matrices depending on the current state of the system. This way, a non-linear system can be simulated accurately.Optional:
get_equilibrium_point(): Override this method when you’re including non-linear behaviour. This method should return the equilibrium state and required input to maintain this state.
- Parameters:
- EXACT = 'exact'¶
Set discretisation to this constant for exact discretisation.
- EULER = 'euler'¶
Set discretisation to this constant for Euler discretisation.
- TUSTIN = 'tustin'¶
Set discretisation to this constant for Tustin discretisation.
- property discretisation: str¶
Get or set discretisation method used. Must be one of
EXACT,EULERorTUSTIN. In order to useEXACT, Scipy must be installed.- Raises:
RunTimeError – When trying to set
EXACTwithout Scipy installed.
- calculate_a(state: ndarray[tuple[int, ...], dtype[float64]]) ndarray[tuple[int, ...], dtype[float64]][source]¶
Calculate A matrix. This method must be implemented on a subclass.
- calculate_b(state: ndarray[tuple[int, ...], dtype[float64]]) ndarray[tuple[int, ...], dtype[float64]][source]¶
Calculate B matrix. This method must be implemented on a subclass.
- calculate_c(state: ndarray[tuple[int, ...], dtype[float64]]) ndarray[tuple[int, ...], dtype[float64]][source]¶
Calculate C matrix. This method must be implemented on a subclass.
- calculate_d(state: ndarray[tuple[int, ...], dtype[float64]]) ndarray[tuple[int, ...], dtype[float64]][source]¶
Calculate A matrix. This method must be implemented on a subclass.
- get_equilibrium_point(state: ndarray[tuple[int, ...], dtype[float64]]) tuple[ndarray[tuple[int, ...], dtype[float64]], float][source]¶
Return equilibrium input and state for the current state. Used for linearising at the current state. By default, the equilibrium state and input are returned as (0, 0), in which case this method has no effect.
- discretise(a: ndarray[tuple[int, ...], dtype[float64]], b: ndarray[tuple[int, ...], dtype[float64]], dt: float) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]¶
Calculate discrete-time matrices \(A_D\) and \(B_D\) from their continuous-time counterpart obtained from
calculate_a()andcalculate_b(), respectively, using the discretisation method set.
- discrete_exact(a: ndarray[tuple[int, ...], dtype[float64]], b: ndarray[tuple[int, ...], dtype[float64]], dt: float) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]¶
Calculate discrete-time matrices \(A_D\) and \(B_D\) from their continuous-time counterpart obtained from
calculate_a()andcalculate_b(), respectively, using the exact discretisation method.\[\begin{split}A_D &= e^{A \cdot dt} \\ B_D &= A^{-1} \cdot \left(A_D - I \right) \cdot B\end{split}\]
- discrete_tustin(a: ndarray[tuple[int, ...], dtype[float64]], b: ndarray[tuple[int, ...], dtype[float64]], dt: float) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]¶
Calculate discrete-time matrices \(A_D\) and \(B_D\) from their continuous-time counterpart obtained from
calculate_a()andcalculate_b(), respectively, using the Tustin discretisation method.\[\begin{split}A_D &= \left(I + \frac{A \cdot dt}{2} \right) \cdot \left( I - \frac{A \cdot dt}{2} \right)^{-1} \\ B_D &= A^{-1} \cdot \left(A_D - I \right) \cdot B\end{split}\]
- discrete_euler(a: ndarray[tuple[int, ...], dtype[float64]], b: ndarray[tuple[int, ...], dtype[float64]], dt: float) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]¶
Calculate discrete-time matrices \(A_D\) and \(B_D\) from their continuous-time counterpart obtained from
calculate_a()andcalculate_b(), respectively, using the forward Euler discretisation method.\[\begin{split}A_D &= I + A \cdot dt \\ B_D &= B \cdot dt\end{split}\]
- condition_input(input: float) float[source]¶
Condition the input before applying it to the system. Override this method in your subclass to customise how the input is conditioned. By default, the input is returned unchanged.
- read() tuple[int, float][source]¶
The
automationshield.shields.BaseShield.read()method is overridden to replicate the behaviour from a physical shield. This method calculates the output of the system and returns it. The output corresponding to the potentiometer value of a physical shield is set to 0.\[y = C \cdot x + D \cdot u\]
- write(flag: int, input: float) float[source]¶
The
automationshield.shields.BaseShield.read()method is overridden to replicate the behaviour from a physical shield. This method does the following:Update the time step;
Calculate the equilibrium point input \(u_e\) and state \(x_e\);
Calculate the discrete-time system and input matrices \(A_D\) and \(B_D\);
Update the state vector using the equation below.
\[x_{k+1} = x_e + A_D \cdot \left( x_k - x_{e,k} \right) + B_D \cdot \left( u_k - u_{e,k} \right)\]Finally, the input is update with the conditioned input value. Conditioning is performed through
StateSpaceShield.condition_input().