| 113 | | CHECK_CLOSE_EX(lq.ctrlaction(vec("1,0")), vec("1.24, -5.6"), 0.0000001); |
| 114 | | } |
| | 113 | CHECK_CLOSE_EX(lq.ctrlaction(vec("1,0")), vec("1.24, -5.6"), 0.0000001);*/ |
| | 114 | } |
| | 115 | |
| | 116 | TEST (lqguniversal_test){ |
| | 117 | //test of universal LQG controller |
| | 118 | LQG_universal lq; |
| | 119 | lq.rv = RV("u", 2, 0); |
| | 120 | lq.set_rvc(RV("x", 2, 0)); |
| | 121 | lq.horizon = 10; |
| | 122 | |
| | 123 | /* |
| | 124 | model: x = Ax + Bu time: 0..horizon |
| | 125 | loss: l = x'Q'Qx + u'R'Ru time: 0..horizon-1 |
| | 126 | final loss: l = x'S'Sx time: horizon |
| | 127 | |
| | 128 | dim: x: 2 |
| | 129 | u: 2 |
| | 130 | |
| | 131 | A = [ 2 -1 ] |
| | 132 | [ 0 0.5 ] |
| | 133 | |
| | 134 | B = [ 1 -0.1 ] |
| | 135 | [ -0.2 2 ] |
| | 136 | |
| | 137 | Q = [ 5 0 ] |
| | 138 | [ 0 1 ] |
| | 139 | |
| | 140 | R = [ 0.01 0 ] |
| | 141 | [ 0 0.1 ] |
| | 142 | |
| | 143 | S = Q |
| | 144 | */ |
| | 145 | |
| | 146 | //mat mA("2 -1;0 0.5"); |
| | 147 | //mat mB("1 -0.1;-0.2 2"); |
| | 148 | //mat mQ("5 0;0 1"); |
| | 149 | //mat mR("0.01 0;0 0.1"); |
| | 150 | //mat mS = mQ; |
| | 151 | |
| | 152 | ////starting configuration |
| | 153 | //vec x0("6 3"); |
| | 154 | |
| | 155 | //uniform random generator |
| | 156 | Uniform_RNG urng; |
| | 157 | double maxmult = 10; |
| | 158 | vec tmpdiag; |
| | 159 | |
| | 160 | mat mA; |
| | 161 | urng.sample_matrix(2, 2, mA); |
| | 162 | mA *= maxmult; |
| | 163 | mat mB; |
| | 164 | urng.sample_matrix(2, 2, mB); |
| | 165 | mB *= maxmult; |
| | 166 | mat mQ(2, 2); |
| | 167 | urng.sample_vector(2, tmpdiag); |
| | 168 | tmpdiag *= maxmult; |
| | 169 | mQ.zeros(); |
| | 170 | mQ.set(0, 0, tmpdiag.get(0)); |
| | 171 | mQ.set(1, 1, tmpdiag.get(1)); |
| | 172 | mat mR(2, 2); |
| | 173 | urng.sample_vector(2, tmpdiag); |
| | 174 | tmpdiag *= maxmult; |
| | 175 | mR.zeros(); |
| | 176 | mR.set(0, 0, tmpdiag.get(0)); |
| | 177 | mR.set(1, 1, tmpdiag.get(1)); |
| | 178 | mat mS(2, 2); |
| | 179 | urng.sample_vector(2, tmpdiag); |
| | 180 | tmpdiag *= maxmult; |
| | 181 | mS.zeros(); |
| | 182 | mS.set(0, 0, tmpdiag.get(0)); |
| | 183 | mS.set(1, 1, tmpdiag.get(1)); |
| | 184 | |
| | 185 | //starting configuration |
| | 186 | vec x0; |
| | 187 | urng.sample_vector(2, x0); |
| | 188 | x0 *= maxmult; |
| | 189 | |
| | 190 | /*cout << "configuration:" << endl |
| | 191 | << "mA:" << endl << mA << endl |
| | 192 | << "mB:" << endl << mB << endl |
| | 193 | << "mQ:" << endl << mQ << endl |
| | 194 | << "mR:" << endl << mR << endl |
| | 195 | << "mS:" << endl << mS << endl |
| | 196 | << "x0:" << endl << x0 << endl;*/ |
| | 197 | |
| | 198 | //model |
| | 199 | Array<linfnEx> model(2); |
| | 200 | //model Ax part |
| | 201 | model(0).A = mA; |
| | 202 | model(0).B = vec("0 0"); |
| | 203 | model(0).rv = RV("x", 2, 0); |
| | 204 | model(0).rv_ret = RV("x", 2, 1); |
| | 205 | //model Bu part |
| | 206 | model(1).A = mB; |
| | 207 | model(1).B = vec("0 0"); |
| | 208 | model(1).rv = RV("u", 2, 0); |
| | 209 | model(1).rv_ret = RV("x", 2, 1); |
| | 210 | //setup |
| | 211 | lq.Models = model; |
| | 212 | |
| | 213 | //loss |
| | 214 | Array<quadraticfn> loss(2); |
| | 215 | //loss x'Qx part |
| | 216 | loss(0).Q.setCh(mQ); |
| | 217 | loss(0).rv = RV("x", 2, 0); |
| | 218 | //loss u'Ru part |
| | 219 | loss(1).Q.setCh(mR); |
| | 220 | loss(1).rv = RV("u", 2, 0); |
| | 221 | //setup |
| | 222 | lq.Losses = loss; |
| | 223 | |
| | 224 | //finalloss setup |
| | 225 | lq.finalLoss.Q.setCh(mS); |
| | 226 | lq.finalLoss.rv = RV("x", 2, 1); |
| | 227 | |
| | 228 | //default L |
| | 229 | //cout << "default L matrix:" << endl << lq.getL() << endl; |
| | 230 | |
| | 231 | //produce last control matrix L |
| | 232 | lq.redesign(); |
| | 233 | |
| | 234 | //verification via Riccati LQG version |
| | 235 | mat mK = mS; |
| | 236 | mat mL = - inv(mR + mB.transpose() * mK * mB) * mB.transpose() * mK * mA; |
| | 237 | |
| | 238 | //cout << "L matrix LQG_universal:" << endl << lq.getL() << endl << |
| | 239 | //"L matrix LQG Riccati:" << endl << mL << endl; |
| | 240 | |
| | 241 | //checking L matrix (universal vs Riccati), tolerance is high, but L is not main criterion |
| | 242 | //more important is reached loss compared in the next part |
| | 243 | double tolerr = 1;//0.01; //0.01 OK x 0.001 NO OK |
| | 244 | |
| | 245 | //check last time L matrix |
| | 246 | CHECK_CLOSE_EX(lq.getL().get_cols(0,1), mL, tolerr); |
| | 247 | |
| | 248 | mat oldK; |
| | 249 | int i; |
| | 250 | |
| | 251 | //produce next control matrix L |
| | 252 | for(i = 0; i < lq.horizon - 1; i++) { |
| | 253 | lq.redesign(); |
| | 254 | oldK = mK; |
| | 255 | mK = mA.transpose() * (oldK - oldK * mB * inv(mR + mB.transpose() * oldK * mB) * mB.transpose() * oldK) * mA + mQ; |
| | 256 | mL = - inv(mR + mB.transpose() * mK * mB) * mB.transpose() * mK * mA; |
| | 257 | |
| | 258 | //cout << "L matrix LQG_universal:" << endl << lq.getL() << endl << |
| | 259 | //"L matrix LQG Riccati:" << endl << mL << endl; |
| | 260 | |
| | 261 | //check other times L matrix |
| | 262 | CHECK_CLOSE_EX(lq.getL().get_cols(0,1), mL, tolerr); |
| | 263 | } |
| | 264 | |
| | 265 | //check losses of LQG control - compare LQG_universal and Riccati version, no noise |
| | 266 | |
| | 267 | //loss of LQG_universal |
| | 268 | /*double*/vec loss_uni("0"); |
| | 269 | |
| | 270 | //setup |
| | 271 | vec x = x0; |
| | 272 | vec xold = x; |
| | 273 | vec u; |
| | 274 | //vec tmploss; |
| | 275 | |
| | 276 | //iteration |
| | 277 | for(i = 0; i < lq.horizon - 1; i++){ |
| | 278 | u = lq.getL().get_cols(0,1) * xold; |
| | 279 | x = mA * xold + mB * u; |
| | 280 | /*tmploss*/loss_uni = x.transpose() * mQ * x + u.transpose() * mR * u; |
| | 281 | //loss_uni += tmploss.get(0); |
| | 282 | xold = x; |
| | 283 | } |
| | 284 | /*tmploss*/ loss_uni = x.transpose() * mS * x; |
| | 285 | //loss_uni += tmploss.get(0); |
| | 286 | |
| | 287 | //loss of LQG Riccati version |
| | 288 | /*double*/ vec loss_rct("0"); |
| | 289 | |
| | 290 | //setup |
| | 291 | x = x0; |
| | 292 | xold = x; |
| | 293 | |
| | 294 | //iteration |
| | 295 | for(i = 0; i < lq.horizon - 1; i++){ |
| | 296 | u = mL * xold; |
| | 297 | x = mA * xold + mB * u; |
| | 298 | /*tmploss*/loss_rct = x.transpose() * mQ * x + u.transpose() * mR * u; |
| | 299 | //loss_rct += tmploss.get(0); |
| | 300 | xold = x; |
| | 301 | } |
| | 302 | /*tmploss*/loss_rct = x.transpose() * mS * x; |
| | 303 | //loss_rct += tmploss.get(0); |
| | 304 | |
| | 305 | //cout << "Loss LQG_universal: " << loss_uni << " vs Loss LQG Riccati: " << loss_rct << endl; |
| | 306 | CHECK_CLOSE_EX(loss_uni, loss_rct, 0.0001); |
| | 307 | } |