Controlpp
Loading...
Searching...
No Matches
H2Controller.hpp
Go to the documentation of this file.
1#pragma once
2
3// Eigen
4#include <Eigen/Core>
5#include <Eigen/Dense>
6#include <Eigen/Eigenvalues>
7#include <Eigen/Cholesky>
8
9// controlpp
10#include <controlpp/math.hpp>
12
13namespace controlpp
14{
15 template<class T, int NStates, int NInputs, int NPerfOutputs, int NMeasOutputs, int NDisturbances>
17 const Eigen::Matrix<T, NStates, NStates>& A,
18 const Eigen::Matrix<T, NStates, NDisturbances>& Bw,
19 const Eigen::Matrix<T, NStates, NInputs>& Bu,
20 const Eigen::Matrix<T, NPerfOutputs, NStates>& Cz,
21 const Eigen::Matrix<T, NPerfOutputs, NInputs>& Duz,
22 const Eigen::Matrix<T, NMeasOutputs, NStates>& Cy,
23 const Eigen::Matrix<T, NMeasOutputs, NDisturbances>& Dwy,
24 const Eigen::Matrix<T, NInputs, NInputs>& R,
25 const Eigen::Matrix<T, NMeasOutputs, NMeasOutputs>& S
26 ){
27
28 // Weighting Matrices
29 const Eigen::Matrix<T, NStates, NStates> Q = Cz.transpose() * Cz;
30 const Eigen::Matrix<T, NStates, NStates> W = Bw * Bw.transpose();
31
32
33 // State feedback
34 // A^\top X + X A - X B_u R^{-1} B_u^\top X + Q = 0
35 const Eigen::Matrix<T, NStates, NInputs> N1 = Cz.transpose() * Duz;
36 const Eigen::Matrix<T, NStates, NStates> X = controlpp::care_solver(A, Bu, Q, R, N1);
37
38 // Estimator Feedback
39 // A Y + Y A^\top - Y C_y^\top S^{-1} C_y Y + W = 0
40 const Eigen::Matrix<T, NStates, NMeasOutputs> N2 = Bw * Dwy.transpose();
41 const Eigen::Matrix<T, NStates, NStates> Y = controlpp::care_solver(A.transpose().eval(), Cy.transpose().eval(), W, S, N2);
42
43 // State gain
44 // F = -R^{-1} \left( B_u^\top X + D_{1u}^\top C_z \right)
45 const Eigen::Matrix<T, NInputs, NStates> F = -R.ldlt().solve(Bu.transpose() * X + Duz.transpose() * Cz);
46
47 // Estimator gain
48 // L = - \left( Y C_y^\top + B_w D_{2w}^\top \right) S^{-1}
49 const Eigen::Matrix<T, NStates, NMeasOutputs> M = Y * Cy.transpose() + Bw * Dwy.transpose();
50 const Eigen::Matrix<T, NStates, NMeasOutputs> L = -S.ldlt().solve(M.transpose()).transpose();
51
52 // Construct the H2 Controller
53 const Eigen::Matrix<T, NStates, NStates> A_K = A + Bu * F + L * Cy;
54 const Eigen::Matrix<T, NStates, NMeasOutputs> B_K = -L;
55 const Eigen::Matrix<T, NInputs, NStates> C_K = F;
56
58 return H2;
59 }
60
185 template<class T, int NStates, int NInputs, int NPerfOutputs, int NMeasOutputs, int NDisturbances>
186 requires(NInputs>1 && NMeasOutputs>1)
188 const Eigen::Matrix<T, NStates, NStates>& A,
189 const Eigen::Matrix<T, NStates, NDisturbances>& Bw,
190 const Eigen::Matrix<T, NStates, NInputs>& Bu,
191 const Eigen::Matrix<T, NPerfOutputs, NStates>& Cz,
192 const Eigen::Matrix<T, NPerfOutputs, NInputs>& Duz,
193 const Eigen::Matrix<T, NMeasOutputs, NStates>& Cy,
194 const Eigen::Matrix<T, NMeasOutputs, NDisturbances>& Dwy,
195 const Eigen::Vector<T, NInputs> r = Eigen::Vector<T, NInputs>::Zero(),
196 const Eigen::Vector<T, NMeasOutputs> s = Eigen::Vector<T, NMeasOutputs>::Zero()
197 ){
198
199 // Weighting Matrices
200 const Eigen::Matrix<T, NInputs, NInputs> R = Duz.transpose() * Duz + Eigen::DiagonalMatrix<T, NInputs>(r.array() * r.array()).toDenseMatrix();
201 const Eigen::Matrix<T, NMeasOutputs, NMeasOutputs> S = (Dwy * Dwy.transpose() + Eigen::DiagonalMatrix<T, NMeasOutputs>(s.array() * s.array()).toDenseMatrix()).eval();
202
203 return continous_h2(A, Bw, Bu, Cz, Duz, Cy, Dwy, R, S);
204 }
205
210 template<class T, int NStates, int NInputs, int NPerfOutputs, int NMeasOutputs, int NDisturbances>
212 const Eigen::Matrix<T, NStates, NStates>& A,
213 const Eigen::Matrix<T, NStates, NDisturbances>& Bw,
214 const Eigen::Matrix<T, NStates, NInputs>& Bu,
215 const Eigen::Matrix<T, NPerfOutputs, NStates>& Cz,
216 const Eigen::Matrix<T, NPerfOutputs, NInputs>& Duz,
217 const Eigen::Matrix<T, NMeasOutputs, NStates>& Cy,
218 const Eigen::Matrix<T, NMeasOutputs, NDisturbances>& Dwy,
219 const T& r_scalar = 0,
220 const T& s_scalar = 0
221 ){
222
223 // Weighting Vectors
224 const Eigen::Vector<T, NInputs> r = Eigen::Vector<T, NInputs>::Constant(static_cast<T>(r_scalar * r_scalar));
225 const Eigen::Vector<T, NMeasOutputs> s = Eigen::Vector<T, NMeasOutputs>::Constant(static_cast<T>(s_scalar * s_scalar));
226
227 // Weighting Matrices
228 const Eigen::Matrix<T, NInputs, NInputs> R = Duz.transpose() * Duz + Eigen::DiagonalMatrix<T, NInputs>(r).toDenseMatrix();
229 const Eigen::Matrix<T, NMeasOutputs, NMeasOutputs> S = (Dwy * Dwy.transpose() + Eigen::DiagonalMatrix<T, NMeasOutputs>(s).toDenseMatrix()).eval();
230
231
232 return continous_h2(A, Bw, Bu, Cz, Duz, Cy, Dwy, R, S);
233 }
234
238 template<class T, int NStates, int NInputs=1, int NPerfOutputs=1, int NMeasOutputs=1, int NDisturbances=1>
240 Eigen::Matrix<T, NStates, NStates> A;
241 Eigen::Matrix<T, NStates, NDisturbances> Bw;
242 Eigen::Matrix<T, NStates, NInputs> Bu;
243 Eigen::Matrix<T, NPerfOutputs, NStates> Cz;
244 Eigen::Matrix<T, NPerfOutputs, NInputs> Duz;
245 Eigen::Matrix<T, NMeasOutputs, NStates> Cy;
246 Eigen::Matrix<T, NMeasOutputs, NDisturbances> Dwy;
247 };
248
249 template<class T, int NStates, int NInputs=1, int NPerfOutputs=1, int NMeasOutputs=1, int NDisturbances=1>
251 stream << "A:\n" << G.A << "\n";
252 stream << "Bw:\n" << G.Bw << "\n";
253 stream << "Bu:\n" << G.Bu << "\n";
254 stream << "Cz:\n" << G.Cz << "\n";
255 stream << "Duz:\n" << G.Duz << "\n";
256 stream << "Cy:\n" << G.Cy << "\n";
257 stream << "Dwy:\n" << G.Dwy << "\n";
258 return stream;
259 };
260
273 template<class T, int NStates, int NInputs, int NPerfOutputs, int NMeasOutputs, int NDisturbances>
276 const Eigen::Vector<T, NInputs>& control_penalty = Eigen::Vector<T, NInputs>::Zero(),
277 const Eigen::Vector<T, NMeasOutputs>& measurement_noise = Eigen::Vector<T, NMeasOutputs>::Zero()
278 ){
279 return continous_h2(
280 Gss.A, Gss.Bw, Gss.Bu,
281 Gss.Cz, Gss.Duz,
282 Gss.Cy, Gss.Dwy,
283 control_penalty, measurement_noise
284 );
285 }
286
287 template<class T, int NStates, int NInputs, int NPerfOutputs, int NMeasOutputs, int NDisturbances>
290 const T& control_penalty = static_cast<T>(0),
291 const T& measurement_noise = static_cast<T>(0)
292 ){
293 return continous_h2(
294 Gss.A, Gss.Bw, Gss.Bu,
295 Gss.Cz, Gss.Duz,
296 Gss.Cy, Gss.Dwy,
297 control_penalty, measurement_noise
298 );
299 }
300
336 template<class T,
337 int PNumOrder, int PDenOrder,
338 int MNumOrder, int MDenOrder,
339 int WdNumOrder, int WdDenOrder,
340 int WzNumOrder, int WzDenOrder>
346 const T& control_penalty,
347 const T& measurement_noise
348 ){
349 constexpr int NStates = PDenOrder + MDenOrder + WdDenOrder + WzDenOrder;
350 constexpr int NInputs = 1;
351 constexpr int NPerfOutputs = 1;
352 constexpr int NMeasOutputs = 1;
353 constexpr int NDisturbances = 1;
354
355 const auto P_ss = to_state_space(P);
356 const auto M_ss = to_state_space(M);
357 const auto Wd_ss = to_state_space(Wd);
358 const auto Wz_ss = to_state_space(Wz);
359
361
362 Gp.A.setZero();
363
364 // A: digonal elements
365 Gp.A.template block<PDenOrder, PDenOrder>(0, 0) = P_ss.A();
366 Gp.A.template block<WdDenOrder, WdDenOrder>(PDenOrder, PDenOrder) = Wd_ss.A();
367 Gp.A.template block<WzDenOrder, WzDenOrder>(PDenOrder + WdDenOrder, PDenOrder + WdDenOrder) = Wz_ss.A();
368 Gp.A.template block<MDenOrder, MDenOrder>(PDenOrder + WdDenOrder + WzDenOrder, PDenOrder + WdDenOrder + WzDenOrder) = M_ss.A();
369
370 // A: Off diagonal elements
371 const Eigen::Matrix<T, WzDenOrder, PDenOrder> BzCp = Wz_ss.B() * P_ss.C();
372 Gp.A.template block<WzDenOrder, PDenOrder>(PDenOrder + WdDenOrder, 0) = BzCp;
373
374 const Eigen::Matrix<T, WzDenOrder, WdDenOrder> BzCd = Wz_ss.B() * Wd_ss.C();
375 Gp.A.template block<WzDenOrder, WdDenOrder>(PDenOrder + WdDenOrder, PDenOrder) = BzCd;
376
377 const Eigen::Matrix<T, MDenOrder, PDenOrder> BmCp = M_ss.B() * P_ss.C();
378 Gp.A.template block<MDenOrder, PDenOrder>(PDenOrder + WdDenOrder, 0) = BmCp;
379
380 const Eigen::Matrix<T, MDenOrder, WdDenOrder> BmCd = M_ss.B() * Wd_ss.C();
381 Gp.A.template block<MDenOrder, WdDenOrder>(PDenOrder + WdDenOrder, PDenOrder) = BmCd;
382
383 // Bw: disturbance input
384 Gp.Bw.setZero();
385 Gp.Bw.template block<WdDenOrder, 1>(PDenOrder, 0) = Wd_ss.B();
386
387 // Bu: control input
388 Gp.Bu.setZero();
389 Gp.Bu.template block<PDenOrder, 1>(0, 0) = P_ss.B();
390
391 // Cz: performance output
392 Gp.Cz.setZero();
393 Gp.Cz.template block<1, WzDenOrder>(0, PDenOrder + WdDenOrder) = Wz_ss.C();
394
395 // Cy: measurement output
396 Gp.Cy.setZero();
397 Gp.Cy.template block<1, MDenOrder>(0, PDenOrder + WdDenOrder + WzDenOrder) = M_ss.C();
398
399 // Direct pass throughs
400 Gp.Duz.setZero();
401 Gp.Dwy(0, 0) = measurement_noise;
402
404 return h2;
405 }
406
407
408
409} // namespace controlpp
Definition ContinuousStateSpace.hpp:10
Continuous transfer functions in the s lapace plain.
Definition ContinuousTransferFunction.hpp:28
The main namespace for the Control++ library.
Definition Bode.cpp:3
ContinuousStateSpace< T, NStates, NMeasOutputs, NInputs > continuous_h2(const ContinuousGeneralisedPlant< T, NStates, NInputs, NPerfOutputs, NMeasOutputs, NDisturbances > &Gss, const Eigen::Vector< T, NInputs > &control_penalty=Eigen::Vector< T, NInputs >::Zero(), const Eigen::Vector< T, NMeasOutputs > &measurement_noise=Eigen::Vector< T, NMeasOutputs >::Zero())
Constructs a continuous H2 controller from a continuous state space plant model.
Definition H2Controller.hpp:274
std::ostream & operator<<(std::ostream &stream, EBodeCsvReadError val)
Definition Bode.cpp:5
ContinuousStateSpace< T, NStates, NMeasOutputs, NInputs > continous_h2(const Eigen::Matrix< T, NStates, NStates > &A, const Eigen::Matrix< T, NStates, NDisturbances > &Bw, const Eigen::Matrix< T, NStates, NInputs > &Bu, const Eigen::Matrix< T, NPerfOutputs, NStates > &Cz, const Eigen::Matrix< T, NPerfOutputs, NInputs > &Duz, const Eigen::Matrix< T, NMeasOutputs, NStates > &Cy, const Eigen::Matrix< T, NMeasOutputs, NDisturbances > &Dwy, const Eigen::Matrix< T, NInputs, NInputs > &R, const Eigen::Matrix< T, NMeasOutputs, NMeasOutputs > &S)
Definition H2Controller.hpp:16
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
Eigen::Matrix< T, NStates, NStates > care_solver(const Eigen::Matrix< T, NStates, NStates, AOpt, AMaxR, AMaxC > &A, const Eigen::Matrix< T, NStates, NInputs, BOpt, BMaxR, BMaxC > &B, const Eigen::Matrix< T, NStates, NStates, QOpt, QMaxR, QMaxC > &Q, const Eigen::Matrix< T, NInputs, NInputs, ROpt, RMaxR, RMaxC > &R)
Solves the continuous time riccati equation (CARE)
Definition math.hpp:608
A continuous generalised plant model.
Definition H2Controller.hpp:239
Eigen::Matrix< T, NMeasOutputs, NStates > Cy
Definition H2Controller.hpp:245
Eigen::Matrix< T, NStates, NDisturbances > Bw
Definition H2Controller.hpp:241
Eigen::Matrix< T, NStates, NStates > A
Definition H2Controller.hpp:240
Eigen::Matrix< T, NMeasOutputs, NDisturbances > Dwy
Definition H2Controller.hpp:246
Eigen::Matrix< T, NPerfOutputs, NInputs > Duz
Definition H2Controller.hpp:244
Eigen::Matrix< T, NStates, NInputs > Bu
Definition H2Controller.hpp:242
Eigen::Matrix< T, NPerfOutputs, NStates > Cz
Definition H2Controller.hpp:243