| 1 | // gyrocalibrator.cc
 | 
|---|
| 2 | // Eric Aubourg         CEA/DAPNIA/SPP   octobre 1999
 | 
|---|
| 3 | 
 | 
|---|
| 4 | // assumption : same calibration for all gyros...
 | 
|---|
| 5 | 
 | 
|---|
| 6 | // Warning, current implementation can only output ONE calibration.
 | 
|---|
| 7 | // workaround : clone the object for different options.
 | 
|---|
| 8 | 
 | 
|---|
| 9 | 
 | 
|---|
| 10 | #include "gyrocalibrator.h"
 | 
|---|
| 11 | #include "archexc.h"
 | 
|---|
| 12 | #include "archparam.h"
 | 
|---|
| 13 | 
 | 
|---|
| 14 | #define gyroCal    "gyroCal"
 | 
|---|
| 15 | #define gyroOffset "gyroOffset"
 | 
|---|
| 16 | #define gyroSpeed  "gyroSpeed"
 | 
|---|
| 17 | 
 | 
|---|
| 18 | GyroCalibrator::GyroCalibrator() {
 | 
|---|
| 19 |   possibleTOIs.insert(TOI(gyroCal,      TOI::all,    "linearCal", "deg/s/V"));  
 | 
|---|
| 20 |   possibleTOIs.insert(TOI(gyroOffset,   TOI::all,    "linearCal", "deg/s/V"));  
 | 
|---|
| 21 |   possibleTOIs.insert(TOI(gyroSpeed,    TOI::all   , "linearCal", "deg/s"));  
 | 
|---|
| 22 |   
 | 
|---|
| 23 |   needAfter = 3600;  // about one turn...
 | 
|---|
| 24 |   startSample = -1;
 | 
|---|
| 25 |   lastRotSpeed = -1;
 | 
|---|
| 26 |   lastFence1 = lastFence2 = -1;
 | 
|---|
| 27 |   for (int i=0; i<3; i++) {
 | 
|---|
| 28 |     lastCalib[i] = -99999;
 | 
|---|
| 29 |     lastOffset[i] = 0;
 | 
|---|
| 30 |   }
 | 
|---|
| 31 |   gyroProducer = NULL;
 | 
|---|
| 32 | }
 | 
|---|
| 33 | 
 | 
|---|
| 34 | string GyroCalibrator::getName() {
 | 
|---|
| 35 |   return("GyroCalibrator 1.0");
 | 
|---|
| 36 | }
 | 
|---|
| 37 | 
 | 
|---|
| 38 | 
 | 
|---|
| 39 | set<TOI> GyroCalibrator::reqTOIFor(TOI const&) {
 | 
|---|
| 40 |   set<TOI> t; 
 | 
|---|
| 41 |   t.insert(TOI("rotSpeed",        TOI::unspec)); // pull only
 | 
|---|
| 42 |   t.insert(TOI("rotSpeedSample1", TOI::unspec)); // pull only
 | 
|---|
| 43 |   t.insert(TOI("rotSpeedSample2", TOI::unspec)); // pull only
 | 
|---|
| 44 |   t.insert(TOI("gyroV", 0));  // push
 | 
|---|
| 45 |   t.insert(TOI("gyroV", 1));  // push
 | 
|---|
| 46 |   t.insert(TOI("gyroV", 2));  // push
 | 
|---|
| 47 |   return t;
 | 
|---|
| 48 | }
 | 
|---|
| 49 | 
 | 
|---|
| 50 | void GyroCalibrator::dataFeed(TOIProducer* , TOI const& toi, long sampleNum, double value) {
 | 
|---|
| 51 |  // if (toi.name != "gyroV" || toi.index != 2) return;
 | 
|---|
| 52 |   if (toi.name != "gyroV" ) return;
 | 
|---|
| 53 |   
 | 
|---|
| 54 |   if (gyro[2].empty()) {
 | 
|---|
| 55 |     startSample = sampleNum;
 | 
|---|
| 56 |   }
 | 
|---|
| 57 |   
 | 
|---|
| 58 |   gyro[toi.index].push_back(value);
 | 
|---|
| 59 | }
 | 
|---|
| 60 | 
 | 
