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