Mercurial > hg > beaglert
comparison core/ClockSync.cpp @ 141:44d07fa9bd03 ClockSync
Ultra-basic feedback for clock sync works^CIssues: response time of the IIR filter is too slow, requires PID and better filtering algorithm.
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Mon, 14 Sep 2015 15:42:11 +0100 |
parents | 4e2dd3eb1d28 |
children | 55c1e591cb2e |
comparison
equal
deleted
inserted
replaced
140:5edc6d0713ef | 141:44d07fa9bd03 |
---|---|
8 slave=thisIsSlave; | 8 slave=thisIsSlave; |
9 setPort(aPort); | 9 setPort(aPort); |
10 // isSlave() ? client.setServer("127.0.0.1") : client.setServer("127.0.0.1"); | 10 // isSlave() ? client.setServer("127.0.0.1") : client.setServer("127.0.0.1"); |
11 isSlave() ? client.setServer("192.168.7.1") : client.setServer("192.168.7.2"); | 11 isSlave() ? client.setServer("192.168.7.1") : client.setServer("192.168.7.2"); |
12 bufferLength=kSyncMessageLength; | 12 bufferLength=kSyncMessageLength; |
13 resetTs(); | |
14 receiveLoopSleepUs=100; | |
15 receiveLoopTimeout=1e5; | |
16 movingAverage.setLength(31); | |
17 expectedClockSyncType=isSlave() ? kSync : kNone; | |
18 } | |
19 void ClockSync::resetTs(){ | |
13 T1=-1; | 20 T1=-1; |
14 T1p=-1; | 21 T1p=-1; |
15 T2=-1; | 22 T2=-1; |
16 T2p=-1; | 23 T2p=-1; |
17 receiveLoopSleepUs=100; | 24 } |
18 receiveLoopTimeout=1e5; | 25 bool ClockSync::areTsValid(){ |
19 movingAverage.setLength(31); | 26 return T1>0 && T1p>0 && T2>0 && T2p>0; |
20 expectedClockSyncType=isSlave() ? kSync : kNone; | |
21 } | 27 } |
22 ClockSync::ClockSync(bool thisIsSlave, int aPort, VirtualClock &aVirtualClock){ | 28 ClockSync::ClockSync(bool thisIsSlave, int aPort, VirtualClock &aVirtualClock){ |
23 init(thisIsSlave, aPort, aVirtualClock); | 29 init(thisIsSlave, aPort, aVirtualClock); |
24 } | 30 } |
25 void* ClockSync::getBuffer(){ | 31 void* ClockSync::getBuffer(){ |
188 } | 194 } |
189 | 195 |
190 int ClockSync::slaveHandleMessage(){ | 196 int ClockSync::slaveHandleMessage(){ |
191 switch(clockSyncType){ | 197 switch(clockSyncType){ |
192 case kSync: //the clockSync timestamp is meaningless, the localTimestamp is when kSync was received | 198 case kSync: //the clockSync timestamp is meaningless, the localTimestamp is when kSync was received |
199 resetTs(); | |
193 T1p=localTimestamp; | 200 T1p=localTimestamp; |
194 expectedClockSyncType=kFollowUp; | 201 expectedClockSyncType=kFollowUp; |
195 break; | 202 break; |
196 case kFollowUp: //the clockSyncTimestamp is the time when kSync was sent, the localTimestamp is meaningless | 203 case kFollowUp: //the clockSyncTimestamp is the time when kSync was sent, the localTimestamp is meaningless |
197 T1=clockSyncTimestamp; | 204 T1=clockSyncTimestamp; |
207 break; | 214 break; |
208 case kDelayResp: {//the clockSyncTimestamp is the instant when the master received the kDelayResp clockSync, the localTimestamp is meaningless | 215 case kDelayResp: {//the clockSyncTimestamp is the instant when the master received the kDelayResp clockSync, the localTimestamp is meaningless |
209 T2p=clockSyncTimestamp; | 216 T2p=clockSyncTimestamp; |
210 //TODO: evaluate things | 217 //TODO: evaluate things |
211 double offset=(T1p-T1-T2p+T2)/2.0d; | 218 double offset=(T1p-T1-T2p+T2)/2.0d; |
212 printf("-----------OFFSET IS : %04.4f seconds, average: %04.4f seconds\n", | 219 if(areTsValid()){ |
213 offset/44100.f, movingAverage.add(offset)/44100.f); | 220 processOffset(offset); |
221 | |
222 /* | |
223 static int calls=0; | |
224 static double referenceOffset=0; | |
225 | |
226 if(calls<100){ // start by averaging everything | |
227 movingAverage.add(offset); | |
228 } else { //once we get an estimate, start discarding outliers | |
229 float maxOffsetDeviation=20; | |
230 float deviation=fabsf(movingAverage.getAverage()-offset); | |
231 if(deviation<maxOffsetDeviation){ | |
232 movingAverage.add(offset); | |
233 printf("w(end+1)=%4.1f;\n", movingAverage.getAverage()); | |
234 } else { | |
235 // printf("Out of range: %f \n", deviation); | |
236 } | |
237 } | |
238 printf("offset(end+1)=%f;\n", offset); | |
239 if (calls==100){ | |
240 // printf("Update reference\n"); | |
241 referenceOffset=movingAverage.getAverage(); | |
242 } else if (calls==200){ | |
243 calls=99; | |
244 } | |
245 calls++; | |
246 */ | |
247 | |
248 // printf("%lld, %lld, %lld, %lld \n", T1, T1p, T2, T2p); | |
249 // if(T2-T1p<0){ | |
250 // printf("Negative: %lld, %lld, %lld, %lld \n", T1, T1p, T2, T2p); | |
251 // } | |
252 } else { | |
253 printf("InvalidTs:\n %lld, %lld, %lld, %lld \n", T1, T1p, T2, T2p); | |
254 } | |
214 expectedClockSyncType=kSync; //end of the cycle, wait for next sync. | 255 expectedClockSyncType=kSync; //end of the cycle, wait for next sync. |
215 break; | 256 break; |
216 } | 257 } |
217 default: | 258 default: |
218 //printf("Unexpected message type\n"); // we should never get here | 259 //printf("Unexpected message type\n"); // we should never get here |
219 return -1; | 260 return -1; |
220 } | 261 } |
221 return 1; | 262 return 1; |
222 } | 263 } |
223 | 264 #include <I2c_Codec.h> |
265 extern I2c_Codec* gAudioCodec; | |
266 void ClockSync::processOffset(double offset){ | |
267 static int calls=0; | |
268 // TODO: change the flow control below so that it can happen multiple times | |
269 //(base it upon the length of movingAverage rather than the number of calls) | |
270 if(calls<10) { //get an initial guess | |
271 movingAverage.add(offset); | |
272 // printf("-----------OFFSET IS : %04.4f samples, average: %04.4f samples\n", | |
273 // offset, movingAverage.getAverage()); | |
274 } else if (calls==10){ //then compensate for initial offset | |
275 // printf("compensating for offset: %f\n", offset); | |
276 virtualClock->addOffset(movingAverage.getAverage()); | |
277 movingAverage.reset(); | |
278 } else if (calls>=10){ //use IIR filter from now on | |
279 //filter coefficients obtained from Matlab : [B,A]=butter(2,0.005); | |
280 // static float B[3]={6.10061787580662e-05, 0.000122012357516132, 6.10061787580662e-05}; | |
281 // static float A[3]={1, -1.97778648377676, 0.978030508491796}; | |
282 static float B[3]={6.10061787580662e-05, 0.000122012357516132, 6.10061787580662e-05}; | |
283 static float A[3]={1, -1.97778648377676, 0.978030508491796}; | |
284 static float pastOut[3]={0,0,0}; | |
285 static float pastIn[3]={0,0,0}; | |
286 float in=offset; | |
287 float out= -pastOut[1]*A[1] -pastOut[2]*A[2] +in*B[0] +pastIn[1]*B[1] +pastIn[2]*B[2]; | |
288 pastOut[2]=pastOut[1]; | |
289 pastOut[1]=out; | |
290 pastIn[2]=pastIn[1]; | |
291 pastIn[1]=in; | |
292 offset=out; | |
293 static float maxOffset=0; | |
294 maxOffset=fabsf(offset) > fabsf(maxOffset) ? offset : maxOffset; | |
295 printf("%10.3f, %10.3f, %10.3f, %10.3f\n", in, offset, offset-pastOut[2], maxOffset); //unfiltered, filtered | |
296 if(fabsf(offset)>10 && calls>30){ | |
297 calls=11; | |
298 //TODO: correct for offset | |
299 float targetSamplingRate=offset>0 ? 44097 : 44103; | |
300 gAudioCodec->setAudioSamplingRate(targetSamplingRate); | |
301 // pastOut[1]=pastOut[2]=pastIn[1]=pastIn[2]=offset; | |
302 printf("------setAudioSmplingRate to %f\n", targetSamplingRate); | |
303 } | |
304 } | |
305 calls++; | |
306 } | |
224 int ClockSync::masterHandleMessage(){ | 307 int ClockSync::masterHandleMessage(){ |
225 switch(clockSyncType){ | 308 switch(clockSyncType){ |
226 case kDelayReq: | 309 case kDelayReq: |
227 //TODO: do something with it | |
228 //send kDelayResp | 310 //send kDelayResp |
229 setType(kDelayResp); | 311 setType(kDelayResp); |
230 setTimestamp(localTimestamp); | 312 setTimestamp(localTimestamp); |
231 send(); | 313 send(); |
232 expectedClockSyncType=kNone; | 314 expectedClockSyncType=kNone; |
315 return 1; | |
233 break; | 316 break; |
317 default: | |
318 return -1; | |
234 } | 319 } |
235 } | 320 } |
236 | 321 |
237 int ClockSync::sendReceiveLoop(){ | 322 int ClockSync::sendReceiveLoop(){ |
238 if(isSlave()==true){ | 323 if(isSlave()==true){ |