|---|
| 61 | void GyroCalibrator::recomputeCalib() {
 | 
|---|
| 62 |   // Integral of gyro signal between the two fences.
 | 
|---|
| 63 |   
 | 
|---|
| 64 |   // can we do it ?
 | 
|---|
| 65 |   for (int i=0; i<3; i++) {
 | 
|---|
| 66 |     lastCalib[i] = -99999;
 | 
|---|
| 67 |   }
 | 
|---|
| 68 |   if (startSample > lastFence1) return;
 | 
|---|
| 69 |   if ((long)gyro[2].size()+startSample < lastFence2) return;
 | 
|---|
| 70 |         
 | 
|---|
| 71 |   double sum[3];
 | 
|---|
| 72 |   for (int i=0; i<3; i++) {
 | 
|---|
| 73 |     sum[i] = 0;
 | 
|---|
| 74 |   }
 | 
|---|
| 75 |   vector<double>::iterator i0     = gyro[0].begin() + (lastFence1-startSample);
 | 
|---|
| 76 |   vector<double>::iterator i1     = gyro[1].begin() + (lastFence1-startSample);
 | 
|---|
| 77 |   vector<double>::iterator i2     = gyro[2].begin() + (lastFence1-startSample);
 | 
|---|
| 78 |   vector<double>::iterator stop2  = gyro[2].begin() + (lastFence2-startSample);
 | 
|---|
| 79 |   for (; i2 != stop2; i0++,i1++,i2++) {
 | 
|---|
| 80 |     sum[0] += *i0;
 | 
|---|
| 81 |     sum[1] += *i1;
 | 
|---|
| 82 |     sum[2] += *i2;
 | 
|---|
| 83 |   }
 | 
|---|
| 84 |     
 | 
|---|
| 85 |   // average of signal
 | 
|---|
| 86 |   sum[0] /= (lastFence2-lastFence1);
 | 
|---|
| 87 |   sum[1] /= (lastFence2-lastFence1);
 | 
|---|
| 88 |   sum[2] /= (lastFence2-lastFence1);
 | 
|---|
| 89 |   
 | 
|---|
| 90 |   lastOffset[0] = sum[0];
 | 
|---|
| 91 |   lastOffset[1] = sum[1];
 | 
|---|
| 92 |   lastOffset[2] = (lastOffset[0] + lastOffset[1])/2.;  // We don't have a better estimate...
 | 
|---|
| 93 |   
 | 
|---|
| 94 |   lastCalib[2]  = lastRotSpeed / (sum[2] - lastOffset[2]);
 | 
|---|
| 95 |   lastCalib[0] = lastCalib[1] = lastCalib[2];          // We don't have a better estimate...
 | 
|---|
| 96 | }
 | 
|---|
| 97 | 
 | 
|---|
| 98 | bool GyroCalibrator::fetchFences(long sampleNum) {
 | 
|---|
| 99 |   map<TOI, TOIProducer*> & m = (*(neededTOIs.begin())).second;
 | 
|---|
| 100 |   
 | 
|---|
| 101 |   long oldf2 = lastFence2;
 | 
|---|
| 102 |   for (map<TOI, TOIProducer*>::iterator i = m.begin(); i != m.end(); i++) {
 | 
|---|
| 103 |     TOI const& inToi = (*i).first;
 | 
|---|
| 104 |     TOIProducer* prod =  (*i).second;
 | 
|---|
| 105 |     if (inToi.name == "rotSpeed")        lastRotSpeed = prod->getValue(sampleNum, inToi);
 | 
|---|
| 106 |     if (inToi.name == "rotSpeedSample1") lastFence1   = long(prod->getValue(sampleNum, inToi));
 | 
|---|
| 107 |     if (inToi.name == "rotSpeedSample2") lastFence2   = long(prod->getValue(sampleNum, inToi));
 | 
|---|
| 108 |     if (inToi.name == "gyroV")           gyroProducer = prod;
 | 
|---|
| 109 |   }
 | 
|---|
| 110 |   
 | 
|---|
| 111 |   return (oldf2 != lastFence2);
 | 
|---|
| 112 | }
 | 
|---|
| 113 | 
 | 
|---|
| 114 | 
 | 
|---|
| 115 | bool GyroCalibrator::canGetValue(long sampleNum, TOI const& ) {
 | 
|---|
| 116 |   // We can get value if sampleNum is between the two fences, or
 | 
|---|
| 117 |   // if a new fence later than sampleNum is now available.
 | 
|---|
| 118 |   // In any case, we must have gyro data up to the highest fence.
 | 
|---|
| 119 |   
 | 
|---|
| 120 |   if (startSample > lastFence1) return false; // will never work...
 | 
|---|
| 121 |   if (sampleNum >= lastFence1 && sampleNum < lastFence2 && (gyro[2].size()+startSample >= lastFence2)) return true;
 | 
|---|
| 122 |   if ((long)gyro[2].size()+startSample < lastFence2) return false; // We have to wait for more gyro data
 | 
|---|
| 123 |   if (fetchFences(sampleNum)) {
 | 
|---|
| 124 |     recomputeCalib(); // do it now to keep a consistent state
 | 
|---|
| 125 |   }
 | 
|---|
| 126 |   if (sampleNum >= lastFence1 && sampleNum < lastFence2) {
 | 
|---|
| 127 |     return true;
 | 
|---|
| 128 |   } else {
 | 
|---|
| 129 |     return false;
 | 
|---|
| 130 |   }  
 | 
|---|
| 131 | }
 | 
|---|
| 132 | 
 | 
