32 #define isfinite _finite
50 IndexSet(
unsigned int max_size) :
51 size_(0), max_size_(max_size), data_(new unsigned int[max_size]) {}
52 unsigned int get_size()
const {
58 unsigned int& operator[](
unsigned int n) {
61 unsigned int operator[](
unsigned int n)
const {
64 void set_size(
unsigned int size) {
67 bool exist(
unsigned int elem) {
69 for(
unsigned int i = 0; i < size_; ++i) {
70 if(data_[i] == elem) {
77 bool insert(
unsigned int elem) {
79 if((size_ < max_size_) && (
false ==
exist(elem))) {
80 data_[size_++] = elem;
85 bool remove(
unsigned int elem) {
87 for(
unsigned int i = 0; i < size_; ++i) {
88 if(data_[i] == elem) {
90 memcpy(data_ + i, data_ + i + 1, (size_ - i - 1)*
sizeof(*data_));
101 unsigned int max_size_;
109 static double get_dist(
const Point *p0,
const Point *p1) {
111 double *coord_p0 = (
double*)p0;
112 double *coord_p1 = (
double*)p1;
113 for(
int n = 0; n < 3; ++n) {
114 out += (coord_p1[n] - coord_p0[n]) * (coord_p1[n] - coord_p0[n]);
118 static bool test_uniqueness(
const Point *bs_pos,
int bs_pos_len,
double eps) {
121 for(i = bs_pos_len - 1; i >= 0; --i) {
122 for(j = i - 1; j >= 0; --j) {
123 if((fabs(bs_pos[i].x - bs_pos[j].x) < eps) && (fabs(bs_pos[i].y - bs_pos[j].y) < eps) &&
124 (fabs(bs_pos[i].z - bs_pos[j].z) < eps)) {
132 static double det_3by3(
const double mat[9]) {
133 return mat[0] * (mat[4] * mat[8] - mat[5] * mat[7]) + mat[3] * (mat[2] * mat[7] - mat[1] * mat[8]) + mat[6] * (mat[1] * mat[5] - mat[2] * mat[4]);
135 static double det_4by4(
const double mat[16]) {
136 return mat[0] * mat[5] * mat[10] * mat[15] + mat[0] * mat[9] * mat[14] * mat[7] + mat[0] * mat[13] * mat[6] * mat[11] +
137 mat[4] * mat[1] * mat[14] * mat[11] + mat[4] * mat[9] * mat[2] * mat[15] + mat[4] * mat[13] * mat[10] * mat[3] +
138 mat[8] * mat[1] * mat[6] * mat[15] + mat[8] * mat[5] * mat[14] * mat[3] + mat[8] * mat[13] * mat[2] * mat[7] +
139 mat[12] * mat[1] * mat[10] * mat[7] + mat[12] * mat[5] * mat[2] * mat[11] + mat[12] * mat[9] * mat[6] * mat[3] -
140 mat[0] * mat[5] * mat[14] * mat[11] - mat[0] * mat[9] * mat[6] * mat[15] - mat[0] * mat[13] * mat[10] * mat[7] -
141 mat[4] * mat[1] * mat[10] * mat[15] - mat[4] * mat[9] * mat[14] * mat[3] - mat[4] * mat[13] * mat[2] * mat[11] -
142 mat[8] * mat[1] * mat[14] * mat[7] - mat[8] * mat[5] * mat[2] * mat[15] - mat[8] * mat[13] * mat[6] * mat[3] -
143 mat[12] * mat[1] * mat[6] * mat[11] - mat[12] * mat[5] * mat[10] * mat[3] - mat[12] * mat[9] * mat[2] * mat[7];
145 static bool inv_3by3(
double *
inv,
const double *mat) {
146 double det = det_3by3(mat);
147 if((0 == det) || (0 == isfinite(det))) {
148 memset(inv, 0, 9 *
sizeof(*inv));
151 inv[0] = (mat[4] * mat[8] - mat[5] * mat[7]) / det;
152 inv[1] = (mat[2] * mat[7] - mat[1] * mat[8]) / det;
153 inv[2] = (mat[1] * mat[5] - mat[2] * mat[4]) / det;
154 inv[3] = (mat[5] * mat[6] - mat[3] * mat[8]) / det;
155 inv[4] = (mat[0] * mat[8] - mat[2] * mat[6]) / det;
156 inv[5] = (mat[2] * mat[3] - mat[0] * mat[5]) / det;
157 inv[6] = (mat[3] * mat[7] - mat[4] * mat[6]) / det;
158 inv[7] = (mat[1] * mat[6] - mat[0] * mat[7]) / det;
159 inv[8] = (mat[0] * mat[4] - mat[1] * mat[3]) / det;
163 static bool test_noncoplanar(
const Point *bs_pos,
int bs_pos_len) {
165 double *coord[] = {NULL, NULL};
169 if((NULL == bs_pos) || (4 != bs_pos_len)) {
174 coord[0] = (
double*)bs_pos;
175 for(i = 0; i < 3; ++i) {
176 coord[1] = (
double*)(bs_pos + i + 1);
177 for(j = 0; j < 3; ++j) {
178 mat[i + 3 * j] = (*(coord[1] + j)) - (*(coord[0] + j));
181 return (0 != det_3by3(mat)) ?
true :
false;
183 static bool combination(
unsigned int *comb_mat,
unsigned int *nb_cols,
unsigned int nb_rows,
unsigned int len) {
184 unsigned int idx = 0;
185 unsigned int j, k, l, m;
187 if((NULL == comb_mat) || (NULL == nb_cols)) {
198 for(j = 1; j < len; ++j) {
199 for(k = j + 1; k < len; ++k) {
200 for(l = k + 1; l < len; ++l) {
201 for(m = l + 1; m < len; ++m) {
214 for(j = 1; j < len; ++j) {
215 for(k = j + 1; k < len; ++k) {
216 for(l = k + 1; l < len; ++l) {
227 for(j = 1; j < len; ++j) {
228 for(k = j + 1; k < len; ++k) {
237 for(j = 1; j < len; ++j) {
248 *nb_cols = idx / nb_rows;
251 static unsigned int comb_nb(
unsigned int n,
unsigned int k) {
253 unsigned int nom = 1;
254 unsigned int denom = 1;
256 for(i = k + 1; i <= n; ++i) {
260 for(i = 2; i <= (n - k); ++i) {
265 static bool update_subsets(IndexSet &used_subset_idx, IndexSet &unused_subset_idx,
266 const unsigned int *subset_idx,
unsigned int subset_idx_len) {
269 for(i = 0; i < subset_idx_len; ++i) {
270 if((
true == used_subset_idx.insert(subset_idx[i])) &&
271 (
false == unused_subset_idx.remove(subset_idx[i]))) {
279 static bool store_subset(
unsigned int **subsets,
unsigned int *in_subset,
unsigned int in_subset_len,
unsigned int in_subset_idx) {
283 *subsets = (
unsigned int*)realloc(*subsets, (in_subset_idx + 1) * in_subset_len *
sizeof(**subsets));
284 if(NULL != *subsets) {
286 memcpy((*subsets) + in_subset_idx * in_subset_len, in_subset, in_subset_len *
sizeof(*in_subset));
300 enum GeoPos {GEO_POS_NO = 0, GEO_POS_YES, GEO_POS_EXACT};
301 virtual GeoPos validate(
const Point *bs_pos,
unsigned int bs_pos_len,
const double *r) = 0;
302 virtual bool setup(
const Point *bs_pos,
unsigned int bs_pos_len) = 0;
304 virtual bool get_pos(Point *ms_pos,
const double *range,
unsigned int range_len) = 0;
305 virtual void set_meas_mat(
const double *meas) = 0;
306 virtual void get_meas(
double *meas,
const unsigned int *bs_subset_idx,
unsigned int len) = 0;
307 virtual bool get_meas_mult_mat(
const unsigned int *bs_pos_idx,
unsigned int rows,
unsigned int cols) = 0;
308 virtual void get_meas_mult(
unsigned int *meas_mult,
const unsigned int *subset_idx,
unsigned int meas_mult_len) = 0;
309 virtual bool get_grad(
double *grad,
const Point *bs_pos,
unsigned int bs_nb,
const Point *ms_pos) = 0;
310 virtual double* get_meas_mat()
const = 0;
311 virtual unsigned int* get_mult_mat()
const = 0;
312 virtual ~Algorithm() {}
315 class Spherical :
public Algorithm
318 explicit Spherical(
unsigned int nb_bs);
319 virtual ~Spherical();
320 virtual Algorithm::GeoPos validate(
const Point *bs_pos,
unsigned int bs_pos_len,
const double *r);
321 virtual bool setup(
const Point *bs_pos,
unsigned int bs_pos_len);
322 virtual bool get_pos(Point *ms_pos,
const double *range,
unsigned int range_len);
323 virtual void set_meas_mat(
const double *meas) {
324 memcpy(meas_mat_, meas, nb_bs_ *
sizeof(*meas));
326 virtual void get_meas(
double *meas,
const unsigned int *bs_subset_idx,
unsigned int len);
327 virtual bool get_meas_mult_mat(
const unsigned int *bs_pos_idx,
unsigned int rows,
unsigned int cols);
328 virtual void get_meas_mult(
unsigned int *meas_mult,
const unsigned int *subset_idx,
unsigned int meas_mult_len);
329 virtual bool get_grad(
double *grad,
const Point *bs_pos,
unsigned int bs_nb,
const Point *ms_pos);
330 virtual double* get_meas_mat()
const {
333 virtual unsigned int* get_mult_mat()
const {
337 double mult_vTMw(
double v[2],
double M[4],
double w[2]) {
338 return w[0] * (M[0] * v[0] + M[1] * v[1]) + w[1] * (M[2] * v[0] + M[3] * v[1]);
340 double comp_quadratic(
double *u,
const double *range) {
346 v[1] = u[1] = range[0] * range[0];
347 v[2] = u[2] = range[1] * range[1];
348 v[3] = u[3] = range[2] * range[2];
358 scalar = xi[0] * v[0];
359 for(i = 1; i < 10; ++i) {
360 scalar += xi[i] * v[i];
366 unsigned int bs_pos_len_;
373 unsigned int *mult_mat_;
376 Spherical::Spherical(
unsigned int nb_bs) :
378 meas_mat_(new double[nb_bs]),
379 mult_mat_(new unsigned int [nb_bs])
383 Spherical::~Spherical()
390 Algorithm::GeoPos Spherical::validate(
const Point *bs_pos,
unsigned int bs_pos_len,
const double *r)
392 GeoPos out = GEO_POS_NO;
398 if(
true == Spherical::setup(bs_pos, bs_pos_len)) {
400 double scalar = comp_quadratic(u, r);
404 else if((0 < scalar) && (1 == bs_pos_len_)) {
414 bool Spherical::setup(
const Point *bs_pos,
unsigned int bs_pos_len)
436 memset(xi, 0,
sizeof(xi));
437 memset(Lambda, 0,
sizeof(Lambda));
438 memset(mu, 0,
sizeof(mu));
441 for(i = 0; i < 3; ++i) {
442 S[i] = bs_pos[i].x * bs_pos[i].x + bs_pos[i].y * bs_pos[i].y + bs_pos[i].z * bs_pos[i].z;
444 W[0] = bs_pos[1].x - bs_pos[0].x;
445 W[1] = bs_pos[2].x - bs_pos[0].x;
446 W[2] = bs_pos[1].y - bs_pos[0].y;
447 W[3] = bs_pos[2].y - bs_pos[0].y;
448 detW = W[0] * W[3] - W[1] * W[2];
453 invW[0] = W[3] / detW;
454 invW[1] = -W[1] / detW;
455 invW[2] = -W[2] / detW;
456 invW[3] = W[0] / detW;
457 G[0] = invW[0] * invW[0] + invW[1] * invW[1];
458 G[1] = invW[0] * invW[2] + invW[1] * invW[3];
460 G[3] = invW[2] * invW[2] + invW[3] * invW[3];
461 rh1[0] = bs_pos[0].x;
462 rh1[1] = bs_pos[0].y;
463 for(i = 0; i < 2; ++i) {
464 d[i] = bs_pos[i + 1].z - bs_pos[0].z;
465 delta[i] = S[0] - S[i + 1];
467 for(i = 0; i < 2; ++i) {
468 e[i] = 0.5 * (delta[0] * G[2 * i] + delta[1] * G[2 * i + 1]) + rh1[0] * invW[2 * i] + rh1[1] * invW[2 * i + 1];
470 a = 1.0 + mult_vTMw(d, G, d);
472 lambda[0] = -(2 * mult_vTMw(rh1, invW, d) - 2 * bs_pos[0].z + mult_vTMw(d, G, delta)) / (2 * a);
473 lambda[1] = ((bs_pos[1].z - bs_pos[0].z) * (G[0] + G[1]) + (bs_pos[2].z - bs_pos[0].z) * (G[1] + G[3])) / (2 * a);
474 lambda[2] = -((bs_pos[1].z - bs_pos[0].z) * G[0] + (bs_pos[2].z - bs_pos[0].z) * G[1]) / (2 * a);
475 lambda[3] = -((bs_pos[2].z - bs_pos[0].z) * G[3] + (bs_pos[1].z - bs_pos[0].z) * G[1]) / (2 * a);
477 xi[0] = lambda[0] * lambda[0] - (0.25 * mult_vTMw(delta, G, delta) + mult_vTMw(rh1, invW, delta) + S[0]) / a;
478 xi[1] = 2 * lambda[0] * lambda[1] + (1 + e[0] + e[1]) / a;
479 xi[2] = 2 * lambda[0] * lambda[2] - e[0] / a;
480 xi[3] = 2 * lambda[0] * lambda[3] - e[1] / a;
481 xi[4] = lambda[1] * lambda[1] - (G[0] + 2 * G[1] + G[3]) / (4 * a);
482 xi[5] = lambda[2] * lambda[2] - G[0] / (4 * a);
483 xi[6] = lambda[3] * lambda[3] - G[3] / (4 * a);
484 xi[7] = 2 * lambda[1] * lambda[2] + (G[0] + G[1]) / (2 * a);
485 xi[8] = 2 * lambda[1] * lambda[3] + (G[1] + G[3]) / (2 * a);
486 xi[9] = 2 * lambda[2] * lambda[3] - G[1] / (2 * a);
488 w1Td = invW[0] * d[0] + invW[2] * d[1];
489 w2Td = invW[1] * d[0] + invW[3] * d[1];
491 Lambda[0] = -w1Td * lambda[0] - (invW[0] * delta[0] + invW[2] * delta[1]) / 2;
492 Lambda[3] = -w1Td * lambda[1] + (bs_pos[2].y - bs_pos[1].y) / (2 * detW);
493 Lambda[6] = -w1Td * lambda[2] - (bs_pos[2].y - bs_pos[0].y) / (2 * detW);
494 Lambda[9] = -w1Td * lambda[3] + (bs_pos[1].y - bs_pos[0].y) / (2 * detW);
496 Lambda[1] = -w2Td * lambda[0] - (invW[1] * delta[0] + invW[3] * delta[1]) / 2;
497 Lambda[4] = -w2Td * lambda[1] + (bs_pos[1].x - bs_pos[2].x) / (2 * detW);
498 Lambda[7] = -w2Td * lambda[2] + (bs_pos[2].x - bs_pos[0].x) / (2 * detW);
499 Lambda[10] = -w2Td * lambda[3] - (bs_pos[1].x - bs_pos[0].x) / (2 * detW);
501 Lambda[2] = lambda[0];
502 Lambda[5] = lambda[1];
503 Lambda[8] = lambda[2];
504 Lambda[11] = lambda[3];
514 if(4 == bs_pos_len) {
515 if(
false == PosHelper::test_noncoplanar(bs_pos, bs_pos_len)) {
526 bool Spherical::get_pos(Point *ms_pos,
const double *range,
unsigned int range_len)
532 double *coord = NULL;
535 it_warning(
"at least 3 measurements are needed");
538 if(0 == bs_pos_len_) {
539 it_warning(
"geo_spheric_setup needs to be called first");
543 scalar = comp_quadratic(u, range);
545 it_warning(
"square root from negative number");
553 coord = (
double*)ms_pos;
554 for(j = 0; j < 3; ++j) {
555 coord[j] = mu[j] * scalar;
556 for(i = 0; i < 4; ++i) {
557 coord[j] += Lambda[3 * i + j] * u[i];
566 coord = (
double*)(&tmp_pos);
567 for(j = 0; j < 3; ++j) {
568 coord[j] = mu[3 + j] * scalar;
569 for(i = 0; i < 4; ++i) {
570 coord[j] += Lambda[3 * i + j] * u[i];
574 r1[0] = fabs(PosHelper::get_dist(ms_pos, &bs_pos_) - range[3]);
575 r1[1] = fabs(PosHelper::get_dist(&tmp_pos, &bs_pos_) - range[3]);
584 void Spherical::get_meas(
double *meas,
const unsigned int *bs_subset_idx,
unsigned int len)
587 for(i = 0; i < len; ++i) {
588 meas[i] = meas_mat_[bs_subset_idx[i]];
592 bool Spherical::get_meas_mult_mat(
const unsigned int *bs_pos_idx,
unsigned int rows,
unsigned int cols)
594 memset(mult_mat_, 0, nb_bs_ *
sizeof(*mult_mat_));
599 for(
unsigned int i = 0; i < (rows * cols); ++i) {
600 if(nb_bs_ <= bs_pos_idx[i]) {
603 ++mult_mat_[bs_pos_idx[i]];
608 void Spherical::get_meas_mult(
unsigned int *meas_mult,
const unsigned int *subset_idx,
unsigned int meas_mult_len)
610 for(
unsigned int i = 0; i < meas_mult_len; ++i) {
611 meas_mult[i] = mult_mat_[subset_idx[i]];
615 bool Spherical::get_grad(
double *grad,
const Point *bs_pos,
unsigned int bs_nb,
const Point *ms_pos)
617 double *coord_ms = NULL;
618 double *coord_bs = NULL;
623 coord_ms = (
double*)ms_pos;
624 for(n = 0; n < bs_nb; ++n) {
625 denom = PosHelper::get_dist(ms_pos, bs_pos + n);
630 coord_bs = (
double*)(bs_pos + n);
631 for(i = 0; i < 3; ++i) {
632 grad[i + 3 * n] = (coord_ms[i] - coord_bs[i]) / denom;
638 class Hyperbolic :
public Algorithm
641 explicit Hyperbolic(
unsigned int nb_bs);
642 virtual ~Hyperbolic();
643 virtual Algorithm::GeoPos validate(
const Point *bs_pos,
unsigned int bs_pos_len,
const double *r);
644 virtual bool setup(
const Point *bs_pos,
unsigned int bs_pos_len);
645 virtual bool get_pos(Point *ms_pos,
const double *range,
unsigned int range_len);
646 virtual void set_meas_mat(
const double *meas) {
647 memcpy(meas_mat_, meas, nb_bs_ * nb_bs_ *
sizeof(*meas));
649 virtual void get_meas(
double *meas,
const unsigned int *bs_subset_idx,
unsigned int len);
650 virtual bool get_meas_mult_mat(
const unsigned int *bs_pos_idx,
unsigned int rows,
unsigned int cols);
651 virtual void get_meas_mult(
unsigned int *meas_mult,
const unsigned int *subset_idx,
unsigned int meas_mult_len);
652 virtual bool get_grad(
double *grad,
const Point *bs_pos,
unsigned int bs_nb,
const Point *ms_pos);
653 virtual double* get_meas_mat()
const {
656 virtual unsigned int* get_mult_mat()
const {
660 double dot_prod(
const double *v,
const double *w,
int len) {
661 double out = v[0] * w[0];
663 for(i = 1; i < len; ++i) {
668 char comp_quadratic(
double *c,
double *r1,
double *beta,
const double *r) {
669 double diff_range2[3];
677 for(i = 0; i < 3; ++i) {
678 diff_range2[i] = r[i] * r[i];
680 coord = (
double*)(bs_pos_);
681 for(i = 0; i < 3; ++i) {
682 c[i] = b[i] - 0.5 * dot_prod(A + 3 * i, diff_range2, 3);
683 alpha[i] = coord[i] - c[i];
684 beta[i] = dot_prod(A + 3 * i, r, 3);
690 for(i = 0; i < 3; ++i) {
691 d += beta[i] * beta[i];
692 e += 2 * alpha[i] * beta[i];
693 f += alpha[i] * alpha[i];
695 delta = e * e - 4 * d * f;
705 r1[0] = (-e +
std::sqrt(delta)) / (2 * d);
706 r1[1] = (-e -
std::sqrt(delta)) / (2 * d);
714 unsigned int bs_pos_len_;
717 unsigned int *mult_mat_;
721 Hyperbolic::Hyperbolic(
unsigned int nb_bs) :
723 meas_mat_(new double[nb_bs*nb_bs]),
724 mult_mat_(new unsigned int[nb_bs*nb_bs])
728 Hyperbolic::~Hyperbolic()
734 bool Hyperbolic::setup(
const Point *bs_pos,
unsigned int bs_pos_len)
741 if((4 > bs_pos_len) || (NULL == bs_pos)) {
746 memset(b, 0,
sizeof(b));
747 memset(A, 0,
sizeof(A));
748 memset(bs_pos_, 0,
sizeof(bs_pos_));
751 for(i = 0; i < 3; ++i) {
752 tmp[i] = bs_pos[i + 1].x - bs_pos[0].x;
753 tmp[i + 3] = bs_pos[i + 1].y - bs_pos[0].y;
754 tmp[i + 2 * 3] = bs_pos[i + 1].z - bs_pos[0].z;
756 if(
false == PosHelper::inv_3by3(A, tmp)) {
761 for(i = 0; i < 3; ++i) {
763 tmp[3 * i + 1] = A[3 + i];
764 tmp[3 * i + 2] = A[6 + i];
766 memcpy(A, tmp,
sizeof(A));
768 K0 = bs_pos[0].x * bs_pos[0].x + bs_pos[0].y * bs_pos[0].y + bs_pos[0].z * bs_pos[0].z;
769 for(i = 0; i < 3; ++i) {
770 K[i] = bs_pos[i + 1].x * bs_pos[i + 1].x + bs_pos[i + 1].y * bs_pos[i + 1].y + bs_pos[i + 1].z * bs_pos[i + 1].z - K0;
772 for(i = 0; i < 3; ++i) {
773 b[i] = 0.5 * dot_prod(A + 3 * i, K, 3);
776 memcpy(bs_pos_, bs_pos,
sizeof(bs_pos_[0]));
778 if(5 == bs_pos_len) {
781 if(
false == PosHelper::test_uniqueness(bs_pos, bs_pos_len, 1e-3)) {
785 memcpy(bs_pos_ + 1, bs_pos + 4,
sizeof(bs_pos_[1]));
792 Algorithm::GeoPos Hyperbolic::validate(
const Point *bs_pos,
unsigned int bs_pos_len,
const double *r)
797 Algorithm::GeoPos out = GEO_POS_NO;
800 if((NULL == bs_pos) || (0 == bs_pos_len) || (NULL == r)) {
805 if(
true == setup(bs_pos, bs_pos_len)) {
808 delta_sign = comp_quadratic(c, r1, beta, r);
811 if(0 == delta_sign) {
815 else if((0 < delta_sign) && (2 == bs_pos_len_)) {
820 for(i = 0; i < 4; ++i) {
821 tmp[i] = bs_pos[i + 1].x - bs_pos[0].x;
822 tmp[4 + i] = bs_pos[i + 1].y - bs_pos[0].y;
823 tmp[2 * 4 + i] = bs_pos[i + 1].z - bs_pos[0].z;
824 tmp[3 * 4 + i] = r[i];
826 det = PosHelper::det_4by4(tmp);
827 out = (0 !=
det) ? GEO_POS_YES : GEO_POS_NO;
833 bool Hyperbolic::get_pos(Point *ms_pos,
const double *r,
unsigned int r_len)
842 if((3 > r_len) || (NULL == r)) {
843 it_warning(
"at least 3 measurements are needed");
850 if(0 == bs_pos_len_) {
851 it_warning(
"geo_hyper_setup needs to be called first");
856 delta_sign = comp_quadratic(c, r1, beta, r);
859 if(0 == delta_sign) {
861 coord = (
double*)(ms_pos);
862 for(j = 0; j < 3; ++j) {
863 coord[j] = c[j] - beta[j] * r1[0];
869 if((4 != r_len) || (2 != bs_pos_len_)) {
870 it_warning(
"4 measurements from 5 BSs are needed");
874 for(i = 0; i < 2; ++i) {
875 coord = (
double*)(out + i);
876 for(j = 0; j < 3; ++j) {
877 coord[j] = c[j] - beta[j] * r1[i];
881 for(i = 0; i < 2; ++i) {
882 r1[i] = PosHelper::get_dist(bs_pos_ + 1, out + i) - PosHelper::get_dist(bs_pos_, out + i);
883 r1[i] = fabs(r1[i] - r[3]);
888 memcpy(ms_pos, out + j,
sizeof(*ms_pos));
893 void Hyperbolic::get_meas(
double *meas,
const unsigned int *bs_subset_idx,
unsigned int len)
895 for(
unsigned int i = 0; i < (len - 1); ++i) {
896 meas[i] = meas_mat_[bs_subset_idx[i + 1] + nb_bs_ * bs_subset_idx[0]];
900 bool Hyperbolic::get_meas_mult_mat(
const unsigned int *bs_pos_idx,
unsigned int rows,
unsigned int cols)
904 memset(mult_mat_, 0, nb_bs_ * nb_bs_ *
sizeof(*mult_mat_));
909 for(j = 0; j < cols; ++j) {
910 if(nb_bs_ <= bs_pos_idx[rows * j]) {
913 for(i = 0; i < (rows - 1); ++i) {
914 if(nb_bs_ <= bs_pos_idx[i + 1 + rows * j]) {
917 ++mult_mat_[bs_pos_idx[i + 1 + rows * j] + nb_bs_ * bs_pos_idx[rows * j]];
923 void Hyperbolic::get_meas_mult(
unsigned int *meas_mult,
const unsigned int *subset_idx,
unsigned int meas_mult_len)
925 for(
unsigned int i = 0; i < meas_mult_len; ++i) {
926 meas_mult[i] = mult_mat_[subset_idx[i + 1] + nb_bs_ * subset_idx[0]];
934 bool Hyperbolic::get_grad(
double *grad,
const Point *bs_pos,
unsigned int bs_nb,
const Point *ms_pos)
937 double *coord_ms = NULL;
938 double *coord_bs = NULL;
943 denom = PosHelper::get_dist(ms_pos, bs_pos);
948 coord_ms = (
double*)ms_pos;
949 coord_bs = (
double*)bs_pos;
950 for(i = 0; i < 3; ++i) {
951 dr[i] = (coord_ms[i] - coord_bs[i]) / denom;
953 for(n = 1; n < bs_nb; ++n) {
954 denom = PosHelper::get_dist(ms_pos, bs_pos + n);
959 coord_bs = (
double*)(bs_pos + n);
960 for(i = 0; i < 3; ++i) {
961 grad[i + 3 * (n - 1)] = (coord_ms[i] - coord_bs[i]) / denom - dr[i];
967 bool Multilateration::set_method(
const itpp::bvec &method)
969 int method_len =
length(method);
975 if((0 == nb_bs_) || (4 > method_len)) {
976 it_warning(
"BSs positions are not set or too small method length");
982 for(n = 0; n < method_len; ++n) {
983 if(bin(1) == method[n]) {
987 if(n == method_len) {
992 for(n = 0; n < method_len; ++n) {
993 if(bin(0) == method[n]) {
997 if(n == method_len) {
1011 if((method_len + 1) != nb_bs_) {
1012 it_warning(
"For hyperbolic multilateration the number of BSs should exceed by one the number of measures");
1015 algo_ =
new Hyperbolic(nb_bs_);
1018 if((method_len + 1) != nb_bs_) {
1019 it_warning(
"For hybrid multilateration the number of BSs should exceed by one the number of measures");
1022 algo_ =
new Spherical(nb_bs_ - 1);
1025 if(method_len != nb_bs_) {
1026 it_warning(
"For spherical multilateration the number of BSs should equal the number of measures");
1029 algo_ =
new Spherical(nb_bs_);
1032 it_warning(
"unknown multilateration method");
1035 nb_fails_part = nb_fails_pos = 0;
1037 return (NULL != algo_) ?
true :
false;
1040 bool Multilateration::set_bs_pos(
const itpp::mat &bs_pos)
1042 int rows = bs_pos.rows();
1043 int cols = bs_pos.cols();
1045 if(((3 != cols) && (3 != rows)) || (cols == rows)) {
1046 it_warning(
"BS positions should be specified in 3D cartezian coordinates on either columns or rows");
1049 nb_bs_ = (3 == cols) ? rows : cols;
1050 if(NULL != bs_pos_) {
1053 bs_pos_ =
new Point[nb_bs_];
1056 for(n = 0; n < nb_bs_; ++n) {
1057 bs_pos_[n].x = bs_pos(n, 0);
1058 bs_pos_[n].y = bs_pos(n, 1);
1059 bs_pos_[n].z = bs_pos(n, 2);
1062 else if(3 == rows) {
1063 for(n = 0; n < nb_bs_; ++n) {
1064 bs_pos_[n].x = bs_pos(0, n);
1065 bs_pos_[n].y = bs_pos(1, n);
1066 bs_pos_[n].z = bs_pos(2, n);
1080 unsigned int *subsets_idx = NULL;
1081 unsigned int subsets_nb = 0;
1082 unsigned int subset_len = 0;
1083 Point *tmp_bs_pos = NULL;
1084 Point *bs_pos = bs_pos_;
1085 unsigned int nb_bs = nb_bs_;
1087 const int method_len =
length(method_);
1090 if((0 == method_len) || (NULL == bs_pos_) || (0 == nb_bs_) || (NULL == algo_)) {
1094 algo_->set_meas_mat(measures);
1101 tmp_bs_pos = (Point*)malloc(nb_bs_ *
sizeof(*tmp_bs_pos));
1102 memcpy(tmp_bs_pos, bs_pos_, nb_bs_ *
sizeof(*tmp_bs_pos));
1103 if(
false == hybrid2spherical(tmp_bs_pos, algo_->get_meas_mat())) {
1106 bs_pos = tmp_bs_pos;
1118 if((
false == partition(&subsets_idx, &subsets_nb, bs_pos, nb_bs, subset_len)) || (0 == subsets_nb)) {
1121 if(0 != subsets_nb) {
1122 if(
false == algo_->get_meas_mult_mat(subsets_idx, subset_len, subsets_nb)) {
1125 if(
false == get_ml_pos(&tmp_ms_pos, bs_pos, nb_bs, subsets_idx, subsets_nb, subset_len)) {
1130 ms_pos(0) = tmp_ms_pos.x;
1131 ms_pos(1) = tmp_ms_pos.y;
1132 ms_pos(2) = tmp_ms_pos.z;
1136 out = (0 != subsets_nb) ?
true :
false;
1140 if(NULL != subsets_idx) {
1145 if(NULL != tmp_bs_pos) {
1153 bool Multilateration::hybrid2spherical(Point *bs_pos,
double *meas)
1157 Point *out_bs_pos = NULL;
1158 double *out_meas = NULL;
1159 int method_len =
length(method_);
1160 static const bin zero = bin(0);
1162 if((4 > method_len) || (NULL == bs_pos) || (NULL == meas)) {
1171 for(n = 0; n < method_len; ++n) {
1172 if(zero == method_[n]) {
1176 if(n == method_len) {
1180 out_bs_pos = (Point*)malloc(method_len *
sizeof(*out_bs_pos));
1181 if(NULL == out_bs_pos) {
1184 out_meas = (
double*)malloc(method_len *
sizeof(*out_meas));
1185 if(NULL == out_meas) {
1192 out_meas[0] = meas[0];
1193 out_bs_pos[0] = bs_pos[0];
1194 for(k = 1; k < method_len; ++k) {
1195 if(zero == method_[k]) {
1196 out_bs_pos[k] = bs_pos[k];
1197 out_meas[k] = meas[k];
1200 out_meas[k] = meas[k] + out_meas[0];
1201 out_bs_pos[k] = bs_pos[k + 1];
1209 out_meas[0] = meas[n] - meas[n - 1];
1210 out_bs_pos[0] = bs_pos[0];
1211 for(k = 0; k < method_len; ++k) {
1215 if(zero == method_[k]) {
1216 out_bs_pos[idx] = bs_pos[k];
1217 out_meas[idx] = meas[k];
1220 out_bs_pos[idx] = bs_pos[k + 1];
1221 out_meas[idx] = meas[k] + out_meas[0];
1228 for(k = 0; k < method_len; ++k) {
1229 bs_pos[k] = out_bs_pos[k];
1230 meas[k] = out_meas[k];
1238 bool Multilateration::partition(
unsigned int **subsets_idx,
unsigned int *subsets_nb,
const Point *bs_pos,
unsigned int nb_bs,
unsigned int subset_len)
1240 unsigned int nb_avail_bs = nb_bs;
1241 unsigned int *comb_mat = NULL;
1242 unsigned int nb_comb = 0;
1246 Point bs_pos_subset[5];
1247 unsigned int *bs_subset_idx = NULL;
1249 char subset_found = 0;
1250 int valid_res = Algorithm::GEO_POS_NO;
1253 if((nb_avail_bs < subset_len) || (NULL == subsets_idx) || (NULL == subsets_nb) || (NULL == bs_pos)) {
1257 *subsets_idx = NULL;
1261 IndexSet unused_subset_idx(nb_avail_bs);
1262 for(n = 0; n < nb_avail_bs; ++n) {
1263 unused_subset_idx[n] = n;
1265 unused_subset_idx.set_size(nb_avail_bs);
1266 IndexSet used_subset_idx(nb_avail_bs);
1267 nb_comb = PosHelper::comb_nb(nb_avail_bs - 1, subset_len - 1);
1268 comb_mat = (
unsigned int*)malloc(subset_len * nb_comb *
sizeof(*comb_mat));
1269 if(NULL == comb_mat) {
1273 bs_subset_idx = (
unsigned int*)malloc(subset_len *
sizeof(*bs_subset_idx));
1274 if(NULL == bs_subset_idx) {
1282 while((0 != unused_subset_idx.get_size()) && (nb_avail_bs >= subset_len)) {
1284 if(
false == PosHelper::combination(comb_mat, &nb_comb, subset_len, unused_subset_idx.get_size())) {
1290 while(n < nb_comb) {
1291 for(i = 0; i < subset_len; ++i) {
1292 bs_subset_idx[i] = unused_subset_idx[comb_mat[i + n * subset_len]];
1293 bs_pos_subset[i] = bs_pos[bs_subset_idx[i]];
1295 algo_->get_meas(meas, bs_subset_idx, subset_len);
1296 valid_res = algo_->validate(bs_pos_subset, subset_len, meas);
1297 if((Algorithm::GEO_POS_EXACT == valid_res) || (Algorithm::GEO_POS_YES == valid_res)) {
1299 if(
false == PosHelper::store_subset(subsets_idx, bs_subset_idx, subset_len, *subsets_nb)) {
1305 if(
false == PosHelper::update_subsets(used_subset_idx, unused_subset_idx, bs_subset_idx, subset_len)) {
1306 it_warning(
"error in geo_pos_update_subsets");
1314 if(
false == PosHelper::combination(comb_mat, &nb_comb, subset_len, unused_subset_idx.get_size())) {
1323 if((0 == unused_subset_idx.get_size()) || (
false == res)) {
1329 if(
false == PosHelper::combination(comb_mat, &nb_comb, subset_len, nb_avail_bs)) {
1334 for(n = 0; n < nb_comb; ++n) {
1335 if(comb_mat[subset_len - 1 + subset_len * n] < unused_subset_idx[0]) {
1338 for(i = 0; i < subset_len; ++i) {
1339 k = comb_mat[i + n * subset_len];
1340 if(k < unused_subset_idx.get_size()) {
1341 bs_subset_idx[i] = unused_subset_idx[k];
1345 bs_subset_idx[i] = used_subset_idx[used_subset_idx.get_size() - 1 - (k - unused_subset_idx.get_size())];
1347 bs_pos_subset[i] = bs_pos[bs_subset_idx[i]];
1349 algo_->get_meas(meas, bs_subset_idx, subset_len);
1350 valid_res = algo_->validate(bs_pos_subset, subset_len, meas);
1351 if((Algorithm::GEO_POS_EXACT == valid_res) || (Algorithm::GEO_POS_YES == valid_res)) {
1353 if(
false == PosHelper::store_subset(subsets_idx, bs_subset_idx, subset_len, *subsets_nb)) {
1359 if(
false == PosHelper::update_subsets(used_subset_idx, unused_subset_idx, bs_subset_idx, subset_len)) {
1360 it_warning(
"error in geo_pos_update_subsets");
1372 if((0 == unused_subset_idx.get_size()) || (
false == res)) {
1377 if(0 == subset_found) {
1380 if(
false == unused_subset_idx.remove(unused_subset_idx[0])) {
1391 free(bs_subset_idx);
1395 bool Multilateration::get_bs_pos_subset(Point *bs_pos_subset,
const Point *bs_pos,
unsigned int nb_bs,
const unsigned int *subset_idx,
unsigned int subset_len)
1399 for(i = 0; i < subset_len; ++i) {
1405 bs_pos_subset[i] = bs_pos[k];
1410 bool Multilateration::get_ml_pos(Point *ms_pos,
const Point *bs_pos,
unsigned int nb_bs,
const unsigned int *subsets_idx,
unsigned int subsets_nb,
unsigned int subset_len)
1412 Point bs_pos_subset[5];
1414 unsigned int meas_mult[4];
1422 double *coord = NULL;
1425 if((NULL == bs_pos) || (0 == nb_bs) || (NULL == subsets_idx) || (0 == subsets_nb) || (0 == subset_len) || (NULL == ms_pos)) {
1430 if(1 != subsets_nb) {
1431 memset(nom, 0,
sizeof(nom));
1432 memset(denom, 0,
sizeof(denom));
1435 for(n = 0; n < subsets_nb; ++n) {
1437 if(
false == get_bs_pos_subset(bs_pos_subset, bs_pos, nb_bs, subsets_idx + n * subset_len, subset_len)) {
1440 if(
false == algo_->setup(bs_pos_subset, subset_len)) {
1444 algo_->get_meas(meas, subsets_idx + n * subset_len, subset_len);
1445 if(
false == algo_->get_pos(ms_pos, meas, 4)) {
1449 if(1 == subsets_nb) {
1454 if(
false == algo_->get_grad(grad, bs_pos_subset, subset_len, ms_pos)) {
1458 algo_->get_meas_mult(meas_mult, subsets_idx + n * subset_len, 4);
1459 if(
false == prod(coeff, grad, meas_mult, 3, 4)) {
1464 coord = (
double*)ms_pos;
1465 for(k = 0; k < 3; ++k) {
1466 for(i = 0; i < 3; ++i) {
1467 nom[k] += coeff[k + 3 * i] * coord[i];
1468 denom[k + 3 * i] += coeff[k + 3 * i];
1473 if(
true == PosHelper::inv_3by3(coeff, denom)) {
1474 coord = (
double*)ms_pos;
1475 for(n = 0; n < 3; ++n) {
1477 for(k = 0; k < 3; ++k) {
1478 coord[n] += coeff[n + 3 * k] * nom[k];
1488 bool Multilateration::prod(
double *out,
const double *AT,
const unsigned int *d,
unsigned int cols,
unsigned int rows)
1494 if((NULL == out) || (NULL == AT) || (NULL == d) || (0 == cols) || (0 == rows)) {
1499 for(i = 0; i < cols; ++i) {
1500 for(n = 0; n < cols; ++n) {
1501 out[i + cols * n] = 0.0;
1502 for(k = 0; k < rows; ++k) {
1507 out[i + cols * n] += (AT[i + k * cols] / (double)d[k]) * AT[n + k * cols];
1516 if((3 !=
length(ms_pos)) || (0 == nb_bs_)) {
1525 pos_ref(0) = bs_pos_[0].x;
1526 pos_ref(1) = bs_pos_[0].y;
1527 pos_ref(2) = bs_pos_[0].z;
1529 static const bin zero =
bin(0);
1530 const unsigned int method_len =
length(method_);
1531 mat dh(3, method_len);
1535 for(n = 0; n < method_len; ++n) {
1536 if(zero == method_(n)) {
1537 pos(0) = bs_pos_[n].x;
1538 pos(1) = bs_pos_[n].y;
1539 pos(2) = bs_pos_[n].z;
1540 for(i = 0; i < 3; ++i) {
1545 pos(0) = bs_pos_[n + 1].x;
1546 pos(1) = bs_pos_[n + 1].y;
1547 pos(2) = bs_pos_[n + 1].z;
1548 for(i = 0; i < 3; ++i) {
1556 for(n = 0; n < 3; ++n) {
1557 for(i = 0; i < 3; ++i) {
1558 info_mat(n, i) = dh.get_row(n) * dh.get_row(i);
1561 info_mat = info_mat / sigma2;