SAF
Loading...
Searching...
No Matches
saf_tracker_internal.c
Go to the documentation of this file.
1/*
2 * This file is part of the saf_tracker module.
3 * Copyright (c) 2020 - Leo McCormack
4 *
5 * The saf_tracker module is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * The saf_tracker module is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * See <http://www.gnu.org/licenses/> for a copy of the GNU General Public
16 * License.
17 */
18
44#include "saf_tracker.h"
46
47#ifdef SAF_ENABLE_TRACKER_MODULE
48
50#define SAF_LOG_2PI ( logf(2.0f*SAF_PI) )
51
53typedef struct _kf_update6 {
54 void* hLinSolve; /* Linear solver handle '\' */
55 void* hLinSolveT; /* Linear solver handle '/' */
57
58/* ========================================================================== */
59/* Static Prototypes */
60/* ========================================================================== */
61
73static double lngamma(double x, double* sgngam);
74
96static double incompletegamma(double a, double x);
97
121static double incompletegammac(double a, double x);
122
123
124/* ========================================================================== */
125/* Internal Functions */
126/* ========================================================================== */
127
129(
130 void** phPart,
131 float W0,
132 float dt
133)
134{
135 *phPart = malloc1d(sizeof(MCS_data));
136 MCS_data *p = (MCS_data*)(*phPart);
137
138 p->W = W0;
139 p->W_prev = W0;
140 p->W0 = W0;
141 p->nTargets = 0;
142 p->dt = dt;
146 p->Tcount = malloc1d(TRACKER3D_MAX_NUM_TARGETS*sizeof(int));
147}
148
150(
151 void* hPart
152)
153{
154 MCS_data *p = (MCS_data*)(hPart);
155
156 p->W = p->W0;
157 p->W_prev = p->W0;
158 p->nTargets = 0;
159 memset(p->M, 0, TRACKER3D_MAX_NUM_TARGETS*sizeof(M6));
160 memset(p->P, 0, TRACKER3D_MAX_NUM_TARGETS*sizeof(P66));
161 memset(p->targetIDs, 0, TRACKER3D_MAX_NUM_TARGETS*sizeof(int));
162 memset(p->Tcount, 0, TRACKER3D_MAX_NUM_TARGETS*sizeof(int));
163}
164
166(
167 void* hPart1,
168 void* hPart2
169)
170{
171 MCS_data *p1 = (MCS_data*)(hPart1);
172 MCS_data *p2 = (MCS_data*)(hPart2);
173
174 p2->W = p1->W;
175 p2->W_prev = p1->W_prev;
176 p2->W0 = p1->W0;
177 p2->nTargets = p1->nTargets;
178 p2->dt = p1->dt;
179 cblas_scopy(p1->nTargets*6, (float*)p1->M->M, 1, (float*)p2->M->M, 1);
180 cblas_scopy(p1->nTargets*6*6, (float*)p1->P->P, 1, (float*)p2->P->P, 1);
181 cblas_scopy(p1->nTargets, (float*)p1->targetIDs, 1, (float*)p2->targetIDs, 1);
182 cblas_scopy(p1->nTargets, (float*)p1->Tcount, 1, (float*)p2->Tcount, 1);
183}
184
186(
187 void** phPart
188)
189{
190 MCS_data *p = (MCS_data*)(*phPart);
191
192 if(p!=NULL){
193 free(p->M);
194 free(p->P);
195 free(p->targetIDs);
196 free(p->Tcount);
197 p=NULL;
198 *phPart = NULL;
199 }
200}
201
203(
204 void* const hT3d,
205 int Tinc
206)
207{
208 tracker3d_data *pData = (tracker3d_data*)(hT3d);
209 int i, j, k, n, nDead, isDead, ind;
210 int* dead;
211 float dt0, dt1, p_death, rand01, distance_diff;
212 MCS_data* S;
213 tracker3d_config* tpars = &(pData->tpars);
214#ifdef TRACKER_VERY_VERBOSE
215 char c_event[256], tmp[256];
216 printf("%s\n", "Prediction step");
217#endif
218
219 dead = NULL;
220
221 /* Loop over particles */
222 for (i=0; i<tpars->Np; i++){
223 S = (MCS_data*)pData->SS[i];
224
225 /* prep */
226 nDead = 0;
227 free(dead);
228 dead = NULL;
229#ifdef TRACKER_VERY_VERBOSE
230 memset(c_event, 0, 256*sizeof(char));
231#endif
232
233 /* Loop over targets */
234 for (j=0; j<S->nTargets; j++){
235
236 /* No target has died yet or multiple targets are allowed to die in
237 * one prediction step */
238 if (nDead==0 || tpars->ALLOW_MULTI_DEATH){
239 /* Probability of death */
240 dt0 = (float)S->Tcount[j] * S->dt;
241 dt1 = dt0 + S->dt * (float)Tinc;
242 if (dt0 == 0)
243 p_death = gamma_cdf(dt1, tpars->alpha_death, tpars->beta_death, 0.0f);
244 else
245 p_death = 1.0f - (1.0f-gamma_cdf(dt1, tpars->alpha_death,tpars->beta_death, 0.0f)) /
246 (1.0f-gamma_cdf(dt0,tpars->alpha_death,tpars->beta_death, 0.0f));
247
248 /* Force probability of death to 1, if this target is too close
249 another target that has been alive longer. */
250 if (tpars->FORCE_KILL_TARGETS){
251 for(k=0; k<S->nTargets; k++){
252 if (k!=j){
253 distance_diff = (S->M[j].m0 - S->M[k].m0) * (S->M[j].m0 - S->M[k].m0) +
254 (S->M[j].m1 - S->M[k].m1) * (S->M[j].m1 - S->M[k].m1) +
255 (S->M[j].m2 - S->M[k].m2) * (S->M[j].m2 - S->M[k].m2);
256 distance_diff = sqrtf(distance_diff);
257 if (distance_diff < tpars->forceKillDistance && S->Tcount[j] <= S->Tcount[k])
258 p_death = 1.0f;
259 }
260 }
261 }
262
263 /* Decide whether target should die */
264 rand_0_1(&rand01, 1);
265 if (rand01 < p_death){
266 nDead++; /* Target dies */
267 dead = realloc1d(dead, nDead*sizeof(float));
268 dead[nDead-1] = j;
269 }
270 }
271
272 /* Prediction step if target is alive */
273 if( tpars->ALLOW_MULTI_DEATH ){
274 isDead = 0;
275 for(n=0; n<nDead; n++)
276 if(j==dead[n])
277 isDead = 1;
278
279 /* Kalman Filter prediction for the target if alive */
280 if(!isDead)
281 kf_predict6(S->M[j].M, S->P[j].P, pData->A, pData->Q);
282 }
283 else {
284 /* Kalman Filter prediction for the target if alive */
285 if ( (nDead==0) || (j != dead[0]) )
286 kf_predict6(S->M[j].M, S->P[j].P, pData->A, pData->Q);
287 }
288 }
289
290 /* Remove the dead target */
291 if (tpars->ALLOW_MULTI_DEATH){
292 for(j=0; j<nDead; j++){
293 /* Find index of the target to remove */
294 ind = -1;
295 for(k=0; k<S->nTargets; k++)
296 if(dead[j]==k)
297 ind = k;
298 saf_assert(ind != -1, "Ugly error");
299
300 /* Shimy target data down by 1... overriding the dead target */
301 S->nTargets--;
302 if(ind!=S->nTargets){
303 memmove(&S->M[ind], &S->M[ind+1], (S->nTargets-ind)*sizeof(M6));
304 memmove(&S->P[ind], &S->P[ind+1], (S->nTargets-ind)*sizeof(P66));
305 memmove(&S->Tcount[ind], &S->Tcount[ind+1], (S->nTargets-ind)*sizeof(int));
306 memmove(&S->targetIDs[ind], &S->targetIDs[ind+1], (S->nTargets-ind)*sizeof(int));
307 }
308
309 /* Remove dead index for next iteration */
310 for(k=0; k<nDead; k++)
311 dead[k]--;
312
313#ifdef TRACKER_VERY_VERBOSE
314 sprintf(tmp, " Target %d died ", ind);
315 strcat(c_event, tmp);
316#endif
317 }
318 }
319 else {
320 if (nDead==1){
321 /* Find index of the target to remove */
322 ind = -1;
323 for(k=0; k<S->nTargets; k++)
324 if(dead[0]==k)
325 ind = k;
326 saf_assert(ind != -1, "Ugly error");
327
328 S->nTargets--;
329 if(ind!=S->nTargets){
330 memmove(&S->M[ind], &S->M[ind+1], (S->nTargets-ind)*sizeof(M6));
331 memmove(&S->P[ind], &S->P[ind+1], (S->nTargets-ind)*sizeof(P66));
332 memmove(&S->Tcount[ind], &S->Tcount[ind+1], (S->nTargets-ind)*sizeof(int));
333 memmove(&S->targetIDs[ind], &S->targetIDs[ind+1], (S->nTargets-ind)*sizeof(int));
334 }
335
336#ifdef TRACKER_VERY_VERBOSE
337 sprintf(tmp, ", Target %d died ", ind);
338 strcpy(c_event, tmp);
339#endif
340 }
341 }
342
343 /* Print particle state */
344#ifdef TRACKER_VERY_VERBOSE
345 sprintf(S->evstr, "MCS: %d, W: %.7f, IDs: [", i, S->W);
346 for (j=0; j<S->nTargets; j++){
347 sprintf(tmp, "%d ", S->targetIDs[j]);
348 strcat(S->evstr, tmp);
349 }
350 strcat(S->evstr, "] ");
351 strcat(S->evstr, c_event);
352 printf("%s\n", S->evstr);
353#endif
354 }
355}
356
358(
359 void* const hT3d,
360 float* Y,
361 int Tinc
362)
363{
364 tracker3d_data *pData = (tracker3d_data*)(hT3d);
365 int i, j, k, ss, n_events, count, cidx, unique, j_new, ev;
366 float TP0, LH, norm;
367 float M[6], P[6][6];
368 MCS_data* S, *S_event;
369 tracker3d_config* tpars = &(pData->tpars);
370#ifdef TRACKER_VERY_VERBOSE
371 char tmp[256];
372 printf("%s\n", "Update step");
373#endif
374
375 /* Loop over particles */
376 for (i=0; i<tpars->Np; i++){
377 S = (MCS_data*)pData->SS[i];
378
379 /* Association priors to targets */
380 TP0 = (1.0f-tpars->noiseLikelihood)/(S->nTargets+2.23e-10f);
381
382 /* Number of possible events: */
383 n_events = S->nTargets + 1; /* clutter (+1) or 1 of the targets is active */
384 if( S->nTargets < tpars->maxNactiveTargets)
385 n_events++; /* Also a chance of a new target */
386 saf_assert(n_events<=TRACKER3D_MAX_NUM_EVENTS, "Number of hypotheses/events exceeded the maximum");
387
388 /* Prep */
389#ifdef TRACKER_VERBOSE
390 memset(pData->evt, 0, n_events*256*sizeof(char)); /* Event descriptions */
391#endif
392 count = 0; /* Event counter */
393 cidx = 0; /* current index */
394
395 /* Association to clutter */
396 count++;
397#ifdef TRACKER_VERBOSE
398 strcpy(pData->evt[cidx], "Clutter");
399#endif
400 pData->evta[cidx] = -1;
401 pData->evp[cidx] = (1.0f-tpars->init_birth)*tpars->noiseLikelihood;
402 pData->evl[cidx] = tpars->cd;
403 tracker3d_particleCopy(pData->SS[i], pData->str[cidx]);
404 cidx++;
405
406 /* Loop over associations to targets */
407 for (j=0; j<S->nTargets; j++){
408 /* Compute update result and likelihood for association to signal j */
409 kf_update6(pData->hKF6, S->M[j].M, S->P[j].P, Y, pData->H, pData->R, M, P, &LH);
410 if(pData->tpars.ARE_UNIT_VECTORS)
411 cblas_sscal(3, 1.0f/L2_norm3(M), M, 1);
412
413 /* Assocation to target j */
414 count++;
415#ifdef TRACKER_VERBOSE
416 sprintf(pData->evt[cidx], "Target %d ", S->targetIDs[j]);
417#endif
418 pData->evta[cidx] = S->targetIDs[j];
419 pData->evp[cidx] = (1.0f-tpars->init_birth)*TP0;
420 pData->evl[cidx] = LH;
421 tracker3d_particleCopy(pData->SS[i], pData->str[cidx]);
422 S_event = (MCS_data*)pData->str[cidx];
423 cblas_scopy(6, (float*)M, 1, (float*)S_event->M[j].M, 1);
424 cblas_scopy(6*6, (float*)P, 1, (float*)S_event->P[j].P, 1);
425 for(k=0; k<S->nTargets; k++)
426 S_event->Tcount[k] += Tinc;
427 cidx++;
428 }
429
430 /* Association to new target */
432 /* Initialization of new target */
433 kf_update6(pData->hKF6, tpars->M0, tpars->P0, Y, pData->H, pData->R, M, P, &LH);
434 if(pData->tpars.ARE_UNIT_VECTORS)
435 cblas_sscal(3, 1.0f/L2_norm3(M), M, 1);
436
437 /* find an untaken ID */
438 j_new = 0;
439 for (ss = 0; ss<tpars->maxNactiveTargets; ss++){
440 unique = 1;
441 for(j=0; j<S->nTargets; j++){
442 if(ss == S->targetIDs[j]){
443 unique = 0;
444 }
445 };
446 if(unique){
447 j_new = ss;
448 break;
449 }
450 }
451
452 count++;
453 j = S->nTargets;
454#ifdef TRACKER_VERBOSE
455 sprintf(pData->evt[cidx], "New Target %d ", j);
456#endif
457 pData->evta[cidx] = j;
458 pData->evp[cidx] = tpars->init_birth;
459 pData->evl[cidx] = LH;
460 tracker3d_particleCopy(pData->SS[i], pData->str[cidx]);
461 S_event = (MCS_data*)pData->str[cidx];
462 S_event->nTargets = j+1;
463 cblas_scopy(6, (float*)M, 1, (float*)S_event->M[j].M, 1);
464 cblas_scopy(6*6, (float*)P, 1, (float*)S_event->P[j].P, 1);
465 S_event->Tcount[j] = 0;
466 S_event->targetIDs[j] = j_new;
467 cidx++;
468 }
469
470 /* Draw sample from importance distribution */
471 norm = 1.0f/sumf(pData->evp, count);
472 cblas_sscal(count, norm, pData->evp, 1);
473 utility_svvmul(pData->evp, pData->evl, count, pData->imp);
474 norm = 1.0f/sumf(pData->imp, count);
475 cblas_sscal(count, norm, pData->imp, 1);
476 ev = categ_rnd(pData->imp, count); /* Event index */
477 saf_assert(ev!=-1, "Falied to randomly select an event");
478
479 /* Update particle */
480 tracker3d_particleCopy(pData->str[ev], pData->SS[i]);
481 S->W *= (pData->evl[ev] * pData->evp[ev]/ pData->imp[ev]);
482
483 /* Print particle state */
484#ifdef TRACKER_VERY_VERBOSE
485 sprintf(S->evstr, "MCS: %d, W: %.7f, IDs: [", i, S->W);
486 for (j=0; j<S->nTargets; j++){
487 sprintf(tmp, "%d ", S->targetIDs[j]);
488 strcat(S->evstr, tmp);
489 }
490 strcat(S->evstr, "] ");
491 strcat(S->evstr, pData->evt[ev]);
492 printf("%s\n", S->evstr);
493#endif
494 }
495
496 normalise_weights(pData->SS, tpars->Np);
497}
498
500(
501 void* const hT3d
502)
503{
504 tracker3d_data *pData = (tracker3d_data*)(hT3d);
505 int i, maxIdx;
506 float maxVal;
507
508 /* Find most significant particle.. */
509 maxVal = FLT_MIN;
510 maxIdx = -1;
511 for(i=0; i<pData->tpars.Np; i++){
512 if(maxVal<((MCS_data*)pData->SS[i])->W){
513 maxVal = ((MCS_data*)pData->SS[i])->W;
514 maxIdx = i;
515 }
516 }
517 saf_assert(maxIdx!=-1, "Ugly error");
518 return maxIdx;
519}
520
521
522/* ========================================================================== */
523/* RBMCDA Functions */
524/* ========================================================================== */
525
527(
528 voidPtr* SS,
529 int NP,
530 int* s
531)
532{
533 int i, j, k, a;
534 float c;
536
537 for (i=0; i<NP; i++)
538 pn[i] = ((MCS_data*)SS[i])->W*(float)NP;
539 memset(s, 0, NP*sizeof(int));
540 rand_0_1(r, NP);
541 k=0;
542 c=0.0f;
543 for (i=0; i<NP; i++){
544 c+=pn[i];
545 if (c>=1.0f) {
546 a = (int)floorf(c);
547 c = c-a;
548 for(j=0; j<a; j++)
549 s[k+j]=i;
550 k=k+a;
551 }
552 if (k<NP && c>=r[k]){
553 c=c-1.0f;
554 s[k]=i;
555 k++;
556 }
557 }
558}
559
561(
562 voidPtr* SS,
563 int NP
564)
565{
566 int i;
567 MCS_data* S;
568 float sumW2;
569
570 /* Number of effective particles */
571 sumW2 = 0.0f;
572 for(i=0; i<NP; i++){
573 S = (MCS_data*)SS[i];
574 sumW2 += (S->W * S->W);
575 }
576 return 1.0f/sumW2;
577}
578
580(
581 voidPtr* SS,
582 int NP
583)
584{
585 int i;
586 float W_sum;
587 MCS_data* S;
588
589 W_sum = 0.0f;
590 for (i=0; i<NP; i++){
591 S = (MCS_data*)SS[i];
592 W_sum += S->W;
593 }
594 for (i=0; i<NP; i++){
595 S = (MCS_data*)SS[i];
596 S->W /= W_sum;
597 }
598}
599
600/* hard-coded for length(M)=6 ... */
602(
603 float M[6],
604 float P[6][6],
605 float A[6][6],
606 float Q[6][6]
607)
608{
609 float AM[6], AP[6][6], APAT[6][6];
610
611 /* Perform prediction */
612 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 6, 1, 6, 1.0f,
613 (float*)A, 6,
614 (float*)M, 1, 0.0f,
615 (float*)AM, 1);
616 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 6, 6, 6, 1.0f,
617 (float*)A, 6,
618 (float*)P, 6, 0.0f,
619 (float*)AP, 6);
620 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 6, 6, 6, 1.0f,
621 (float*)AP, 6,
622 (float*)A, 6, 0.0f,
623 (float*)APAT, 6);
624
625 /* Override M and P, with new M and P */
626 memcpy(M, AM, 6*sizeof(float));
627 utility_svvadd((float*)APAT, (float*)Q, 36, (float*)P);
628}
629
630void kf_update6_create(void ** const phUp6)
631{
632 *phUp6 = malloc1d(sizeof(kf_update6_data));
633 kf_update6_data *h = (kf_update6_data*)(*phUp6);
634
635 utility_sslslv_create(&h->hLinSolve, 3, 1);
636 utility_sglslvt_create(&h->hLinSolveT, 6, 3);
637}
638void kf_update6_destroy(void ** const phUp6)
639{
640 kf_update6_data *h = (kf_update6_data*)(*phUp6);
641
642 if(h!=NULL){
643 utility_sslslv_destroy(&h->hLinSolve);
644 utility_sglslvt_destroy(&h->hLinSolveT);
645
646 free(h);
647 h=NULL;
648 *phUp6 = NULL;
649 }
650}
651
652/* hard-coded for length(X)=6 ... */
654(
655 void * const hUp6,
656 float X[6],
657 float P[6][6],
658 float y[3],
659 float H[3][6],
660 float R[3][3],
661 float X_out[6],
662 float P_out[6][6],
663 float* LH
664)
665{
666 kf_update6_data *h = (kf_update6_data*)(hUp6);
667 float ISnd_sum;
668 float yIM[3], IM[3], IS[3][3], HP[3][6], HPHT[3][3], PHT[6][3], K[6][3], K_yIM[6], KIS[6][3];
669
670 /* update step */
671 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 1, 6, 1.0f,
672 (float*)H, 6,
673 (float*)X, 1, 0.0f,
674 (float*)IM, 1);
675 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 6, 6, 1.0f,
676 (float*)H, 6,
677 (float*)P, 6, 0.0f,
678 (float*)HP, 6);
679 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 6, 1.0f,
680 (float*)HP, 6,
681 (float*)H, 6, 0.0f,
682 (float*)HPHT, 3);
683 IS[0][0] = HPHT[0][0] + R[0][0]; IS[0][1] = HPHT[0][1] + R[0][1]; IS[0][2] = HPHT[0][2] + R[0][2];
684 IS[1][0] = HPHT[1][0] + R[1][0]; IS[1][1] = HPHT[1][1] + R[1][1]; IS[1][2] = HPHT[1][2] + R[1][2];
685 IS[2][0] = HPHT[2][0] + R[2][0]; IS[2][1] = HPHT[2][1] + R[2][1]; IS[2][2] = HPHT[2][2] + R[2][2];
686 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 6, 3, 6, 1.0f,
687 (float*)P, 6,
688 (float*)H, 6, 0.0f,
689 (float*)PHT, 3);
690 ISnd_sum = IS[0][1] + IS[0][2] + IS[1][2] + IS[1][0] + IS[2][0] + IS[2][1];
691 if(ISnd_sum<0.00001f){ /* If "IS" is diagonal: */
692 K[0][0] = 1.0f/IS[0][0] * PHT[0][0];
693 K[0][1] = 1.0f/IS[1][1] * PHT[0][1];
694 K[0][2] = 1.0f/IS[2][2] * PHT[0][2];
695 K[1][0] = 1.0f/IS[0][0] * PHT[1][0];
696 K[1][1] = 1.0f/IS[1][1] * PHT[1][1];
697 K[1][2] = 1.0f/IS[2][2] * PHT[1][2];
698 K[2][0] = 1.0f/IS[0][0] * PHT[2][0];
699 K[2][1] = 1.0f/IS[1][1] * PHT[2][1];
700 K[2][2] = 1.0f/IS[2][2] * PHT[2][2];
701 K[3][0] = 1.0f/IS[0][0] * PHT[3][0];
702 K[3][1] = 1.0f/IS[1][1] * PHT[3][1];
703 K[3][2] = 1.0f/IS[2][2] * PHT[3][2];
704 K[4][0] = 1.0f/IS[0][0] * PHT[4][0];
705 K[4][1] = 1.0f/IS[1][1] * PHT[4][1];
706 K[4][2] = 1.0f/IS[2][2] * PHT[4][2];
707 K[5][0] = 1.0f/IS[0][0] * PHT[5][0];
708 K[5][1] = 1.0f/IS[1][1] * PHT[5][1];
709 K[5][2] = 1.0f/IS[2][2] * PHT[5][2];
710 }
711 else
712 utility_sglslvt(h->hLinSolveT, (float*)PHT, 6, (float*)IS, 3, (float*)K);
713 yIM[0] = y[0]-IM[0];
714 yIM[1] = y[1]-IM[1];
715 yIM[2] = y[2]-IM[2];
716 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 6, 1, 3, 1.0f,
717 (float*)K, 3,
718 (float*)yIM, 1, 0.0f,
719 (float*)K_yIM, 1);
720 X_out[0] = X[0] + K_yIM[0];
721 X_out[1] = X[1] + K_yIM[1];
722 X_out[2] = X[2] + K_yIM[2];
723 X_out[3] = X[3] + K_yIM[3];
724 X_out[4] = X[4] + K_yIM[4];
725 X_out[5] = X[5] + K_yIM[5];
726 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 6, 3, 3, 1.0f,
727 (float*)K, 3,
728 (float*)IS, 3, 0.0f,
729 (float*)KIS, 3);
730 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 6, 6, 3, 1.0f,
731 (float*)KIS, 3,
732 (float*)K, 3, 0.0f,
733 (float*)P_out, 6);
734 cblas_sscal(6*6, -1.0f, (float*)P_out, 1);
735 cblas_saxpy(6*6, 1.0f, (float*)P, 1, (float*)P_out, 1);
736 if (LH!=NULL)
737 *LH = gauss_pdf3(hUp6, y,IM,IS);
738}
739
741(
742 float x,
743 float gam,
744 float beta,
745 float mu
746)
747{
748 /* Convert to standard form */
749 x = (x-mu)/beta;
750
751 /* Compute the probability using the imcomplete gamma function */
752 return (float)(incompletegamma((double)gam, (double)x)/tgamma((double)x));
753}
754
756(
757 float* F,
758 int len_N,
759 int len_Q,
760 float* opt_L,
761 float* opt_Qc,
762 float dt,
763 float* A,
764 float* Q
765)
766{
767 int i, j;
768 float* L, *Qc;
769 float* Fdt;
770 float** L_Qc, **L_Qc_LT, **Phi, **ZE, **B, **AB, **AB1_T, **AB2_T, **Q_T;
771
772 /* Defaults: */
773 if(opt_L==NULL){ /* Identity */
774 L = calloc1d(len_N*len_Q, sizeof(float));
775 for(i=0; i<SAF_MIN(len_N, len_Q); i++)
776 L[i*len_Q+i] = 1.0f;
777 }
778 else
779 L = opt_L;
780 if(opt_Qc==NULL) /* zeros */
781 Qc = calloc1d(len_Q*len_Q, sizeof(float));
782 else
783 Qc = opt_Qc;
784 Fdt = malloc1d(len_N*len_N*sizeof(float));
785
786 /* Closed form integration of transition matrix */
787 for(i=0; i<len_N*len_N; i++)
788 Fdt[i] = F[i]*dt;
789 gexpm(Fdt, len_N, 0, A);
790
791 /* Closed form integration of covariance by matrix fraction decomposition */
792 L_Qc = (float**)malloc2d(len_N, len_Q, sizeof(float));
793 L_Qc_LT = (float**)malloc2d(len_N, len_N, sizeof(float));
794 Phi = (float**)calloc2d(len_N*2, len_N*2, sizeof(float)); // ca
795 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, len_N, len_Q, len_Q, 1.0f,
796 L, len_Q,
797 Qc, len_Q, 0.0f,
798 FLATTEN2D(L_Qc), len_Q);
799 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, len_N, len_N, len_Q, 1.0f,
800 FLATTEN2D(L_Qc), len_Q,
801 L, len_Q, 0.0f,
802 FLATTEN2D(L_Qc_LT), len_N);
803 for(i=0; i<len_N; i++){
804 for(j=0; j<len_N; j++){
805 Phi[i][j] = F[i*len_N+j];
806 Phi[i][j+len_N] = L_Qc_LT[i][j];
807 Phi[i+len_N][j+len_N] = -F[j*len_N+i];
808 }
809 }
810 utility_svsmul(FLATTEN2D(Phi), &dt, (len_N*2)*(len_N*2), NULL);
811 ZE = (float**)calloc2d(len_N*2, len_N, sizeof(float));
812 for(i=0; i<len_N; i++)
813 ZE[i+len_N][i] = 1.0f;
814 B = (float**)malloc2d(len_N*2, len_N*2, sizeof(float));
815 AB = (float**)malloc2d(len_N*2, len_N, sizeof(float));
816 gexpm(FLATTEN2D(Phi), len_N*2, 0, FLATTEN2D(B));
817 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, len_N*2, len_N, len_N*2, 1.0f,
818 FLATTEN2D(B), len_N*2,
819 FLATTEN2D(ZE), len_N, 0.0f,
820 FLATTEN2D(AB), len_N);
821 AB1_T = (float**)malloc2d(len_N, len_N, sizeof(float));
822 AB2_T = (float**)malloc2d(len_N, len_N, sizeof(float));
823 Q_T = (float**)malloc2d(len_N, len_N, sizeof(float));
824 for(i=0; i<len_N; i++){
825 for(j=0; j<len_N; j++){
826 AB1_T[j][i] = AB[i][j];
827 AB2_T[j][i] = AB[i+len_N][j];
828 }
829 }
830 utility_sglslv(NULL, FLATTEN2D(AB2_T), len_N, FLATTEN2D(AB1_T), len_N, FLATTEN2D(Q_T));
831
832 /* transpose back */
833 for(i=0; i<len_N; i++)
834 for(j=0; j<len_N; j++)
835 Q[i*len_N+j] = Q_T[j][i];
836
837 /* clean-up */
838 if(opt_L==NULL)
839 free(L);
840 if(opt_Qc==NULL)
841 free(Qc);
842 free(Fdt);
843 free(L_Qc);
844 free(L_Qc_LT);
845 free(Phi);
846 free(ZE);
847 free(B);
848 free(AB);
849 free(AB1_T);
850 free(AB2_T);
851 free(Q_T);
852}
853
854/* Approximate expf and logf (BSD-3-clause License), Copyright 2011 Edward Kmett, https://github.com/ekmett/approximate */
855#if defined(LITTLE_ENDIAN) && 0
856static float expf_fast(float a) {
857 union { float f; int x; } u;
858 a=SAF_MAX(a, -80.0f);
859 u.x = (int) (12102203 * a + 1064866805);
860 return u.f;
861}
862
863static float logf_fast(float a) {
864 union { float f; int x; } u = { a };
865 return (u.x - 1064866805) * 8.262958405176314e-8f; /* 1 / 12102203.0; */
866}
867#endif
868
869/* hard-coded for length(M)=3 ... */
871(
872 void * const hUp6,
873 float X[3],
874 float M[3],
875 float S[3][3]
876)
877{
878 kf_update6_data *h = (kf_update6_data*)(hUp6);
879 float E, Snd_sum;
880 float DX[3], S_DX[3];
881
882 DX[0] = X[0]-M[0];
883 DX[1] = X[1]-M[1];
884 DX[2] = X[2]-M[2];
885 Snd_sum = S[0][1] + S[0][2] + S[1][2] + S[1][0] + S[2][0] + S[2][1];
886 if(Snd_sum<0.00001f){ /* If "S" is diagonal: */
887 S_DX[0] = 1.0f/S[0][0] * DX[0];
888 S_DX[1] = 1.0f/S[1][1] * DX[1];
889 S_DX[2] = 1.0f/S[2][2] * DX[2];
890 }
891 else
892 utility_sslslv(h->hLinSolve, (float*)S, 3, (float*)DX, 1, (float*)S_DX);
893 E = DX[0] * S_DX[0];
894 E += DX[1] * S_DX[1];
895 E += DX[2] * S_DX[2];
896 E *= 0.5f;
897
898#if defined(LITTLE_ENDIAN) && 0
899 E = E + 1.5f * SAF_LOG_2PI + 0.5f *
900 logf_fast(S[0][0] * (S[1][1] * S[2][2] - S[2][1] * S[1][2])-S[1][0] * (S[0][1] * S[2][2] - S[2][1] * S[0][2])+S[2][0] * (S[0][1] * S[1][2] - S[1][1] * S[0][2]));
901 return expf_fast(-E);
902#else
903 E = E + 1.5f * SAF_LOG_2PI + 0.5f * logf(S[0][0] * (S[1][1] * S[2][2] - S[2][1] * S[1][2])-S[1][0] * (S[0][1] * S[2][2] - S[2][1] * S[0][2])+S[2][0] * (S[0][1] * S[1][2] - S[1][1] * S[0][2]));
904 return expf(-E);
905#endif
906}
907
909(
910 float* P,
911 int len_P
912)
913{
914 int i;
915 float rand01, norm;
916 float Ptmp[TRACKER3D_MAX_NUM_EVENTS];
917
918 cblas_scopy(len_P, P, 1, Ptmp, 1);
919
920 /* Draw the categories */
921 norm = 1.0f/(sumf(Ptmp, len_P) + 2.23e-10f);
922 cblas_sscal(len_P, norm, Ptmp, 1);
923 for(i=1; i<len_P; i++)
924 Ptmp[i] += Ptmp[i-1];
925 rand_0_1(&rand01, 1);
926 rand01 = SAF_MIN(rand01, 0.9999f);
927 for(i=0; i<len_P; i++)
928 if(Ptmp[i]>rand01)
929 return i;
930
931 return -1; /* indicates error */
932}
933
934
935/* ========================================================================== */
936/* Static Functions */
937/* ========================================================================== */
938
939static double lngamma
940(
941 double x,
942 double* sgngam
943)
944{
945 double a, b, c, p, q, u, w, z, logpi, ls2pi, tmp, result;
946 int i;
947
948 *sgngam = 0;
949 *sgngam = (double)(1);
950 logpi = 1.14472988584940017414;
951 ls2pi = 0.91893853320467274178;
952 if( x<-34.0 ) {
953 q = -x;
954 w = lngamma(q, &tmp);
955 p = floor(q);
956 i = (int)floor(p+0.5);
957 if( i%2==0 )
958 *sgngam = (double)(-1);
959 else
960 *sgngam = (double)(1);
961 z = q-p;
962 if( z>0.5 ) {
963 p = p+1.0;
964 z = p-q;
965 }
966 z = q*sin(SAF_PId*z);
967 result = logpi-log(z)-w;
968 return result;
969 }
970 if( x<13.0 ) {
971 z = (double)(1);
972 p = (double)(0);
973 u = x;
974 while(u>=(double)3) {
975 p = p-1.0;
976 u = x+p;
977 z = z*u;
978 }
979 while(u<(double)2) {
980 z = z/u;
981 p = p+1;
982 u = x+p;
983 }
984 if( z<(double)0 ) {
985 *sgngam = (double)(-1);
986 z = -z;
987 }
988 else
989 *sgngam = (double)(1);
990 if( u==(double)(2) ) {
991 result = log(z);
992 return result;
993 }
994 p = p-2.0;
995 x = x+p;
996 b = -1378.25152569120859100;
997 b = -38801.6315134637840924+x*b;
998 b = -331612.992738871184744+x*b;
999 b = -1162370.97492762307383+x*b;
1000 b = -1721737.00820839662146+x*b;
1001 b = -853555.664245765465627+x*b;
1002 c = (double)(1);
1003 c = -351.815701436523470549+x*c;
1004 c = -17064.2106651881159223+x*c;
1005 c = -220528.590553854454839+x*c;
1006 c = -1139334.44367982507207+x*c;
1007 c = -2532523.07177582951285+x*c;
1008 c = -2018891.41433532773231+x*c;
1009 p = x*b/c;
1010 result = log(z)+p;
1011 return result;
1012 }
1013 q = (x-0.5)*log(x)-x+ls2pi;
1014 if( x>(double)(100000000) ) {
1015 result = q;
1016 return result;
1017 }
1018 p = 1.0/(x*x);
1019 if( x>=1000.0 )
1020 q = q+((7.9365079365079365079365*0.0001*p-2.7777777777777777777778*0.001)*p+0.0833333333333333333333)/x;
1021 else {
1022 a = 8.11614167470508450300*0.0001;
1023 a = -5.95061904284301438324*0.0001+p*a;
1024 a = 7.93650340457716943945*0.0001+p*a;
1025 a = -2.77777777730099687205*0.001+p*a;
1026 a = 8.33333333333331927722*0.01+p*a;
1027 q = q+a/x;
1028 }
1029 result = q;
1030 return result;
1031}
1032
1033static double incompletegammac
1034(
1035 double a,
1036 double x
1037)
1038{
1039 double igammaepsilon, igammabignumber, igammabignumberinv, result;
1040 double ans, ax, c, yc, r, t, y, z, pk, pkm1, pkm2, qk, qkm1, qkm2, tmp;
1041
1042 igammaepsilon = 0.000000000000001;
1043 igammabignumber = 4503599627370496.0;
1044 igammabignumberinv = 2.22044604925031308085*0.0000000000000001;
1045 if((x<=(double)(0))|| (a<=(double)(0)) ) {
1046 result = (double)(1);
1047 return result;
1048 }
1049 if( (x<(double)(1))||(x<a) ) {
1050 result = 1.0-incompletegamma(a, x);
1051 return result;
1052 }
1053 ax = a*log(x)-x-lngamma(a, &tmp);
1054 if( (ax<-709.78271289338399) ) {
1055 result = (double)(0);
1056 return result;
1057 }
1058 ax = exp(ax);
1059 y = 1.0-a;
1060 z = x+y+1.0;
1061 c = (double)(0);
1062 pkm2 = (double)(1);
1063 qkm2 = x;
1064 pkm1 = x+1;
1065 qkm1 = z*x;
1066 ans = pkm1/qkm1;
1067 do {
1068 c = c+1.0;
1069 y = y+1.0;
1070 z = z+2.0;
1071 yc = y*c;
1072 pk = pkm1*z-pkm2*yc;
1073 qk = qkm1*z-qkm2*yc;
1074 if( !(qk==(double)(0)) ) {
1075 r = pk/qk;
1076 t = fabs((ans-r)/r);
1077 ans = r;
1078 }
1079 else
1080 t = (double)(1);
1081 pkm2 = pkm1;
1082 pkm1 = pk;
1083 qkm2 = qkm1;
1084 qkm1 = qk;
1085 if( (fabs(pk)>igammabignumber) ) {
1086 pkm2 = pkm2*igammabignumberinv;
1087 pkm1 = pkm1*igammabignumberinv;
1088 qkm2 = qkm2*igammabignumberinv;
1089 qkm1 = qkm1*igammabignumberinv;
1090 }
1091 }
1092 while((t>igammaepsilon));
1093 result = ans*ax;
1094 return result;
1095}
1096
1097static double incompletegamma
1098(
1099 double a,
1100 double x
1101)
1102{
1103 double igammaepsilon, ans, ax, c, r, tmp, result;
1104
1105 igammaepsilon = 0.000000000000001;
1106 if( (x<=(double)(0))||(a<=(double)(0)) ) {
1107 result = (double)(0);
1108 return result;
1109 }
1110 if( (x>(double)(1))&&(x>a) ) {
1111 result = 1.0-incompletegammac(a, x);
1112 return result;
1113 }
1114 ax = a*log(x)-x-lngamma(a, &tmp);
1115 if( (ax<-709.78271289338399) ) {
1116 result = (double)(0);
1117 return result;
1118 }
1119 ax = exp(ax);
1120 r = a;
1121 c = (double)(1);
1122 ans = (double)(1);
1123 do {
1124 r = r+1.0;
1125 c = c*x/r;
1126 ans = ans+c;
1127 }
1128 while((c/ans>igammaepsilon));
1129 result = ans*ax/a;
1130 return result;
1131}
1132
1133#endif /* SAF_ENABLE_TRACKER_MODULE */
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
void utility_svvmul(const float *a, const float *b, const int len, float *c)
Single-precision, element-wise vector-vector multiplication i.e.
#define SAF_MAX(a, b)
Returns the maximum of the two values.
#define SAF_PId
pi constant (double precision)
void utility_sglslvt(void *const hWork, const float *A, const int dim, float *B, int nCol, float *X)
General linear solver (the other way): single precision, i.e.
void rand_0_1(float *vector, int length)
Generates random numbers between 0 and 1 and stores them in the input vector.
void utility_sglslv(void *const hWork, const float *A, const int dim, float *B, int nCol, float *X)
General linear solver: single precision, i.e.
void gexpm(float *D, int sizeD, int m1, float *Y)
Numerically solves first-order, linear, homogeneous differential equation systems,...
void utility_sglslvt_destroy(void **const phWork)
De-allocate the working struct used by utility_sglslvt()
void utility_sslslv_destroy(void **const phWork)
De-allocate the working struct used by utility_sslslv()
#define SAF_MIN(a, b)
Returns the minimum of the two values.
float sumf(float *values, int nValues)
Returns the sum of all values.
void utility_sslslv_create(void **const phWork, int maxDim, int maxNCol)
(Optional) Pre-allocate the working struct used by utility_sslslv()
void utility_svvadd(const float *a, const float *b, const int len, float *c)
Single-precision, vector-vector addition, i.e.
void utility_sglslvt_create(void **const phWork, int maxDim, int maxNCol)
(Optional) Pre-allocate the working struct used by utility_sglslvt()
void utility_sslslv(void *const hWork, const float *A, const int dim, float *B, int nCol, float *X)
Linear solver for SYMMETRIC positive-definate 'A': single precision, i.e.
float L2_norm3(float v[3])
Returns the L2 (Euclidean) norm of a 3-element vector.
void utility_svsmul(float *a, const float *s, const int len, float *c)
Single-precision, multiplies each element in vector 'a' with a scalar 's', i.e.
void ** malloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D malloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:89
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void * calloc1d(size_t dim1, size_t data_size)
1-D calloc (same as calloc, but with error checking)
Definition md_malloc.c:69
void * realloc1d(void *ptr, size_t dim1_data_size)
1-D realloc (same as realloc, but with error checking)
Definition md_malloc.c:79
void ** calloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:102
#define FLATTEN2D(A)
Use this macro when passing a 2-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:65
void * voidPtr
Void pointer (just to improve code readability when working with arrays of handles)
Particle filtering based 3D multi-target tracker (SAF_TRACKER_MODULE)
void tracker3d_update(void *const hT3d, float *Y, int Tinc)
Prediction update.
void tracker3d_particleDestroy(void **phPart)
Destroys an instance of a particle / Monte-Carlo Sample.
float gamma_cdf(float x, float gam, float beta, float mu)
Cumulative density function of a Gamma distribution.
void kf_update6(void *const hUp6, float X[6], float P[6][6], float y[3], float H[3][6], float R[3][3], float X_out[6], float P_out[6][6], float *LH)
Kalman Filter update step.
void tracker3d_particleReset(void *hPart)
Resets a particle structure to defaults.
int categ_rnd(float *P, int len_P)
Draws samples from a given one dimensional discrete distribution.
void kf_update6_create(void **const phUp6)
Creates helper structure for kf_update6()
void tracker3d_particleCopy(void *hPart1, void *hPart2)
Copies particle structure "hPart1" into structure "hPart2".
static double lngamma(double x, double *sgngam)
Natural logarithm of gamma function.
static double incompletegammac(double a, double x)
Complemented incomplete gamma integral.
void tracker3d_predict(void *const hT3d, int Tinc)
Prediction step.
void lti_disc(float *F, int len_N, int len_Q, float *opt_L, float *opt_Qc, float dt, float *A, float *Q)
LTI_DISC Discretize LTI ODE with Gaussian Noise.
int tracker3d_getMaxParticleIdx(void *const hT3d)
Returns the index of the most important particle.
void tracker3d_particleCreate(void **phPart, float W0, float dt)
Creates an instance of a particle / Monte-Carlo Sample.
void normalise_weights(voidPtr *SS, int NP)
Normalises the weights of the given particles.
float gauss_pdf3(void *const hUp6, float X[3], float M[3], float S[3][3])
Multivariate Gaussian PDF.
float eff_particles(voidPtr *SS, int NP)
Estimate the number of effective particles.
void kf_update6_destroy(void **const phUp6)
Destroys helper structure for kf_update6()
static double incompletegamma(double a, double x)
Incomplete gamma integral.
void kf_predict6(float M[6], float P[6][6], float A[6][6], float Q[6][6])
Perform Kalman Filter prediction step.
#define SAF_LOG_2PI
log(2pi)
void resampstr(voidPtr *SS, int NP, int *s)
Stratified resampling - returns a new set of indices according to the probabilities P.
Particle filtering based 3D multi-target tracker (SAF_TRACKER_MODULE)
#define TRACKER3D_MAX_NUM_EVENTS
Maximum number of possible events during update.
#define TRACKER3D_MAX_NUM_TARGETS
Spits out tracker status info to the terminal.
#define TRACKER3D_MAX_NUM_PARTICLES
Maximum number of particles.
Union struct for 3-D mean values.
Monte-Carlo Sample (particle) structure.
P66 * P
Current target variances; nTargets x ([6][6])
float dt
Elapsed time between each observation/measurement.
float W
Importance weight.
int * targetIDs
Unique ID assigned to each target; nTargets x 1.
float W0
PRIOR importance weight.
int nTargets
Number of targets being tracked.
int * Tcount
Time elapsed since birth of target (Tcount * dt); nTargets x 1.
float W_prev
Previous importance weight.
M6 * M
Current target means; nTargets x ([6])
Union struct for 3-D variance values.
Data structure for kf_update6()
User parameters for tracker3d.
Definition saf_tracker.h:59
float M0[6]
[0,1,2] Position of sound source PRIORs (x,y,z), [3,4,5] Mean velocity PRIORs (x,y,...
Definition saf_tracker.h:97
float cd
PRIOR probability of noise.
float init_birth
PRIOR probability of birth [0 1].
Definition saf_tracker.h:79
int ALLOW_MULTI_DEATH
FLAG whether to allow for multiple target deaths in the same tracker prediction step.
Definition saf_tracker.h:76
int FORCE_KILL_TARGETS
FLAG force kill targets that are too close to one another.
Definition saf_tracker.h:90
float P0[6][6]
Diagonal matrix, [0,1,2] Variance PRIORs of estimates along the x,y,z axes; [3,4,5] Velocity PRIORs o...
int maxNactiveTargets
Maximum number of simultaneous targets permitted.
Definition saf_tracker.h:67
int ARE_UNIT_VECTORS
1: if the Cartesian coordinates are given as unit vectors, 0: if not
Definition saf_tracker.h:65
float beta_death
Coefficient influencing the likelihood that a target will die; always >= 1.
Definition saf_tracker.h:82
float alpha_death
Coefficient influencing the likelihood that a target will die; always >= 1.
Definition saf_tracker.h:80
int Np
Number of Monte Carlo samples/particles.
Definition saf_tracker.h:60
float noiseLikelihood
Likelihood of an estimate being noise/clutter between [0..1].
Definition saf_tracker.h:69
Main structure for tracker3d.
float Q[6][6]
Discrete Process Covariance.
tracker3d_config tpars
User parameters struct.
float R[3][3]
Diagonal matrix, measurement noise PRIORs along the x,y,z axes.
int evta[TRACKER3D_MAX_NUM_EVENTS]
Event targets.
voidPtr str[TRACKER3D_MAX_NUM_EVENTS]
Structure after each event.
float evl[TRACKER3D_MAX_NUM_EVENTS]
Event likelhoods.
voidPtr * SS
The particles; tpars.Np x 1.
float A[6][6]
Transition matrix.
float evp[TRACKER3D_MAX_NUM_EVENTS]
Event priors.
float H[3][6]
Measurement matrix.
float imp[TRACKER3D_MAX_NUM_EVENTS]
Event distributions.
void * hKF6
kf_update6 handle