|---|
| 133 | bool GyroCalibrator::canGetValueLater(long sampleNum, TOI const& ) {
 | 
|---|
| 134 |   if (sampleNum >= lastFence1 && sampleNum < lastFence2 && ((long)gyro[2].size()+startSample >= lastFence2)) return false;
 | 
|---|
| 135 |       // because can get now
 | 
|---|
| 136 |   if (sampleNum >= lastFence2) { // check if new fence...
 | 
|---|
| 137 |     if (fetchFences(sampleNum)) {
 | 
|---|
| 138 |       recomputeCalib(); // do it now to keep a consistent state
 | 
|---|
| 139 |     }
 | 
|---|
| 140 |   }
 | 
|---|
| 141 |   
 | 
|---|
| 142 |   // Si nos fournisseurs ne peuvent pas, nous non plus...
 | 
|---|
| 143 |   map<TOI, TOIProducer*> & m = (*(neededTOIs.begin())).second;
 | 
|---|
| 144 |   for (map<TOI, TOIProducer*>::iterator i = m.begin(); i != m.end(); i++) {
 | 
|---|
| 145 |     TOI const& inToi = (*i).first;
 | 
|---|
| 146 |     TOIProducer* prod =  (*i).second;
 | 
|---|
| 147 |     if (!prod->canGetValue(sampleNum, inToi) && !prod->canGetValueLater(sampleNum, inToi)) return false;
 | 
|---|
| 148 | 
 | 
|---|
| 149 |   }
 | 
|---|
| 150 |   
 | 
|---|
| 151 |   if (lastFence1<0 || lastFence2<0) return true;
 | 
|---|
| 152 |   if (sampleNum > lastFence2) return true;
 | 
|---|
| 153 |   return (startSample <= lastFence1 && (long)gyro[2].size()+startSample < lastFence2 && sampleNum > lastFence1);
 | 
|---|
| 154 | }
 | 
|---|
| 155 | 
 | 
|---|
| 156 | double GyroCalibrator::getValue(long sampleNum, TOI const& toi) {
 | 
|---|
| 157 |   if (startSample > lastFence1) return -1; // will never work...
 | 
|---|
| 158 |   if ((long)gyro[2].size()+startSample < lastFence2) return -1; // We have to wait for more gyro data
 | 
|---|
| 159 |   if (!(sampleNum >= lastFence1 && sampleNum < lastFence2)) {
 | 
|---|
| 160 |     if (fetchFences(sampleNum)) {
 | 
|---|
| 161 |       if ((long)gyro[2].size()+startSample < lastFence2) return -1; // We have to wait for more gyro data
 | 
|---|
| 162 |       recomputeCalib(); // do it now to keep a consistent state
 | 
|---|
| 163 |     }
 | 
|---|
| 164 |   }
 | 
|---|
| 165 |   
 | 
|---|
| 166 |   if (!(sampleNum >= lastFence1 && sampleNum < lastFence2)) 
 | 
|---|
| 167 |     return -1;
 | 
|---|
| 168 |     
 | 
|---|
| 169 |   if (lastCalib[0] < 0) recomputeCalib();
 | 
|---|
| 170 |     
 | 
|---|
| 171 |   if (toi.name == gyroCal)    return lastCalib[toi.index];
 | 
|---|
| 172 |   if (toi.name == gyroOffset) return lastOffset[toi.index];
 | 
|---|
| 173 |   if (toi.name == gyroSpeed) {
 | 
|---|
| 174 |     TOI toi2 = TOI("gyroV", toi.index); // $CHECK$ maybe should get from reqtoi ?
 | 
|---|
| 175 |     double gv = gyroProducer->getValue(sampleNum, toi2);
 | 
|---|
| 176 |     return (gv-lastOffset[toi.index])*lastCalib[toi.index];
 | 
|---|
| 177 |   }
 | 
|---|
| 178 |   throw ArchExc("Cannot produce "+toi.fullName());
 | 
|---|
| 179 | }
 | 
|---|
| 180 | 
 | 
|---|
| 181 | 
 | 
|---|
| 182 | void GyroCalibrator::propagateLowBound(TOI const& toi, long sampleNum) {
 | 
|---|
| 183 |    if (startSample < lastFence1) {
 | 
|---|
| 184 |      if (gyro[0].size() > lastFence1 - startSample) {
 | 
|---|
| 185 |        for (int i=0; i<3; i++) {
 | 
|---|
| 186 |          vector<double>::iterator x = gyro[i].begin() + lastFence1 - startSample;
 | 
|---|
| 187 |          gyro[i].erase(gyro[i].begin(), x);
 | 
|---|
| 188 |        }
 | 
|---|
| 189 |        startSample = lastFence1;
 | 
|---|
| 190 |      }
 | 
|---|
| 191 |    }
 | 
|---|
| 192 |    TOIPullProducer::propagateLowBound(toi, sampleNum);
 | 
|---|
| 193 | }
 | 
|---|
| 194 | 
 | 
|---|