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 | } |