ROBOOP, A Robotics Object Oriented Package in C++
utils.cpp
Go to the documentation of this file.
1 /*
2 ROBOOP -- A robotics object oriented package in C++
3 Copyright (C) 1996-2004 Richard Gourdeau
4 
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9 
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 
19 
20 Report problems and direct all questions to:
21 
22 Richard Gourdeau, Professeur
23 Departement de genie electrique
24 Ecole Polytechnique de Montreal
25 C.P. 6079, Succ. Centre-Ville
26 Montreal, Quebec, H3C 3A7
27 
28 email: richard.gourdeau@polymtl.ca
29 
30 -------------------------------------------------------------------------------
31 Revision_history:
32 
33 2003/02/03: Etienne Lachance
34  -Added functions x_prod_matrix, vec_dot_prod, Integ_Trap and sign.
35  -Working on Runge_Kutta4_etienne.
36 
37 2004/07/01: Etienne Lachance
38  -Removed function vec_x_prod and vec_dot_prod. Now we use CrossProduct
39  and DotProduct, from Newmat library.
40  -Added doxygen documentation.
41 
42 2004/07/01: Ethan Tira-Thompson
43  -Added support for newmat's use_namespace #define, using ROBOOP namespace
44 
45 2005/06/10: Carmine Lia
46  -Added pinv
47 
48 2005/06/29 Richard Gourdeau
49  -Fixed max() bug for VC++ 6.0
50 
51 2007/02/15 Richard Gourdeau
52  -Fixed bug in short sign(const Real x)
53 -------------------------------------------------------------------------------
54 */
55 
61 #include "utils.h"
62 
63 #ifdef _MSC_VER
64 #if _MSC_VER < 1300 // Microsoft
65 #ifndef GUARD_minmax_H
66 #define GUARD_minmax_H
67 // needed to cope with bug in MS library:
68 // it fails to define min/max
69 template <class T> inline T max(const T& a, const T& b)
70 {
71  return (a > b) ? a : b;
72 }
73 template <class T> inline T min(const T& a, const T& b)
74 {
75  return (a < b) ? a : b;
76 }
77 #endif
78 #endif
79 #endif
80 
81 #ifdef use_namespace
82 namespace ROBOOP {
83  using namespace NEWMAT;
84 #endif
85 
86 
87 ReturnMatrix x_prod_matrix(const ColumnVector & x)
89 {
90  Matrix S(3,3); S = 0.0;
91  S(1,2) = -x(3); S(1,3) = x(2);
92  S(2,1) = x(3); S(2,3) = -x(1);
93  S(3,1) = -x(2); S(3,2) = x(1);
94 
95  S.Release(); return (S);
96 }
97 
98 ReturnMatrix pinv(const Matrix & M)
120 {
121  /* floating point eps */
122  const Real eps = numeric_limits<Real>::epsilon();
123 
124  int m = M.nrows();
125  int n = M.ncols();
126 
127  if(n > m)
128  {
129  Matrix X = pinv(M.t()).t();
130  return X;
131  }
132 
133  Matrix U, V;
134 
135  DiagonalMatrix Q;
136 
137  Matrix X(n, m);
138 
139  SVD(M, Q, U, V);
140  //cout << "Q\n" << Q << "U\n" << U << "V\n" << V << endl;
141  Real tol = max(m,n)*Q(1)*eps;
142  // cout << "\ntol\n" << tol << "\neps\n" << eps << endl;
143  // conteggio dei sv != 0
144  int r = 0;
145  for(int i = 1; i <= Q.size(); i++)
146  if(Q(i) > tol)
147  r++;
148 
149  if(r != 0)
150  {
151  DiagonalMatrix D(r);
152  for(int i = 1; i <= r; i++)
153  D(i) = 1/Q(i);
154  //cout << V.SubMatrix(1,V.nrows(),1,r) << endl;
155  //cout << D << endl;
156  //cout << U.SubMatrix(1,U.nrows(),1,r).t() << endl;
157  X = V.SubMatrix(1,V.nrows(),1,r)*D*U.SubMatrix(1,U.nrows(),1,r).t();
158 
159  }
160  X.Release();
161  return X;
162 }
163 
164 ReturnMatrix Integ_Trap(const ColumnVector & present, ColumnVector & past,
165  const Real dt)
167 {
168  ColumnVector integration(present.Nrows());
169  integration = (past+present)*0.5*dt;
170  past = present;
171 
172  integration.Release();
173  return ( integration );
174 }
175 
176 
177 void Runge_Kutta4_Real_time(ReturnMatrix (*xdot)(Real time, const Matrix & xin,
178  bool & exit, bool & init),
179  const Matrix & xo, Real to, Real tf, int nsteps)
181 {
182  static Real h, h2, t;
183  static Matrix k1, k2, k3, k4, x;
184  static bool first_pass = true, init = false, exit = false;
185 
186  if(first_pass || init)
187  {
188  h = (tf-to)/nsteps;
189  h2 = h/2.0;
190  t = to;
191  x = xo;
192  first_pass = false;
193  }
194  k1 = (*xdot)(t, x, exit, init) * h;
195  if(exit) return;
196  k2 = (*xdot)(t+h2, x+k1*0.5, exit, init)*h;
197  if(exit) return;
198  k3 = (*xdot)(t+h2, x+k2*0.5, exit, init)*h;
199  if(exit) return;
200  k4 = (*xdot)(t+h, x+k3, exit, init)*h;
201  if(exit) return;
202  x = x + (k1*0.5+ k2 + k3 + k4*0.5)*(1.0/3.0);
203  t += h;
204 }
205 
206 void Runge_Kutta4_Real_time(ReturnMatrix (*xdot)(const Real time, const Matrix & xin),
207  const Matrix & xo, const Real to, const Real tf, const int nsteps)
208 {
209  static Real h, h2, t;
210  static Matrix k1, k2, k3, k4, x;
211  static bool first_pass = true;
212 
213  if(first_pass)
214  {
215  h = (tf-to)/nsteps;
216  h2 = h/2.0;
217  t = to;
218  x = xo;
219  first_pass = false;
220  }
221  k1 = (*xdot)(t, x) * h;
222  t += h2;
223  k2 = (*xdot)(t, x+k1*0.5)*h;
224  k3 = (*xdot)(t, x+k2*0.5)*h;
225  t += h2;
226  k4 = (*xdot)(t, x+k3)*h;
227  x = x + (k1*0.5+ k2 + k3 + k4*0.5)*(1.0/3.0);
228 }
229 
230 
231 void Runge_Kutta4(ReturnMatrix (*xdot)(Real time, const Matrix & xin),
232  const Matrix & xo, Real to, Real tf, int nsteps,
233  RowVector & tout, Matrix & xout)
235 {
236  Real h, h2, t;
237  Matrix k1, k2, k3, k4, x;
238 
239  h = (tf-to)/nsteps;
240  h2 = h/2.0;
241  t = to;
242  x = xo;
243  xout = Matrix(xo.Nrows(),(nsteps+1)*xo.Ncols());
244  xout.SubMatrix(1,xo.Nrows(),1,xo.Ncols()) = x;
245  tout = RowVector(nsteps+1);
246  tout(1) = to;
247  for (int i = 1; i <= nsteps; i++) {
248  k1 = (*xdot)(t, x) * h;
249  k2 = (*xdot)(t+h2, x+k1*0.5)*h;
250  k3 = (*xdot)(t+h2, x+k2*0.5)*h;
251  k4 = (*xdot)(t+h, x+k3)*h;
252  x = x + (k1*0.5+ k2 + k3 + k4*0.5)*(1.0/3.0);
253  t += h;
254  tout(i+1) = t;
255  xout.SubMatrix(1,xo.Nrows(),i*xo.Ncols()+1,(i+1)*xo.Ncols()) = x;
256  }
257 }
258 
259 ReturnMatrix rk4(const Matrix & x, const Matrix & dxdt, Real t, Real h,
260  ReturnMatrix (*xdot)(Real time, const Matrix & xin))
269 {
270  Matrix xt, xout, dxm, dxt;
271  Real th, hh, h6;
272 
273  hh = h*0.5;
274  h6 = h/6.0;
275  th = t + hh;
276  xt = x + hh*dxdt;
277  dxt = (*xdot)(th,xt);
278  xt = x + hh*dxt;
279  dxm = (*xdot)(th,xt);
280  xt = x + h*dxm;
281  dxm += dxt;
282  dxt = (*xdot)(t+h,xt);
283  xout = x+h6*(dxdt+dxt+2.0*dxm);
284 
285  xout.Release(); return xout;
286 }
287 
288 #define PGROW -0.20
289 #define PSHRNK -0.25
290 #define FCOR 0.06666666
291 #define SAFETY 0.9
292 #define ERRCON 6.0E-4
293 
294 void rkqc(Matrix & x, Matrix & dxdt, Real & t, Real htry,
295  Real eps, Matrix & xscal, Real & hdid, Real & hnext,
296  ReturnMatrix (*xdot)(Real time, const Matrix & xin))
305 {
306  Real tsav, hh, h, temp, errmax;
307  Matrix dxsav, xsav, xtemp;
308 
309  tsav = t;
310  xsav = x;
311  dxsav = dxdt;
312  h = htry;
313  for(;;) {
314  hh = 0.5*h;
315  xtemp = rk4(xsav,dxsav,tsav,hh,xdot);
316  t = tsav+hh;
317  dxdt = (*xdot)(t,xtemp);
318  x = rk4(xtemp,dxdt,t,hh,xdot);
319  t = tsav+h;
320  if(t == tsav) {
321  cerr << "Step size too small in routine RKQC\n";
322  exit(1);
323  }
324  xtemp = rk4(xsav,dxsav,tsav,h,xdot);
325  errmax = 0.0;
326  xtemp = x-xtemp;
327  for(int i = 1; i <= x.Nrows(); i++) {
328  temp = fabs(xtemp(i,1)/xscal(i,1));
329  if(errmax < temp) errmax = temp;
330  }
331  errmax /= eps;
332  if(errmax <= 1.0) {
333  hdid = h;
334  hnext = (errmax > ERRCON ?
335  SAFETY*h*exp(PGROW*log(errmax)) : 4.0*h);
336  break;
337  }
338  h = SAFETY*h*exp(PSHRNK*log(errmax));
339  }
340  x += xtemp*FCOR;
341 }
342 
343 #define MAXSTP 10000
344 #define TINY 1.0e-30
345 
346 void odeint(ReturnMatrix (*xdot)(Real time, const Matrix & xin),
347  Matrix & xo, Real to, Real tf, Real eps, Real h1, Real hmin,
348  int & nok, int & nbad,
349  RowVector & tout, Matrix & xout, Real dtsav)
359 {
360  Real tsav, t, hnext, hdid, h;
361  RowVector tv(1);
362 
363  Matrix xscal, x, dxdt;
364 
365  tv = to;
366  tout = tv;
367  xout = xo;
368  xscal = xo;
369  t = to;
370  h = (tf > to) ? fabs(h1) : -fabs(h1);
371  nok = (nbad) = 0;
372  x = xo;
373  tsav = t;
374  for(int nstp = 1; nstp <= MAXSTP; nstp++){
375  dxdt = (*xdot)(t,x);
376  for(int i = 1; i <= x.Nrows(); i++)
377  xscal(i,1) = fabs(x(i,1))+fabs(dxdt(i,1)*h)+TINY;
378  if((t+h-tf)*(t+h-to) > 0.0) h = tf-t;
379  rkqc(x,dxdt,t,h,eps,xscal,hdid,hnext,xdot);
380  if(hdid == h) ++(nok); else ++(nbad);
381  if((t-tf)*(tf-to) >= 0.0) {
382  xo = x;
383  tv = t;
384  tout = tout | tv;
385  xout = xout | x;
386  return;
387  }
388  if(fabs(t-tsav) > fabs(dtsav)) {
389  tv = t;
390  tout = tout | tv;
391  xout = xout | x;
392  tsav = t;
393  }
394  if(fabs(hnext) <= hmin) {
395  cerr << "Step size too small in ODEINT\n";
396  cerr << setw(7) << setprecision(3) << (tout & xout).t();
397  exit(1);
398  }
399  h = hnext;
400  }
401  cerr << "Too many step in routine ODEINT\n";
402  exit(1);
403 }
404 
405 ReturnMatrix sign(const Matrix & x)
407 {
408  Matrix out = x;
409 
410  for(int i = 1; i <= out.Ncols(); i++) {
411  for(int j = 1; j <= out.Nrows(); j++) {
412  if(out(j,i) > 0.0) {
413  out(j,i) = 1.0;
414  } else if(out(j,i) < 0.0) {
415  out(j,i) = -1.0;
416  }
417  }
418  }
419 
420  out.Release(); return out;
421 }
422 
423 
424 short sign(const Real x)
426 {
427  short i = 1;
428  if(x > 0.0)
429  i = 1;
430  else if(x < 0.0)
431  i = -1;
432  else
433  i = 0;
434 
435  return (i);
436 }
437 
438 #ifdef use_namespace
439 }
440 #endif
441