Controlpp
Loading...
Searching...
No Matches
StateSpace.hpp
Go to the documentation of this file.
1#pragma once
2
3// std
4#include <tuple>
5#include <concepts>
6
7// eigen
8#include <Eigen/Core>
9
10// controlpp
11#include <controlpp/math.hpp>
13
14namespace controlpp
15{
16
30 template<class T, int NStates, int NInputs, int NOutputs>
32 public:
33 using value_type = T;
34
35 using A_matrix_type = Eigen::Matrix<T, NStates, NStates>;
36 using B_matrix_type = Eigen::Matrix<T, NStates, NInputs>;
37 using C_matrix_type = Eigen::Matrix<T, NOutputs, NStates>;
38 using D_matrix_type = Eigen::Matrix<T, NOutputs, NInputs>;
39
40 //constexpr static int number_of_states = NStates;
41 //constexpr static int number_of_inputs = NInputs;
42 //constexpr static int number_of_outputs = NOutputs;
43
44 private:
49
50 public:
51 StateSpace() = default;
52 StateSpace(const StateSpace&) = default;
53 StateSpace& operator=(const StateSpace&) = default;
54
56 const Eigen::Matrix<T, NStates, NStates>& A,
57 const Eigen::Matrix<T, NStates, NInputs>& B,
58 const Eigen::Matrix<T, NOutputs, NStates>& C,
59 const Eigen::Matrix<T, NOutputs, NInputs>& D
60 )
61 : _A(A)
62 , _B(B)
63 , _C(C)
64 , _D(D){}
65
76 std::tuple<Eigen::Vector<T, NStates>, Eigen::Vector<T, NOutputs>> eval(const Eigen::Vector<T, NStates>& x, const Eigen::Vector<T, NInputs>& u) const {
77 const Eigen::Vector<T, NStates> result_x = this->A() * x + this->B() * u;
78 const Eigen::Vector<T, NOutputs> result_y = this->C() * x + this->D() * u;
79 return std::tuple(result_x, result_y);
80 }
81
94 template<std::convertible_to<T> U>
95 requires(NInputs == 1 && NOutputs != 1)
96 std::tuple<Eigen::Vector<U, NStates>, Eigen::Vector<U, NOutputs>> eval(const Eigen::Vector<U, NStates>& x, const U& u_scalar) const {
97 const Eigen::Vector<T, 1> u(static_cast<T>(u_scalar));
98 return this->eval(x, u);
99 }
100
113 template<std::convertible_to<T> U>
114 requires(NInputs == 1 && NOutputs == 1)
115 std::tuple<Eigen::Vector<U, NStates>, U> eval(const Eigen::Vector<U, NStates>& x, const U& u_scalar) const {
116 const Eigen::Vector<T, 1> u(static_cast<T>(u_scalar));
117 const auto [new_x, y] = this->eval(x, u);
118 return {new_x, y(0)};
119 }
120
121 const A_matrix_type& A() const {return this->_A;}
122 const B_matrix_type& B() const {return this->_B;}
123 const C_matrix_type& C() const {return this->_C;}
124 const D_matrix_type& D() const {return this->_D;}
125
126 A_matrix_type& A() {return this->_A;}
127 B_matrix_type& B() {return this->_B;}
128 C_matrix_type& C() {return this->_C;}
129 D_matrix_type& D() {return this->_D;}
130
131 friend std::ostream& operator<<(std::ostream& stream, const StateSpace& state_space){
132 stream << "A:\n" << state_space.A() << '\n';
133 stream << "B:\n" << state_space.B() << '\n';
134 stream << "C:\n" << state_space.C() << '\n';
135 stream << "D:\n" << state_space.D() << '\n';
136 return stream;
137 }
138 };
139
199 template<class T, int NumOrder, int DenOrder>
202 const T a_n = rp.den()[rp.den().order()];
203
204 // normalise
205 const Polynom<T, DenOrder> a = -(rp.den() / a_n);
206 const Polynom<T, NumOrder> b = rp.num() / a_n;
207
208 const T bn = (DenOrder > 0 && a.order() == b.order()) ? b.at(b.size()-1) : static_cast<T>(0);
209
210 // write A matrix
211 if constexpr (DenOrder > 0){
212 const auto I = Eigen::Matrix<T, DenOrder-1, DenOrder-1>::Identity();
213 result.A().template block<DenOrder-1, DenOrder-1>(0, 1) = I;
214 result.A().col(0).head(DenOrder-1).setZero();
215 result.A().row(DenOrder-1) = a.vector().head(a.vector().size()-1);
216 }
217
218 // write B matrix
219 if constexpr (DenOrder > 0){
220 result.B().col(0).head(DenOrder-1).setZero();
221 result.B()(DenOrder-1, 0) = T(1);
222 }
223
224 // write C matrix
225 if constexpr (DenOrder > 0){
226 const int l = (b.size() < DenOrder) ? b.size() : DenOrder;
227 if(b.size() > (DenOrder)){
228 result.C().row(0).head(l) = b.vector().head(l) + a.vector().head(l) * bn;
229 }else{
230 result.C().row(0).head(l) = b.vector().head(l);
231 result.C().row(0).tail(DenOrder - b.size()).setZero();
232 }
233 }
234
235 // write D matrix
236 result.D()(0, 0) = (b.size() > (DenOrder)) ? bn : T(0);
237 return result;
238 }
239
244 template<class T, int NumOrder, int DenOrder>
247 const T a_n = rp.den()[rp.den().order()];
248
249 // normalise
250 const Polynom<T, DenOrder> a = -(rp.den() / a_n);
251 const Polynom<T, NumOrder> b = rp.num() / a_n;
252
253 const T bn = (DenOrder > 0 && a.order() == b.order()) ? b.at(b.size()-1) : static_cast<T>(0);
254
255 // write A matrix
256 if constexpr (DenOrder > 0){
257 const auto I = Eigen::Matrix<T, DenOrder-1, DenOrder-1>::Identity();
258 result.A().template block<DenOrder-1, DenOrder-1>(1, 0) = I;
259 result.A().row(0).head(DenOrder-1).setZero();
260 result.A().col(DenOrder-1) = a.vector().head(a.vector().size()-1);
261 }
262
263 // write C matrix
264 if constexpr (DenOrder > 0){
265 result.C().row(0).head(DenOrder-1).setZero();
266 result.C()(0, DenOrder-1) = T(1);
267 }
268
269 // write B matrix
270 if constexpr (DenOrder > 0){
271 const int l = (b.size() < DenOrder) ? b.size() : DenOrder;
272 if(b.size() > (DenOrder)){
273 result.B().col(0).head(l) = b.vector().head(l) + a.vector().head(l) * bn;
274 }else{
275 result.B().col(0).head(l) = b.vector().head(l);
276 result.B().col(0).tail(DenOrder - b.size()).setZero();
277 }
278 }
279
280 // write D matrix
281 result.D()(0, 0) = (b.size() > (DenOrder)) ? bn : T(0);
282 return result;
283 }
284
289 template<class T, int NumOrder, int DenOrder>
293
305 template<class T, int NRows, int NCols, int Opts, int NMaxRows, int NMaxCols>
306 StateSpace<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>
307 to_state_space(const Eigen::Matrix<TransferFunction<T, Eigen::Dynamic, Eigen::Dynamic>, NRows, NCols, Opts, NMaxRows, NMaxCols>& Mtf){
308 // count the number of states for matrix pre-allocation
309 int states = 0;
310 for(int row = 0; row < Mtf.rows(); ++row){
311 for(int col = 0; col < Mtf.cols(); ++col){
312 states += Mtf.at(row, col).den().order();
313 }
314 }
315
316 int inputs = Mtf.cols();
317 int outputs = Mtf.rows();
318
319 // allocate matrices
320 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> A(states, states); A.setZero();
321 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> B(states, inputs); B.setZero();
322 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> C(outputs, states); C.setZero();
323 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> D(outputs, inputs); D.setZero();
324
325 // turn each transfer function into its state space representation and build the total system
326 int state_itr = 0;
327 for(int row = 0; row < Mtf.rows(); ++row){
328 for(int col = 0; col < Mtf.cols(); ++col){
330 A.block(state_itr, state_itr, ss.states(), ss.states()) = ss.A();
331 B.block(state_itr, col, ss.states(), 1) = ss.B();
332 C.block(row, state_itr, 1, ss.states()) = ss.C();
333 D.block(row, col, 1, 1) = ss.D();
334 state_itr += ss.states();
335 }
336 }
338 }
339
349 template<class T, int states>
351 const FixedPolynom<T, states+1> s({0, 1});
352 const auto I = Eigen::Matrix<T, states, states>::Identity();
353 const Eigen::Matrix<FixedPolynom<T, states+1>, states, states> sI_min_A = s * I - css.A();
354 const Eigen::Matrix<FixedPolynom<T, states+1>, states, states> adj_sI_min_A = controlpp::adj(sI_min_A);
355 const FixedPolynom<T, states+1> num = (css.C() * adj_sI_min_A * css.B() + css.D())(0, 0);
356 const FixedPolynom<T, states+1> den = sI_min_A.determinant();
358 }
359
360
361
362/*
363 template<class T, int LStates, int Linputs, int Loutputs, int RStates, int Rinputs, int Routputs>
364 StateSpace<...> operator+(const StateSpace<>& lhs, const StateSpace<>& rhs){
365 // TODO:
366 }
367
368 template<class T, int LStates, int Linputs, int Loutputs, int RStates, int Rinputs, int Routputs>
369 StateSpace<...> operator-(const StateSpace<>& lhs, const StateSpace<>& rhs){
370 // TODO:
371 }
372
373 template<class T, int LStates, int Linputs, int Loutputs, int RStates, int Rinputs, int Routputs>
374 StateSpace<...> operator*(const StateSpace<>& lhs, const StateSpace<>& rhs){
375 // TODO:
376 }
377
378 template<class T, int LStates, int Linputs, int Loutputs, int RStates, int Rinputs, int Routputs>
379 StateSpace<...> operator/(const StateSpace<>& lhs, const StateSpace<>& rhs){
380 // TODO:
381 }
382
383 template<class T, int LStates, int Linputs, int Loutputs, int RStates, int Rinputs, int Routputs>
384 StateSpace<...> inverse(const StateSpace<>& Sys){
385 // TODO:
386 }
387*/
388} // nam
Describes a mathematical polynomial of fixed size.
Definition Polynom.hpp:665
vector_type & vector()
Returns the underlying vector that holds the values.
Definition Polynom.hpp:827
Describes a mathematical polynomial.
Definition Polynom.hpp:39
size_t size() const
returns the size of the polynomial
Definition Polynom.hpp:207
const T & at(size_t i) const
Access elements at the i-th position.
Definition Polynom.hpp:179
vector_type & vector()
Returns the underlying vector that holds the values.
Definition Polynom.hpp:198
size_t order() const
returns the order of the polynomial
Definition Polynom.hpp:212
Base class for the state space representation of a linear time invariant system.
Definition StateSpace.hpp:31
Eigen::Matrix< T, NStates, NInputs > B_matrix_type
Definition StateSpace.hpp:36
StateSpace(const StateSpace &)=default
B_matrix_type & B()
Definition StateSpace.hpp:127
const A_matrix_type & A() const
Definition StateSpace.hpp:121
Eigen::Matrix< T, NOutputs, NStates > C_matrix_type
Definition StateSpace.hpp:37
std::tuple< Eigen::Vector< U, NStates >, Eigen::Vector< U, NOutputs > > eval(const Eigen::Vector< U, NStates > &x, const U &u_scalar) const
calculates the new system states and outupts for SISO (single input, single output) systems
Definition StateSpace.hpp:96
const B_matrix_type & B() const
Definition StateSpace.hpp:122
StateSpace(const Eigen::Matrix< T, NStates, NStates > &A, const Eigen::Matrix< T, NStates, NInputs > &B, const Eigen::Matrix< T, NOutputs, NStates > &C, const Eigen::Matrix< T, NOutputs, NInputs > &D)
Definition StateSpace.hpp:55
A_matrix_type & A()
Definition StateSpace.hpp:126
D_matrix_type & D()
Definition StateSpace.hpp:129
std::tuple< Eigen::Vector< T, NStates >, Eigen::Vector< T, NOutputs > > eval(const Eigen::Vector< T, NStates > &x, const Eigen::Vector< T, NInputs > &u) const
calculates the new system states and outupts
Definition StateSpace.hpp:76
const D_matrix_type & D() const
Definition StateSpace.hpp:124
T value_type
Definition StateSpace.hpp:33
Eigen::Matrix< T, NOutputs, NInputs > D_matrix_type
Definition StateSpace.hpp:38
const C_matrix_type & C() const
Definition StateSpace.hpp:123
StateSpace & operator=(const StateSpace &)=default
std::tuple< Eigen::Vector< U, NStates >, U > eval(const Eigen::Vector< U, NStates > &x, const U &u_scalar) const
calculates the new system states and outupts for SISO (single input, single output) systems
Definition StateSpace.hpp:115
Eigen::Matrix< T, NStates, NStates > A_matrix_type
Definition StateSpace.hpp:35
C_matrix_type & C()
Definition StateSpace.hpp:128
friend std::ostream & operator<<(std::ostream &stream, const StateSpace &state_space)
Definition StateSpace.hpp:131
Definition TransferFunction.hpp:11
constexpr Polynom< T, DenOrder > & den()
returns a reference to the denominator
Definition TransferFunction.hpp:83
constexpr Polynom< T, NumOrder > & num()
returns a reference to the numerator
Definition TransferFunction.hpp:57
The main namespace for the Control++ library.
Definition Bode.cpp:3
ContinuousTransferFunction< T, states+1, states+1 > to_transfer_function(const ContinuousStateSpace< T, states, 1, 1 > &dss)
Transforms a discrete state space system to a discrete transfer function.
Definition ContinuousStateSpace.hpp:101
Eigen::Matrix< T, Rows, Cols > adj(const Eigen::Matrix< T, Rows, Cols, Options, MaxRows, MaxCols > &A)
Definition math.hpp:263
StateSpace< T, DenOrder, 1, 1 > to_state_space_observer_norm(const TransferFunction< T, NumOrder, DenOrder > &rp)
calculates the observer-normed state space representation from a rational polynomial
Definition StateSpace.hpp:245
StateSpace< T, DenOrder, 1, 1 > to_state_space_controller_norm(const TransferFunction< T, NumOrder, DenOrder > &rp)
calculates the control-normed state space representation from a rational polynomial
Definition StateSpace.hpp:200
ContinuousStateSpace< T, DenOrder, 1, 1 > to_state_space(const ContinuousTransferFunction< T, NumOrder, DenOrder > &ctf)
constructs a continuous state space function from a continuous transfer function
Definition ContinuousStateSpace.hpp:91