|
|
Jump to this file's LXR Page |
|
|
File: [CENS] / emstar / devel / loc / multilat / multilat.c
(download)
/
(as text)
Revision: 1.38, Tue Nov 28 00:57:34 2006 UTC (2 years, 11 months ago) by girod Branch: MAIN CVS Tags: pregeonet, PRE_TOSNIC_FIX, PRE_64BIT, HEAD, CYCLOPS_RELEASE_CANDIDATE_2_0, CYCLOPS_PRERELEASE_STABLE, CENTROUTE_EMSTAR_SOCKETS, AMARSS_JR_DEPLOYMENT_6_05_07 Changes since 1.37: +25 -4 lines modifications needed for rerunning data from marmots demo |
/*
*
* Copyright (c) 2005 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <math.h>
#include <emrun/emrun.h>
#include <libmisc/misc.h>
#include "multilat_i.h"
#include <gsl/gsl_multifit_nlin.h>
#include <gsl/gsl_blas.h>
QUEUE_FUNCTION_INSTANTIATIONS(range_list,_,ranges,multilat_range_t,struct _multilat_stages);
float killpairs_prob = 0;
#define PHI_DIST_VARIATION 6.0
#define PSIG d2r(3.5/2.0)
#define TSIG d2r(0.96/2.0)
#define MAX_BIDIR_DIFF 300
#define MIN_BIDIR_DIFF 5
#undef AVERAGE_SMALL
#undef EMBEDDED_USECONF
int isnormal(double d)
{
if (isnan(d)) return 0;
if (isinf(d)) return 0;
return 1;
}
double misc_normalize_angle_rad_d(double rad_angle)
{
double result = fmod(rad_angle, 2.0 * M_PI);
if (result > M_PI) result -= (2.0 * M_PI);
else if (result < - M_PI) result += (2.0 * M_PI);
return result;
}
inline float m_pow_2(float x) { return x*x; }
void multilatbuf_to_file(ml_state_t *mls, char *filename, buf_t *buf) {
if (!mls->logs_off) {
// int thetime = time(NULL);
char f[4096];
// sprintf(f, "/tmp/%s-%d", filename, thetime);
sprintf(f, "%s/%04i-%s", mls->outputprefix, mls->global_run, filename);
elog(LOG_WARNING, "outputing to %s", f);
buf_to_file(f, buf);
}
else
elog(LOG_WARNING, "suppressing log file output..");
}
void print_matrix(buf_t *buf, gsl_matrix *m) {
int i = 0;
int j = 0;
for (i = 0; i < m->size1; ++i) {
for (j = 0; j < m->size2; ++j) {
bufprintf(buf, "%f ", gsl_matrix_get(m, i, j));
}
bufprintf(buf, "\n");
}
}
void print_vector(buf_t *buf, gsl_vector *v) {
int i = 0;
for (i = 0; i < v->size; ++i) {
bufprintf(buf, "%f ", gsl_vector_get(v, i));
}
bufprintf(buf, "\n");
}
void print_multitlat_state(ml_state_t *mls,
gsl_matrix *A,
gsl_matrix *new_A,
gsl_matrix *V,
gsl_vector *s,
gsl_vector *b,
gsl_vector *x,
int state)
{
buf_t *buf = buf_new();
char file[4096];
bufprintf(buf, "Current State:\n");
bufprintf(buf, "A was:\n");
print_matrix(buf, A);
bufprintf(buf, "\n\n");
bufprintf(buf, "A is:\n");
print_matrix(buf, new_A);
bufprintf(buf, "\nV is:\n");
print_matrix(buf, V);
bufprintf(buf,"\n\n s is:\n");
print_vector(buf, s);
bufprintf(buf,"\n\n b is:\n");
print_vector(buf, b);
bufprintf(buf,"\n\n x is:\n");
print_vector(buf, x);
bufprintf(buf, "\n\n\n");
sprintf(file, "state%i", state);
multilatbuf_to_file(mls, file, buf);
buf_free(buf);
}
struct aw {
mreal angle;
mreal weight;
mreal total;
};
struct aw angles[100];
int angle_count;
void init_cm()
{
angle_count = 0;
}
void add_cm(mreal theta, mreal weight)
{
angles[angle_count].angle = misc_normalize_angle_rad_d(theta);
angles[angle_count].weight = weight;
angles[angle_count].total = 0;
angle_count++;
}
int aw_cmp(const void *a,const void *b)
{
return ((struct aw *)a)->angle - ((struct aw *)b)->angle;
}
int realcmp(const void *a,const void *b)
{
mreal cmp = *((mreal *)a) - *((mreal *)b);
if (cmp < 0) return -1;
if (cmp > 0) return 1;
return 0;
}
mreal finish_cm()
{
qsort(angles, angle_count, sizeof(struct aw), aw_cmp);
int i;
float max_weight = 0;
int max_w_index = -1;
for (i=0; i<angle_count; i++) {
int j;
for (j=0; j<angle_count; j++)
if (fabs(misc_normalize_angle_rad_d(angles[j].angle - angles[i].angle)) < d2r(10))
angles[i].total += angles[j].weight;
if (angles[i].total > max_weight || max_w_index < 0) {
max_weight = angles[i].total;
max_w_index = i;
}
}
if (max_w_index >= 0) {
mreal t[2] = {0,0};
int j;
for (j=0; j<angle_count; j++) {
if (fabs(misc_normalize_angle_rad_d(angles[j].angle - angles[max_w_index].angle)) < d2r(10)) {
t[0] += angles[j].weight*cos(angles[j].angle);
t[1] += angles[j].weight*sin(angles[j].angle);
}
}
return atan2(t[1], t[0]);
}
elog(LOG_WARNING, "couldnt compute sloppy mode");
return 0;
}
struct error_stats {
mreal avg_range_diff;
mreal rms_range_diff;
mreal avg_theta_diff;
mreal rms_theta_diff;
mreal avg_phi_diff;
mreal rms_phi_diff;
int range_count;
int theta_count;
int phi_count;
};
buf_t *mlat_errors_to_buf(ml_state_t *mls, struct error_stats *stats)
{
mreal avg_range_diff = 0;
mreal rms_range_diff = 0;
mreal avg_theta_diff = 0;
mreal rms_theta_diff = 0;
mreal avg_phi_diff = 0;
mreal rms_phi_diff = 0;
int range_count = 0;
int theta_count = 0;
int phi_count = 0;
multilat_range_t *mtr;
buf_t *err_summ = buf_new();
bufprintf(err_summ, "#h chirper receiver r r_diff user t terr uset p perr usep yaw pitch roll\n");
for (mtr = range_list_top(mls->multilat_lists) ;
mtr != NULL; mtr = range_list_next(mtr))
if (mtr->distance > 0) {
multilat_result_t * mrr1 = result_list_get(mls, mtr->chirp_from);
multilat_result_t * mrr2 = result_list_get(mls, mtr->data_from);
mreal dist = sqrt(sqrf(mrr1->x - mrr2->x) +
sqrf(mrr1->y - mrr2->y) +
sqrf(mrr1->z - mrr2->z));
mreal phi = atan2(mrr1->z - mrr2->z,
sqrt(sqrf(mrr1->x - mrr2->x) +
sqrf(mrr1->y - mrr2->y)));
mreal theta = atan2(mrr1->y - mrr2->y, mrr1->x - mrr2->x);
mreal rerr = (mtr->userange != 0) ? mtr->userange - dist :
mtr->distance - dist;
mreal perr = misc_normalize_angle_rad_d(mtr->phi) -
misc_normalize_angle_rad_d(phi);
mreal terr =
misc_normalize_angle_rad_d
(misc_normalize_angle_rad_d(mtr->theta) -
misc_normalize_angle_rad_d(mrr2->yaw) -
misc_normalize_angle_rad_d(theta));
bufprintf(err_summ, "%d\t%d\t%f\t%f\t%c\t",
mtr->chirp_from, mtr->data_from, mtr->distance, rerr,
(mtr->state == RANGE_DROPPED || mtr->drop_r) ? 'N' :
#ifdef RTHETA
'Y'
#else
((mtr->use_r) ? 'Y' : 'M')
#endif
);
#ifdef RTHETA
if (!(mtr->state == RANGE_DROPPED || mtr->drop_r))
#else
if (mtr->use_r)
#endif
{
range_count++;
avg_range_diff += fabs(rerr);
rms_range_diff += sqrf(rerr);
}
#ifdef RTHETA
if (mtr->state != RANGE_DROPPED)
#else
if (mtr->use_t)
#endif
{
avg_theta_diff += fabs(terr);
rms_theta_diff += sqrf(terr);
theta_count++;
bufprintf(err_summ, "%f\t%f\tY\t", r2d(mtr->theta), r2d(terr));
}
else bufprintf(err_summ, "%f\t%f\t%c\t", r2d(mtr->theta), r2d(terr),
(mtr->state == RANGE_DROPPED || mtr->drop_t) ? 'N' : 'M');
#ifdef RTHETA
if (mtr->state != RANGE_DROPPED)
#else
if (mtr->use_p)
#endif
{
phi_count++;
avg_phi_diff += fabs(perr);
rms_phi_diff += sqrf(perr);
bufprintf(err_summ, "%f\t%f\tY\t", r2d(mtr->phi), r2d(perr));
}
else bufprintf(err_summ, "%f\t%f\t%c\t", r2d(mtr->phi), r2d(perr),
(mtr->state == RANGE_DROPPED || mtr->drop_p) ? 'N' : 'M');
bufprintf(err_summ, "%f\t%f\t%f\n", r2d(-mrr2->yaw), r2d(-mrr2->pitch), r2d(-mrr2->roll));
}
if (stats) {
stats->avg_range_diff = avg_range_diff;
stats->rms_range_diff = rms_range_diff;
stats->avg_theta_diff = avg_theta_diff;
stats->rms_theta_diff = rms_theta_diff;
stats->avg_phi_diff = avg_phi_diff;
stats->rms_phi_diff = rms_phi_diff;
stats->range_count = range_count;
stats->theta_count = theta_count;
stats->phi_count = phi_count;
}
return err_summ;
}
float last_drop_value = 0;
float min_drop_value = -1;
float min_xyz = -1;
float min_xyz_resid = 0;
int min_xyz_passes = 0;
int iterations = 0;
void dump_errors(ml_state_t *mls, int k)
{
buf_t *err_summ = mlat_errors_to_buf(mls, NULL);
char thefile[4096];
sprintf(thefile, "err-%d", k);
multilatbuf_to_file(mls, thefile, err_summ);
buf_free(err_summ);
}
/* compare the results to the ground truth.. */
void analyse_result(ml_state_t *mls)
{
/* compute raw average differences */
mreal avg_range_diff = 0;
mreal rms_range_diff = 0;
mreal avg_theta_diff = 0;
mreal rms_theta_diff = 0;
mreal avg_phi_diff = 0;
mreal rms_phi_diff = 0;
int range_count = 0;
int theta_count = 0;
int phi_count = 0;
struct error_stats stats = {};
buf_t *err_summ = mlat_errors_to_buf(mls, &stats);
avg_range_diff = stats.avg_range_diff;
rms_range_diff = stats.rms_range_diff;
avg_theta_diff = stats.avg_theta_diff;
rms_theta_diff = stats.rms_theta_diff;
avg_phi_diff = stats.avg_phi_diff;
rms_phi_diff = stats.rms_phi_diff;
range_count = stats.range_count;
theta_count = stats.theta_count;
phi_count = stats.phi_count;
if (range_count > 0) {
avg_range_diff /= (mreal)range_count;
avg_theta_diff /= (mreal)theta_count;
avg_phi_diff /= (mreal)phi_count;
rms_range_diff = sqrt(rms_range_diff / (mreal)range_count);
rms_theta_diff = sqrt(rms_theta_diff / (mreal)theta_count);
rms_phi_diff = sqrt(rms_phi_diff / (mreal)phi_count);
elog(LOG_WARNING, "AVG: r=%f t=%f p=%f",
avg_range_diff, r2d(avg_theta_diff), r2d(avg_phi_diff));
elog(LOG_WARNING, "RMS: r=%f t=%f p=%f",
rms_range_diff, r2d(rms_theta_diff), r2d(rms_phi_diff));
}
char thefile[4096];
sprintf(thefile, "final-err");
multilatbuf_to_file(mls, thefile, err_summ);
buf_free(err_summ);
#ifdef PROCRUSTES
/* compute centroid */
mreal cG[3] = {0,0,0};
mreal c[3] = {0,0,0};
multilat_result_t *node1, *node2;
int count = 0;
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) {
elog(LOG_WARNING, "skipping node %d that isn't in the matrix..", node1->node);
continue;
}
node1->X[0] = node1->x;
node1->X[1] = node1->y;
node1->X[2] = node1->z;
node1->XG[0] = node1->real_x;
node1->XG[1] = node1->real_y;
node1->XG[2] = node1->real_z;
count++;
for (i=0; i<3; i++) {
c[i] += X[i];
cG[i] += XG[i];
}
}
for (i=0; i<3; i++) {
c[i] /= (mreal)count;
cG[i] /= (mreal)count;
}
/* compute centroid sizes */
mreal S = 0;
mreal SG = 0;
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) {
elog(LOG_WARNING, "skipping node %d that isn't in the matrix..", node1->node);
continue;
}
for (i=0; i<3; i++) {
S += sqrf(node1->X[i] - c[i]);
SG += sqrf(node1->XG[i] - cG[i]);
}
}
S = sqrt(S);
SG = sqrt(SG);
/* pre-shape */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) {
elog(LOG_WARNING, "skipping node %d that isn't in the matrix..", node1->node);
continue;
}
for (i=0; i<3; i++) {
node1->X[i] = (node1->X[i] - c[i]) / S;
node1->XG[i] = (node1->XG[i] - cG[i]) / SG;
}
}
/* rotations.. */
/* $$$ */
#else
/* compute scaling factor */
mreal tot_comp = 1.0;
mreal tot_gt = 1.0;
mreal V;
multilat_result_t *node1, *node2;
mreal c[3] = {0,0,0};
mreal cG[3] = {0,0,0};
int count = 0;
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) {
elog(LOG_WARNING, "skipping node %d that isn't in the matrix..", node1->node);
continue;
}
if (node1->nogt) {
elog(LOG_WARNING, "skipping node %d, no gt..", node1->node);
continue;
}
count++;
c[0] += node1->x;
c[1] += node1->y;
c[2] += node1->z;
cG[0] += node1->real_x;
cG[1] += node1->real_y;
cG[2] += node1->real_z;
mreal nD1=-1.0, nD2=-1.0;
for (node2 = result_list_top(mls->multilat_lists);
node2; node2 = result_list_next(node2)) {
if (node2->col < 0 && node2->state != RESULT_COORD_ROOT) continue;
if (node2->nogt) continue;
if (node1 != node2) {
mreal D1 = sqrt
(sqrf(node1->x - node2->x) +
sqrf(node1->y - node2->y) +
sqrf(node1->z - node2->z));
mreal D2 = sqrt
(sqrf(node1->real_x - node2->real_x) +
sqrf(node1->real_y - node2->real_y) +
sqrf(node1->real_z - node2->real_z));
if (nD1 < 0 || D1 < nD1) {
nD1 = D1;
nD2 = D2;
}
}
}
if (nD1 > 0) {
tot_comp += nD1;
tot_gt += nD2;
}
}
V = tot_comp / tot_gt;
/* centroid */
c[0] /= (mreal)count;
c[1] /= (mreal)count;
c[2] /= (mreal)count;
cG[0] /= (mreal)count;
cG[1] /= (mreal)count;
cG[2] /= (mreal)count;
#ifndef ROTATE_ABOUT_CENTROID
mreal min_dist = -1;
/* find center point */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1->nogt) continue;
mreal D1 = sqrt
(sqrf(node1->x - c[0]) +
sqrf(node1->y - c[1]) +
sqrf(node1->z - c[2]));
if (min_dist < 0 || min_dist > D1) {
min_dist = D1;
node2 = node1;
}
}
/* node2 is closest to centroid */
elog(LOG_WARNING, "centroid is node %d", node2->node);
/* translate to center */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1 != node2) {
node1->tx = node1->x - node2->x;
node1->ty = node1->y - node2->y;
node1->tz = node1->z - node2->z;
node1->trx = node1->real_x - node2->real_x;
node1->try = node1->real_y - node2->real_y;
node1->trz = node1->real_z - node2->real_z;
}
}
node2->tx = 0;
node2->ty = 0;
node2->tz = 0;
node2->trx = 0;
node2->try = 0;
node2->trz = 0;
#else
/* translate to centroid */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
node1->tx = node1->x - c[0];
node1->ty = node1->y - c[1];
node1->tz = node1->z - c[2];
node1->trx = node1->real_x - cG[0];
node1->try = node1->real_y - cG[1];
node1->trz = node1->real_z - cG[2];
}
node2=NULL;
#endif
/* scale and init tyaw */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
node1->tx /= V;
node1->ty /= V;
node1->tz /= V;
}
mreal rot;
mreal cumrot = 0;
goto retry_z;
flip:
/* FLIP */
elog(LOG_WARNING, "Flipped!");
cumrot = M_PI-cumrot;
retry_z:
#ifdef USEZ
init_cm();
/* determine Z axis rotation */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1->nogt) continue;
if (node1 != node2) {
mreal D1 = sqrt(sqrf(node1->tx) + sqrf(node1->ty));
mreal dt =
atan2(node1->ty, node1->tx) -
atan2(node1->try, node1->trx);
add_cm(dt, D1);
}
}
rot = -finish_cm();
elog(LOG_WARNING, "Z axis rotation = %f", r2d(rot));
#endif
/* rotate */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) {
elog(LOG_WARNING, "node %d is a root?", node1->node);
continue;
}
if (node1 != node2) {
mreal tmpx = node1->tx;
mreal tmpy = node1->ty;
node1->tx = (cos(rot)*tmpx - sin(rot)*tmpy);
node1->ty = (sin(rot)*tmpx + cos(rot)*tmpy);
}
}
cumrot += rot;
/* does our ground truth have a z axis? */
int have_gtz = 0;
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1->nogt) continue;
if (node1->real_z != 0) {
have_gtz = 1;
break;
}
}
if (have_gtz) {
/* determine Y axis rotation */
init_cm();
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1->nogt) continue;
if (node1 != node2) {
mreal D1 = sqrt(sqrf(node1->tx) + sqrf(node1->tz));
mreal dt =
atan2(node1->tz, node1->tx) -
atan2(node1->trz, node1->trx);
add_cm(dt, D1);
}
}
rot = -finish_cm();
elog(LOG_WARNING, "Y axis rotation = %f", r2d(rot));
/* rotate */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1 != node2) {
mreal tmpx = node1->tx;
mreal tmpz = node1->tz;
node1->tx = (cos(rot)*tmpx - sin(rot)*tmpz);
node1->tz = (sin(rot)*tmpx + cos(rot)*tmpz);
}
}
if (r2d(rot) < -160 || r2d(rot) > 160) {
goto flip;
}
/* determine X axis rotation */
init_cm();
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1->nogt) continue;
if (node1 != node2) {
mreal D1 = sqrt(sqrf(node1->tz) + sqrf(node1->ty));
mreal dt =
atan2(node1->ty, node1->tz) -
atan2(node1->try, node1->trz);
add_cm(dt, D1);
}
}
rot = -finish_cm();
elog(LOG_WARNING, "X axis rotation = %f", r2d(rot));
/* rotate */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1 != node2) {
mreal tmpz = node1->tz;
mreal tmpy = node1->ty;
node1->tz = (cos(rot)*tmpz - sin(rot)*tmpy);
node1->ty = (sin(rot)*tmpz + cos(rot)*tmpy);
}
}
if (r2d(rot) < -160 || r2d(rot) > 160) {
goto flip;
}
}
/* add in original yaw */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
node1->tyaw = -node1->yaw + cumrot;
}
/* average translation */
mreal tr[3] = {0,0,0};
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1->nogt) continue;
mreal D = sqrt(sqrf(node1->trx-node1->tx) +
sqrf(node1->try-node1->ty) +
sqrf(node1->trz-node1->tz));
/* only add into average if < 1 meter away */
if (D < 100) {
tr[0] += node1->trx-node1->tx;
tr[1] += node1->try-node1->ty;
tr[2] += node1->trz-node1->tz;
}
}
tr[0] /= (mreal)count;
tr[1] /= (mreal)count;
tr[2] /= (mreal)count;
/* adjust nodes for translation */
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
node1->tx += tr[0];
node1->ty += tr[1];
node1->tz += tr[2];
}
#endif
/* compute the avg dist */
mreal avg_dist = 0;
mreal rms_dist = 0;
mreal avg_zdist = 0;
mreal rms_zdist = 0;
mreal worst_dist = 0;
mreal avg_zdist_d1 = 0;
mreal avg_yaw_err = 0;
mreal distarr[100];
mreal zdistarr[100];
mreal yawarr[100];
int distcount = 0;
buf_t *xybuf = buf_new();
buf_t *xyzbuf = buf_new();
buf_t *obuf = buf_new();
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) continue;
if (node1->nogt) continue;
mreal DZ = sqrt
(sqrf(node1->tx - node1->trx) +
sqrf(node1->ty - node1->try) +
sqrf(node1->tz - node1->trz));
mreal DXY = sqrt
(sqrf(node1->tx - node1->trx) +
sqrf(node1->ty - node1->try));
avg_dist += DXY;
rms_dist += sqrf(DXY);
avg_zdist += DZ;
rms_zdist += sqrf(DZ);
distarr[distcount] = DXY;
zdistarr[distcount] = DZ;
if (DZ > worst_dist) worst_dist = DZ;
mreal yaw_err = fmod(node1->real_yaw - r2d(node1->tyaw), 360.0);
if (yaw_err > 180) yaw_err -= 360.0;
if (yaw_err < -180) yaw_err += 360.0;
avg_yaw_err += fabs(yaw_err);
yawarr[distcount] = fabs(yaw_err);
distcount++;
elog(LOG_WARNING, "dist %d %f, yawerr=%f", node1->node, DXY, yaw_err);
bufprintf(xybuf, "%f %d\n", DXY, node1->node);
bufprintf(xyzbuf, "%f %d\n", DZ, node1->node);
bufprintf(obuf, "%f %d\n", yaw_err, node1->node);
}
qsort(distarr, distcount, sizeof(mreal), realcmp);
qsort(zdistarr, distcount, sizeof(mreal), realcmp);
qsort(yawarr, distcount, sizeof(mreal), realcmp);
mreal median_dist = distarr[distcount/2];
mreal median_zdist = zdistarr[distcount/2];
mreal median_yaw = yawarr[distcount/2];
#if 0
elog(LOG_WARNING, "distcount=%d, medianyaw=%f", distcount, median_yaw);
int klkl;
for (klkl=0;klkl<distcount;klkl++)
elog(LOG_WARNING, " yaw %d %f", klkl, yawarr[klkl]);
#endif
avg_dist /= (mreal)count;
rms_dist = sqrt(rms_dist / (mreal)count);
avg_yaw_err/= (mreal)count;
avg_zdist_d1 = (avg_zdist - worst_dist) / (mreal)(count-1);
avg_zdist /= (mreal)count;
rms_zdist = sqrt(rms_zdist / (mreal)count);
elog(LOG_WARNING, " V = %f", V);
elog(LOG_WARNING, " DIST = %f, RMS = %f, median = %f", avg_dist, rms_dist, median_dist);
elog(LOG_WARNING, " ZDIST = %f, RMS = %f, median = %f", avg_zdist, rms_zdist, median_zdist);
elog(LOG_WARNING, " YAWERR = %f", avg_yaw_err);
/* print out */
buf_t *firstpass = buf_new();
sprintf(thefile, "final");
bufprintf(firstpass, "#h node x y z yaw roll pitch gt_x gt_y gt_z\n");
multilat_result_t *rlt = result_list_top(mls->multilat_lists);
for ( ; rlt != NULL; rlt = result_list_next(rlt) ) {
if (rlt->col < 0 && rlt->state != RESULT_COORD_ROOT) continue;
bufprintf(firstpass, "%d\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n", rlt->node, rlt->tx, rlt->ty, rlt->tz,
r2d(rlt->tyaw), r2d(-rlt->roll), r2d(-rlt->pitch),
rlt->trx, rlt->try, rlt->trz);
}
if (min_drop_value < 0 || last_drop_value < min_drop_value) min_drop_value = last_drop_value;
if (min_xyz < 0 || avg_zdist < min_xyz) {
min_xyz = avg_zdist;
min_xyz_resid = min_drop_value;
min_xyz_passes = mls->global_run;
}
bufprintf(firstpass, "# V = %f\n", V);
bufprintf(firstpass, "# avg_pos_err(xy) = %f, RMS = %f, med %f\n", avg_dist, rms_dist, median_dist);
bufprintf(firstpass, "# avg_pos_err(xyz) = %f, RMS = %f, med %f\n", avg_zdist, rms_zdist, median_zdist);
bufprintf(firstpass, "# avg_constraint_err: r=%f t=%f p=%f\n",
avg_range_diff, r2d(avg_theta_diff), r2d(avg_phi_diff));
bufprintf(firstpass, "# rms_constraint_err: r=%f t=%f p=%f\n",
rms_range_diff, r2d(rms_theta_diff), r2d(rms_phi_diff));
bufprintf(firstpass, "# yaw_avg %f median %f \n",
avg_yaw_err, median_yaw);
bufprintf(firstpass, "##%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%d\t%f\t%f\t%d\t%d\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n\n",
V, avg_dist, avg_zdist, avg_range_diff, r2d(avg_theta_diff), r2d(avg_phi_diff),
last_drop_value, min_drop_value, count,
min_xyz, min_xyz_resid, min_xyz_passes, iterations, avg_zdist_d1,
median_dist, median_zdist, avg_yaw_err, median_yaw,
killpairs_prob, distarr[distcount-1]
);
multilatbuf_to_file(mls, thefile, firstpass);
buf_free(firstpass);
multilatbuf_to_file(mls, "3d-dist", xyzbuf);
multilatbuf_to_file(mls, "2d-dist", xybuf);
multilatbuf_to_file(mls, "yaw-dist", obuf);
buf_free(xyzbuf);
buf_free(xybuf);
buf_free(obuf);
}
#ifdef RTHETA
void update_minmax(mreal *min, mreal *max, mreal value)
{
if (value < *min) *min = value;
else if (value > *max) *max = value;
}
mreal do_xweight(multilat_range_t *mtr)
{
mreal min=0;
mreal max=0;
min = max = cos(mtr->theta + TSIG)*cos(mtr->phi + PSIG);
update_minmax(&min,&max,cos(mtr->theta - TSIG)*cos(mtr->phi + PSIG));
update_minmax(&min,&max,cos(mtr->theta + TSIG)*cos(mtr->phi - PSIG));
update_minmax(&min,&max,cos(mtr->theta - TSIG)*cos(mtr->phi - PSIG));
mreal w = sqrt(mtr->distance * (max-min));
if (w == 0) return 0;
return 1.0/w;
}
mreal do_yweight(multilat_range_t *mtr)
{
mreal min=0;
mreal max=0;
min = max = sin(mtr->theta + TSIG)*cos(mtr->phi + PSIG);
update_minmax(&min,&max,sin(mtr->theta - TSIG)*cos(mtr->phi + PSIG));
update_minmax(&min,&max,sin(mtr->theta + TSIG)*cos(mtr->phi - PSIG));
update_minmax(&min,&max,sin(mtr->theta - TSIG)*cos(mtr->phi - PSIG));
mreal w = sqrt(mtr->distance * (max-min));
if (w == 0) return 0;
return 1.0/w;
}
mreal do_zweight(multilat_range_t *mtr)
{
mreal min=0;
mreal max=0;
min = max = sin(mtr->phi + PSIG);
update_minmax(&min,&max,sin(mtr->phi + PSIG));
update_minmax(&min,&max,sin(mtr->phi - PSIG));
update_minmax(&min,&max,sin(mtr->phi - PSIG));
mreal w = sqrt(mtr->distance * (max-min));
if (w == 0) return 0;
return 1.0/w;
}
void multilat_solver(ml_state_t *mls) {
int i = 0;
/* the result_view array is the mapping of a 0 to num_nodes index of
all the results... it gives us a convienient way to address the
nodes without having to deal with incosistent node id's */
int num_nodes = result_list_qlen(mls->multilat_lists);
multilat_result_t *(result_view[num_nodes]);
result_list_make_array(mls, result_view, num_nodes);
#ifdef USEZ
int axes = 3;
#else
int axes = 2;
#endif
/* row is chirp_from, column is data_from */
int num_ranges = range_list_qlen(mls->multilat_lists);
multilat_range_t *mtr;
int total_dups = 0;
int runagain = 0;
int dropped_rows = 0;
int num_roots = 0;
buf_t *droppedbuf = buf_new();
/******************/
/* get dimensions */
/******************/
repeate:
if (mls->global_run != 0) {
result_load(mls);
}
num_roots = 0;
for (i = 0; i < num_nodes; ++i) {
if (result_view[i]->state == RESULT_COORD_ROOT)
num_roots++;
}
/* $$$ this would change with tiedowns.. not really right anyway */
int num_rows = (num_ranges - total_dups - (num_roots*(num_roots-1)))*axes - dropped_rows;
int num_cols = (num_nodes - num_roots)*axes;
elog(LOG_CRIT, "total ranges %i, dropped %i, rows,cols= %i,%i", num_ranges, dropped_rows,
num_rows, num_cols);
if (num_cols > num_rows) {
elog(LOG_CRIT, "Can not continue with SVD only have %i by %i matrix", num_rows, num_cols);
exit(1);
}
//mreal VV = 1;
/***********/
/* iterate */
/***********/
int k = 0;
int dobreak=0;
for (k = 0; k < 100; ++k) {
/* setup the matrix */
gsl_matrix *A;
gsl_vector *b;
elog(LOG_DEBUG(0), "allocing %d,%d matrix", num_rows, num_cols);
A = gsl_matrix_calloc(num_rows, num_cols);
b = gsl_vector_calloc(num_rows);
int node1_loc = 0, node2_loc = 0, curr_row = 0, curr_col = 0;
for (mtr = range_list_top(mls->multilat_lists), i = 0;
i < num_ranges; ++i, mtr = range_list_next(mtr) ) {
//elog(LOG_CRIT, "currrow: %i, i is %i", curr_row, i);
//elog(LOG_CRIT, "looking for df: %i cf: %i", mtr->data_from, mtr->chirp_from);
node1_loc = result_list_array_lookup(mls, result_view, mtr->data_from);
node2_loc = result_list_array_lookup(mls, result_view, mtr->chirp_from);
mtr->last_row = -1;
/* skip ranges between anchors */
if ( (mtr->data_from == mls->anode1 && mtr->chirp_from == mls->anode2) ||
(mtr->data_from == mls->anode2 && mtr->chirp_from == mls->anode1)
) {
// elog(LOG_WARNING, "!!!! found the anchors");
continue;
}
/* skip if dropped */
if ( mtr->state == RANGE_DROPPED ) {
continue;
}
mtr->last_row = curr_row;
/* find the columns if they exist... if not, set them */
if (result_view[node1_loc]->col == -1 && result_view[node1_loc]->state != RESULT_COORD_ROOT) {
result_view[node1_loc]->col = curr_col;
curr_col += axes;
}
if (result_view[node2_loc]->col == -1 && result_view[node2_loc]->state != RESULT_COORD_ROOT) {
result_view[node2_loc]->col = curr_col;
curr_col += axes;
}
/* node1_loc represents x1, y1, z1 ...
node2_loc represents x2, y2, z2 */
// node 2 chirps
// node 1 receives
/* $$$ missing VV and tiedowns */
mtr->userange = mtr->distance + PHI_DIST_VARIATION*sin(mtr->phi);
if (result_view[node1_loc]->state == RESULT_COORD_ROOT) {
/* add constraints */
mreal w = do_xweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node2_loc]->col + 0, +1.0*w);
gsl_vector_set(b, curr_row,
(mtr->userange*cos(mtr->phi)*
cos(mtr->theta-result_view[node1_loc]->yaw) +
result_view[node1_loc]->x)*w);
curr_row++;
w = do_yweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node2_loc]->col + 1, +1.0*w);
gsl_vector_set(b, curr_row,
(mtr->userange*cos(mtr->phi)*
sin(mtr->theta-result_view[node1_loc]->yaw) +
result_view[node1_loc]->y)*w);
curr_row++;
if (axes>2) {
w = do_zweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node2_loc]->col + 2, +1.0*w);
gsl_vector_set(b, curr_row, (mtr->userange*sin(mtr->phi) +
result_view[node1_loc]->z)*w);
curr_row++;
}
}
else if (result_view[node2_loc]->state == RESULT_COORD_ROOT) {
/* add constraints */
mreal w = do_xweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node1_loc]->col + 0, -1.0*w);
gsl_vector_set(b, curr_row,
(mtr->userange*cos(mtr->phi)*
cos(mtr->theta-result_view[node1_loc]->yaw) -
result_view[node2_loc]->x)*w);
curr_row++;
w = do_yweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node1_loc]->col + 1, -1.0*w);
gsl_vector_set(b, curr_row,
(mtr->userange*cos(mtr->phi)*
sin(mtr->theta-result_view[node1_loc]->yaw) -
result_view[node2_loc]->y)*w);
curr_row++;
if (axes>2) {
w = do_zweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node1_loc]->col + 2, -1.0*w);
gsl_vector_set(b, curr_row, (mtr->userange*sin(mtr->phi) -
result_view[node2_loc]->z)*w);
curr_row++;
}
}
else {
/* add constraints */
mreal w = do_xweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node1_loc]->col + 0, -1.0*w);
gsl_matrix_set(A, curr_row, result_view[node2_loc]->col + 0, +1.0*w);
gsl_vector_set(b, curr_row,
(mtr->userange*cos(mtr->phi)*
cos(mtr->theta-result_view[node1_loc]->yaw))*w);
curr_row++;
w = do_yweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node1_loc]->col + 1, -1*w);
gsl_matrix_set(A, curr_row, result_view[node2_loc]->col + 1, +1*w);
gsl_vector_set(b, curr_row,
(mtr->userange*cos(mtr->phi)*
sin(mtr->theta-result_view[node1_loc]->yaw))*w);
curr_row++;
if (axes>2) {
w = do_zweight(mtr);
gsl_matrix_set(A, curr_row, result_view[node1_loc]->col + 2, -1*w);
gsl_matrix_set(A, curr_row, result_view[node2_loc]->col + 2, +1*w);
gsl_vector_set(b, curr_row, mtr->userange*sin(mtr->phi)*w);
curr_row++;
}
}
}
elog(LOG_CRIT, "Just added %i rows", curr_row);
/************/
/* SVDecomp */
/************/
gsl_matrix *new_A;
gsl_matrix *V;
gsl_vector *s;
gsl_vector *x_res;
new_A = gsl_matrix_calloc(num_rows, num_cols);
V = gsl_matrix_calloc(num_cols, num_cols);
s = gsl_vector_calloc(num_cols);
x_res = gsl_vector_calloc(num_cols);
int res = gsl_matrix_memcpy(new_A, A);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error copying new matrix: %s\n", gsl_strerror(res));
exit(1);
}
elog(LOG_WARNING, "Starting svdecomp");
res = gsl_linalg_SV_decomp_jacobi(new_A, V, s);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error doing svdecomp: %s\n", gsl_strerror(res));
exit(1);
}
elog(LOG_WARNING, "Starting SV solve");
res = gsl_linalg_SV_solve(new_A, V, s, b, x_res);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error doing svdecomp Solve: %s\n", gsl_strerror(res));
exit(1);
}
elog(LOG_WARNING, "Printing state");
print_multitlat_state(mls, A, new_A, V, s, b, x_res, k);
elog(LOG_WARNING, "Done");
/*********************************/
/* update the results with x_res */
/*********************************/
for (i = 0; i < num_nodes; ++i) {
if (result_view[i]->state != RESULT_COORD_ROOT && result_view[i]->col >= 0) {
result_view[i]->x = gsl_vector_get(x_res, result_view[i]->col + 0);
result_view[i]->y = gsl_vector_get(x_res, result_view[i]->col + 1);
if (axes>2)
result_view[i]->z = gsl_vector_get(x_res, result_view[i]->col + 2);
}
}
/*************************/
/* update yaw/pitch/roll */
/*************************/
mreal totx=0;
mreal toty=0;
int totsum=0;
//mreal max_err=0;
int converged = 1;
multilat_result_t *node;
for (i = 0; i < num_nodes; ++i) {
multilat_result_t *node = result_view[i];
/* compute orientation for roots if there is more than one of them.
* otherwise, lock in specified orientation */
if (num_roots > 1 || (result_view[i]->state != RESULT_COORD_ROOT)) {
mreal yaw[2] = {0,0};
mreal pitch[2] = {0,0};
mreal roll[2] = {0,0};
for (mtr = range_list_top(mls->multilat_lists);
mtr != NULL; mtr = range_list_next(mtr)) {
if (mtr->data_from == result_view[i]->node) {
int chirp_index = result_list_array_lookup(mls, result_view, mtr->chirp_from);
multilat_result_t *chirp_node = result_view[chirp_index];
mreal c[3];
mreal ctheta,cphi;
mreal dtheta,dphi;
/* unit vector of computed angle */
c[0] = chirp_node->x - node->x;
c[1] = chirp_node->y - node->y;
c[2] = chirp_node->z - node->z;
mreal D = sqrt(sqrf(c[0]) + sqrf(c[1]) + sqrf(c[2]));
c[0] /= D;
c[1] /= D;
c[2] /= D;
/* zenith and azimuth angles */
ctheta = atan2(c[1], c[0]);
cphi = misc_normalize_angle_rad_d(atan2(c[2], sqrt(sqrf(c[0])+sqrf(c[1]))));
/* diffs */
dtheta = ctheta - mtr->theta;
dphi = cphi - misc_normalize_angle_rad_d(mtr->phi);
if (!mtr->drop_t) {
/* sum (could weight by confidence..) */
yaw[0] += cos(dtheta)*cos(cphi);
yaw[1] += sin(dtheta)*cos(cphi);
}
if (!mtr->drop_p) {// && fabs(dphi) < (6/180.0*M_PI)) {
elog(LOG_DEBUG(20),
"dphi %f ctheta %f p += %f %f ",
r2d(dphi), r2d(ctheta),
fabs(cos(ctheta))*cos(dphi),
cos(ctheta)*sin(dphi));
elog(LOG_DEBUG(20),
"dphi %f ctheta %f r += %f %f ",
r2d(dphi), r2d(ctheta),
fabs(sin(ctheta))*cos(dphi),
sin(ctheta)*sin(dphi));
pitch[0] += fabs(cos(ctheta))*cos(dphi);
pitch[1] += cos(ctheta)*sin(dphi);
roll[0] += fabs(sin(ctheta))*cos(dphi);
roll[1] += sin(ctheta)*sin(dphi);
elog(LOG_DEBUG(20),
" == %f,%f (%f)",
pitch[0],pitch[1],
r2d(atan2(pitch[1],pitch[0])));
elog(LOG_DEBUG(20),
" == %f,%f (%f)",
roll[0],roll[1],
r2d(atan2(roll[1],roll[0])));
}
else {
elog(LOG_DEBUG(11), "skipping dphi=%f", dphi*180.0/M_PI);
}
}
}
mreal new_yaw = -atan2(yaw[1],yaw[0]);
if (fabs(node->yaw - new_yaw) > 0.01)
converged = 0;
node->yaw = new_yaw;
node->pitch = -atan2(pitch[1],pitch[0]);
node->roll = -atan2(roll[1],roll[0]);
elog(LOG_DEBUG(11), "****node %d: avg yaw=%f pitch=%f roll=%f [%f,%f,%f] ",
node->node, r2d(node->yaw),
r2d(node->pitch),
r2d(node->roll),
sqrt(sqrf(yaw[0])+sqrf(yaw[1])),
sqrt(sqrf(pitch[0])+sqrf(pitch[1])),
sqrt(sqrf(roll[0])+sqrf(roll[1])));
totx += cos(node->yaw);
toty += sin(node->yaw);
totsum++;
}
}
mreal avgor = atan2(toty,totx);
elog(LOG_WARNING, "average orientation is %f", avgor);
#ifndef ORIENT_BY_ROOT
if (converged) {
mreal max_diff = -1;
/* rotate all points and unorient */
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
node->yaw -= avgor;
mreal tmpx = node->x;
mreal tmpy = node->y;
node->x = cos(avgor)*tmpx - sin(avgor)*tmpy;
node->y = sin(avgor)*tmpx + cos(avgor)*tmpy;
if (node->state != RESULT_COORD_ROOT && node->col >= 0) {
mreal diff;
diff = fabs(gsl_vector_get(x_res, node->col + 0) +
(node->x - tmpx));
if (diff > max_diff) max_diff = diff;
diff = fabs(gsl_vector_get(x_res, node->col + 1) +
(node->y - tmpy));
if (diff > max_diff) max_diff = diff;
}
}
elog(LOG_WARNING, "MAX DIFF = %f", max_diff);
}
#endif
if (converged) dobreak = 1;
/******************/
/* out put errors */
/******************/
/*
* This can be done in the mess above, but to keep it from getting
* too messy, we just repeat down here
*/
buf_t *resbuf = buf_new();
bufprintf(resbuf, "#h receiver chirper axis resid\n");
// declared earlier int node1_loc = 0, node2_loc = 0;
// for (i = 0; i < b->size; ++i) {
for (i = 0; i < num_rows; i+=axes) {
/* find the ranges */
for (mtr = range_list_top(mls->multilat_lists) ;
mtr != NULL; mtr = range_list_next(mtr)) {
if (i == mtr->last_row) {
break;
}
}
if (mtr == NULL) {
elog(LOG_WARNING, "Could not find range for that row!");
exit(1);
}
/* find the new calculated positions and the range */
node1_loc = result_list_array_lookup(mls, result_view, mtr->data_from);
node2_loc = result_list_array_lookup(mls, result_view, mtr->chirp_from);
int k;
for (k=0; k<axes; k++) {
int kk;
double sum = 0;
for (kk=0; kk<num_cols; kk++)
sum += (gsl_matrix_get(A, i+k, kk) * gsl_vector_get(x_res, kk));
sum -= gsl_vector_get(b, i+k);
bufprintf(resbuf, "%i %i %i %f\n",
mtr->data_from, mtr->chirp_from, k, sum);
/* $$ could also include range, angle error */
}
}
#if 0
char angleres[4096];
sprintf(angleres, "angleres%i", k);
multilatbuf_to_file(mls, angleres, ares);
buf_free(ares);
#endif
char errors[4096];
sprintf(errors, "errors%i", k);
multilatbuf_to_file(mls, errors, resbuf);
buf_free(resbuf);
/************************/
/* studentized residual */
/************************/
// H = X ( XT X )-1 XT.
if (dobreak && (mls->studthresh != 0)) {
/* num_rows is the number of ranges */
int l = 0;
gsl_matrix *X = gsl_matrix_calloc(num_rows, 2);
gsl_matrix *X2 = gsl_matrix_calloc(num_rows, 2);
gsl_matrix *XTrans = gsl_matrix_calloc(2, num_rows);
gsl_matrix *XTrans2 = gsl_matrix_calloc(2, num_rows);
gsl_matrix *XXTrans = gsl_matrix_calloc(2, 2);
gsl_matrix *H = gsl_matrix_calloc(num_rows, num_rows);
gsl_vector *stud = gsl_vector_calloc(num_rows);
double mean = 0.0;
double var = 0.0;
for (l = 0; l < num_rows; l++) {
mean += gsl_vector_get(b, l);
gsl_matrix_set(X, l, 0, 1);
gsl_matrix_set(X, l, 1, gsl_vector_get(b, l));
gsl_matrix_set(X2, l, 0, 1);
gsl_matrix_set(X2, l, 1, gsl_vector_get(b, l));
gsl_matrix_set(XTrans, 0, l, 1);
gsl_matrix_set(XTrans, 1, l, gsl_vector_get(b, l));
gsl_matrix_set(XTrans2, 0, l, 1);
gsl_matrix_set(XTrans2, 1, l, gsl_vector_get(b, l));
}
mean = mean / (num_rows + 0.0);
elog(LOG_WARNING, "mean is %f", mean);
gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, XTrans, X, 1.0, XXTrans);
gsl_blas_dtrsm(CblasRight, CblasUpper, CblasNoTrans, CblasNonUnit, 1.0, XXTrans, X2);
// upper or lower does not matter // gsl_blas_dtrsm(CblasRight, CblasLower, CblasNoTrans, CblasNonUnit, 1.0, XXTrans, X2);
gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, X2, XTrans2, 1.0, H);
/* calculate the variance */
for (l = 0; l < num_rows; ++l) {
var += m_pow_2(gsl_vector_get(b,l) - mean);
// elog(LOG_WARNING, "%f", gsl_matrix_get(H,l,l));
}
var = var / (num_rows + 0.0);
elog(LOG_WARNING, "var is %f", var);
buf_t *studbuf = buf_new();
bufprintf(studbuf, "#h res stud real chirpfrom datafrom\n");
mreal maxstud = 0;
for (l = 0; l < num_rows; l++) {
double a = gsl_vector_get(b, l) / (sqrtf(var) * sqrtf(1.0 - gsl_matrix_get(H,l,l)));
// gsl_vector_set(stud, l, a);
gsl_vector_set(stud, l, a >= 0 ? a : -a);
if (gsl_vector_get(stud, l) > mls->studthresh) {
if (gsl_vector_get(stud, l) > maxstud) {
maxstud = gsl_vector_get(stud, l);
}
}
}
if (maxstud > mls->studthresh)
for (l = 0; l < num_rows; l++) {
int range_index = (l/axes)*axes;
if (gsl_vector_get(stud, l) == maxstud) {
/* important! */
runagain = 1;
elog(LOG_WARNING, "val is %f at row %i", gsl_vector_get(stud, l), l);
last_drop_value = maxstud;
for (mtr = range_list_top(mls->multilat_lists) ;
mtr != NULL; mtr = range_list_next(mtr)) {
if (range_index == mtr->last_row) {
break;
}
}
if (mtr) {
if (mtr->state != RANGE_DROPPED) {
dropped_rows += axes;
mtr->state = RANGE_DROPPED;
int from = mtr->chirp_from;
int to = mtr->data_from;
bufprintf(droppedbuf, "%i %i %f %f %i\n", from, to,
gsl_vector_get(b,l),
gsl_vector_get(stud,l),
mls->global_run
);
for (mtr = range_list_top(mls->multilat_lists) ;
mtr != NULL; mtr = range_list_next(mtr)) {
if ((from == mtr->chirp_from && to == mtr->data_from) ||
(to == mtr->chirp_from && from == mtr->data_from)) {
if (mtr->state != RANGE_DROPPED) {
dropped_rows += axes;
mtr->state = RANGE_DROPPED;
}
}
}
}
}
else
elog(LOG_CRIT, "cant' find range.. ");
}
for (mtr = range_list_top(mls->multilat_lists) ;
mtr != NULL; mtr = range_list_next(mtr)) {
if (range_index == mtr->last_row) {
break;
}
}
if (mtr) {
multilat_result_t * mrr1 = result_list_get(mls, mtr->chirp_from);
multilat_result_t * mrr2 = result_list_get(mls, mtr->data_from);
bufprintf(studbuf, "%f %f %f %i %i\n",
gsl_vector_get(b,l),
gsl_vector_get(stud,l),
mtr->real_distance -
sqrtf(m_pow_2(mrr1->x - mrr2->x) +
m_pow_2(mrr1->y - mrr2->y) +
m_pow_2(mrr1->z - mrr2->z)),
mtr->chirp_from,
mtr->data_from
);
}
else
elog(LOG_CRIT, "cant' find range for index %d (%d).. 2",
range_index, l);
}
multilatbuf_to_file(mls, "compare", studbuf);
buf_free(studbuf);
elog(LOG_WARNING, " ----- All done!");
gsl_matrix_free(X);
gsl_matrix_free(X2);
gsl_matrix_free(XTrans);
gsl_matrix_free(XTrans2);
gsl_matrix_free(XXTrans);
gsl_matrix_free(H);
gsl_vector_free(stud);
}
mreal avg_resid = 0;
mreal rms_resid = 0;
int range_count = 0;
int l;
for (l = 0; l < num_rows; ++l) {
avg_resid += fabs(gsl_vector_get(b,l));
rms_resid += sqrf(gsl_vector_get(b,l));
range_count++;
}
if (range_count > 0) {
avg_resid /= (float)range_count;
rms_resid = sqrt(rms_resid/(float)range_count);
}
elog(LOG_CRIT, "**** average residuals:");
elog(LOG_CRIT, "AVG: %f RMS: %f",
avg_resid, rms_resid);
/**************/
/* free stuff */
/**************/
gsl_matrix_free(A);
gsl_vector_free(b);
gsl_matrix_free(new_A);
gsl_matrix_free(V);
gsl_vector_free(s);
// gsl_vector_free(work);
gsl_vector_free(x_res);
// gsl_vector_free(check);
buf_t *firstpass = buf_new();
char thefile[4096];
memset(thefile, 0, 4096);
sprintf(thefile, "pass%i", k);
result_list_print(mls, firstpass);
multilatbuf_to_file(mls, thefile, firstpass);
buf_free(firstpass);
if (dobreak) {
dobreak = 0;
break;
}
}
/* print out the final error stuff */
buf_t *ce = buf_new();
bufprintf(ce, "#h node coorderror\n");
multilat_result_t *mlr = result_list_top(mls->multilat_lists);
mreal rms = 0;
int count = 0;
for ( ; mlr != NULL; mlr = result_list_next(mlr) ) {
if (mlr->state != RESULT_COORD_ROOT) {
bufprintf(ce, "%i %f\n", mlr->node,
sqrtf(m_pow_2(mlr->x - mlr->real_x) +
m_pow_2(mlr->y - mlr->real_y) +
m_pow_2(mlr->z - mlr->real_z))
);
rms += m_pow_2(mlr->x - mlr->real_x) +
m_pow_2(mlr->y - mlr->real_y) +
m_pow_2(mlr->z - mlr->real_z);
count++;
}
}
bufprintf(ce, "# rms: %f\n", sqrtf(rms / (count + 0.0)));
bufprintf(ce, "# Grms: %f\n", mls->guess_rms);
multilatbuf_to_file(mls, "coorderr", ce);
buf_free(ce);
iterations = k;
analyse_result(mls);
/*************/
/* increment */
/*************/
if (runagain) {
mls->global_run++;
runagain = 0;
goto repeate;
}
multilatbuf_to_file(mls, "dropped", droppedbuf);
buf_free(droppedbuf);
mls->global_run = 1000;
{
buf_t *firstpass = buf_new();
char thefile[4096];
memset(thefile, 0, 4096);
sprintf(thefile, "last");
result_list_print(mls, firstpass);
multilatbuf_to_file(mls, thefile, firstpass);
buf_free(firstpass);
}
analyse_result(mls);
return;
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
#else //!RTHETA
void reset_matrix(ml_state_t *mls, int num_rows)
{
if (mls->row_info) free(mls->row_info);
mls->row_info = g_new0(struct row_info, num_rows);
mls->row_count = 0;
}
int addrow(ml_state_t *mls, int type, multilat_range_t *new_range)
{
mls->row_info[mls->row_count].c_type = type;
mls->row_info[mls->row_count].range = new_range;
mls->row_count++;
return mls->row_count;
}
int get_row_type(ml_state_t *mls, int row)
{
return mls->row_info[row].c_type;
}
multilat_range_t *get_row_range(ml_state_t *mls, int row)
{
return mls->row_info[row].range;
}
/* compare the forward and reverse paths and compute
* estimates of the common delta for each node.
* the theory is that there may be a fixed delay for each node
* that accounts for the fwd/rev differences
*
* (Rij, i is the receiver)
* Rij = T + Di - Dj
* Rji = T + Dj - Di
* Rij - Di + Dj = Rji - Dj + Di
* Rij - Rji = 2Di - 2Dj
*/
void compute_deltas(ml_state_t *mls)
{
multilat_result_t *node;
multilat_range_t *mtr;
int rows = 0;
/* clear delta_in flags */
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
node->delta_in = 0;
node->col = -1;
}
/* count number of rows */
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
mtr->last_row = -1;
/* sort out ranges */
if (!mtr->drop_r && !mtr->peer->drop_r) {
if (fabs(mtr->peer->distance - mtr->distance) > MAX_BIDIR_DIFF ||
(mtr->peer->distance > MAX_BIDIR_DIFF &&
fabs(mtr->peer->distance - mtr->distance) > (mtr->distance * 0.1))) {
elog(LOG_WARNING, "dropping bogus range and angles..");
if (mtr->peer->distance > mtr->distance) {
mtr->peer->drop_r = mtr->peer->drop_p = mtr->peer->drop_t = 1;
}
else {
mtr->drop_r = mtr->drop_p = mtr->drop_t = 1;
}
}
}
if (!mtr->drop_r && !mtr->peer->drop_r) {
if (fabs(mtr->peer->distance - mtr->distance) < 20) {
mtr->result->delta_in++;
mtr->peer->result->delta_in++;
rows++;
}
}
}
rows /= 2;
#ifdef COMPUTE_DELTAS
/* count cols */
int cols = 0;
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
if (node->delta_in) cols++;
}
/* set up matrices */
gsl_matrix *A;
gsl_vector *b;
elog(LOG_WARNING, "allocing %d by %d matrix", rows, cols);
A = gsl_matrix_calloc(rows, cols);
b = gsl_vector_calloc(rows);
int curr_row = 0;
int curr_col = 0;
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
/* skip if... */
if (mtr->last_row >= 0) continue;
if (mtr->drop_r || mtr->peer->drop_r) continue;
if (fabs(mtr->peer->distance - mtr->distance) >= 20) continue;
/* ok, add it */
if (mtr->result->col < 0)
mtr->result->col = curr_col++;
if (mtr->peer->result->col < 0)
mtr->peer->result->col = curr_col++;
mtr->last_row = curr_row;
mtr->peer->last_row = curr_row;
/* b = Rij - Rji */
gsl_vector_set(b, curr_row, mtr->distance - mtr->peer->distance);
/* A = 2Di - 2Dj */
gsl_matrix_set(A, curr_row, mtr->result->col, +2);
gsl_matrix_set(A, curr_row, mtr->peer->result->col, -2);
curr_row++;
}
gsl_matrix *new_A;
gsl_matrix *V;
gsl_vector *s;
gsl_vector *x_res;
new_A = gsl_matrix_calloc(rows, cols);
V = gsl_matrix_calloc(cols, cols);
s = gsl_vector_calloc(cols);
x_res = gsl_vector_calloc(cols);
buf_t *bn = buf_new();
print_matrix(bn, A);
multilatbuf_to_file(mls, "DeltatAis", bn);
buf_free(bn);
int res = gsl_matrix_memcpy(new_A, A);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error copying new matrix: %s\n", gsl_strerror(res));
exit(1);
}
elog(LOG_WARNING, "Starting svdecomp");
res = gsl_linalg_SV_decomp_jacobi(new_A, V, s);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error doing svdecomp: %s\n", gsl_strerror(res));
goto mlat_failed;
}
elog(LOG_WARNING, "Starting SV solve");
res = gsl_linalg_SV_solve(new_A, V, s, b, x_res);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error doing svdecomp Solve: %s\n", gsl_strerror(res));
goto mlat_failed;
}
/* ok, should now have the answers! */
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
if (node->col >= 0) {
node->delta = gsl_vector_get(x_res, node->col);
elog(LOG_WARNING, "node %d, delta=%.2f", node->node, node->delta);
}
}
#endif
}
int multilat_solver(ml_state_t *mls) {
buf_t *studbuf = NULL;
mls->failed_convergence = 3;
int total_iterations = 0;
int total_passes = 0;
/*
* configure peer relationships
*/
multilat_range_t *mtr;
LOG_ENTRY("****starting multilat");
/* clear peers */
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
mtr->peer = NULL;
if (mtr->distance > 0)
mtr->drop_r = mtr->drop_t = mtr->drop_p = 0;
}
/* set peers and results */
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
if (mtr->peer == NULL) {
multilat_range_t *mtr2;
for (mtr2 = range_list_top(mls->multilat_lists);
mtr2; mtr2 = range_list_next(mtr2)) {
if (mtr != mtr2 &&
mtr->chirp_from == mtr2->data_from &&
mtr->data_from == mtr2->chirp_from &&
mtr2->peer == NULL) {
mtr->peer = mtr2;
mtr2->peer = mtr;
break;
}
}
mtr->result = result_list_get(mls, mtr->data_from);
if (mtr->peer == NULL) {
mtr2 = g_new0(multilat_range_t, 1);
range_list_push(mls->multilat_lists, mtr2);
mtr->peer = mtr2;
mtr2->peer = mtr;
mtr2->chirp_from = mtr->data_from;
mtr2->data_from = mtr->chirp_from;
mtr2->drop_r = mtr2->drop_t = mtr2->drop_p = 1;
}
mtr->peer->result = result_list_get(mls, mtr->peer->data_from);
}
}
/* compute the deltas.. */
compute_deltas(mls);
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
if (!mtr->drop_r && !mtr->peer->drop_r) {
if (mtr->peer->distance > mtr->distance) {
mtr->peer->userange = mtr->userange = mtr->distance;
}
else {
mtr->peer->userange = mtr->userange = mtr->peer->distance;
}
/* 8cm*sin(phi) accounts for excess length when coming in off plane */
mtr->userange += sin(mtr->phi) * PHI_DIST_VARIATION;
mtr->peer->userange += sin(mtr->peer->phi) * PHI_DIST_VARIATION;
}
else {
if (!mtr->drop_r)
mtr->userange = mtr->distance + sin(mtr->phi) * PHI_DIST_VARIATION;
if (!mtr->peer->drop_r)
mtr->peer->userange = mtr->peer->distance + sin(mtr->peer->phi) * PHI_DIST_VARIATION;
}
}
/* clear column assignments */
multilat_result_t *node;
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
node->col = -1;
}
/* compute number of roots */
int num_roots = 0;
multilat_result_t *mlr;
for (mlr = result_list_top(mls->multilat_lists);
mlr; mlr = result_list_next(mlr)) {
if (mlr->state == RESULT_COORD_ROOT)
num_roots++;
}
int runagain = 0;
int num_rows = 0;
int num_cols = 0;
buf_t *droppedbuf = buf_new();
int useVV = 0;
#ifdef USEZ
int axes = 3;
#else
int axes = 2;
#endif
/******************/
/* get dimensions */
/******************/
repeate:
if (mls->global_run != 0) {
result_load(mls);
}
mreal VV = 1;
/***********/
/* iterate */
/***********/
int k = 0;
int orient_count = 0;
for (k = 0; k < 100; ++k) {
elog(LOG_WARNING, "starting iterations %d", k);
total_iterations++;
/* reset usage bits and columns */
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
mtr->use_r = mtr->use_t = mtr->use_p = mtr->use_set = 0;
mtr->result->col = -1;
}
/* for each pair, decide which to use */
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
/* continue if already processed */
if (mtr->use_set) continue;
/* set bit */
mtr->use_set = 1;
if (mtr->peer) mtr->peer->use_set = 1;
/* continue if between two roots */
if (mtr->result->state == RESULT_COORD_ROOT &&
mtr->peer && mtr->peer->result->state == RESULT_COORD_ROOT)
continue;
/* if range is not dropped, use it */
if (!mtr->drop_r)
mtr->use_r = 1;
else if (!mtr->peer->drop_r)
mtr->peer->use_r = 1;
if (mls->useangles) {
/* use this theta angle if not dropped */
if (!mtr->drop_t && mtr->peer && !mtr->peer->drop_t) {
if (mtr->angle_conf > mtr->peer->angle_conf)
mtr->use_t = 1;
else
mtr->peer->use_t = 1;
}
else if (!mtr->drop_t)
mtr->use_t = 1;
else if (mtr->peer && !mtr->peer->drop_t)
mtr->peer->use_t = 1;
#ifndef HACK_OUT_PHI
if (axes > 2) {
/* use this phi angle if not dropped */
if (!mtr->drop_p && mtr->peer && !mtr->peer->drop_p) {
if (mtr->angle_conf > mtr->peer->angle_conf)
mtr->use_p = 1;
else
mtr->peer->use_p = 1;
}
else if (!mtr->drop_p)
mtr->use_p = 1;
else if (mtr->peer && !mtr->peer->drop_p)
mtr->peer->use_p = 1;
}
#endif
}
}
/* count rows and columns */
num_rows = 0;
num_cols = 0;
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
int eqns = (mtr->use_r + mtr->use_p + mtr->use_t);
num_rows += eqns;
if (mtr->peer)
eqns += (mtr->peer->use_r + mtr->peer->use_p + mtr->peer->use_t);
if (eqns > 0 && mtr->result->col == -1 && mtr->result->state != RESULT_COORD_ROOT) {
mtr->result->col = num_cols;
num_cols += axes;
}
}
elog(LOG_CRIT, "total rows %d, num cols %d", num_rows, num_cols);
if (num_cols > num_rows) {
elog(LOG_CRIT, "Can not continue with SVD only have %i by %i matrix", num_rows, num_cols);
goto mlat_failed;
}
if (num_cols == 0 || num_rows == 0) {
elog(LOG_CRIT, "must have rows or cols");
goto mlat_failed;
}
/* clear row map */
reset_matrix(mls, num_rows);
/* setup the matrix */
gsl_matrix *A;
gsl_vector *b;
int Vcol;
elog(LOG_DEBUG(0), "allocing %d,%d matrix", num_rows, num_cols+useVV);
A = gsl_matrix_calloc(num_rows, num_cols+useVV);
b = gsl_vector_calloc(num_rows);
Vcol = num_cols;
int curr_row = 0;
for (mtr = range_list_top(mls->multilat_lists);
mtr; mtr = range_list_next(mtr)) {
if (mtr->peer == NULL) {
elog(LOG_WARNING, "no peer??");
continue;
}
multilat_result_t *node1 = mtr->result;
multilat_result_t *node2 = mtr->peer->result;
mreal DX = node2->x - node1->x;
mreal DY = node2->y - node1->y;
mreal DZ = node2->z - node1->z;
mreal D = sqrtf(sqrf(DX) + sqrf(DY) + sqrf(DZ));
if (mtr->use_r) {
/* protect against explosion */
if (D < 1.0) {
D = 1.0;
}
mreal w = 1.0; //(mls->include_conf ? mtr->conf / 10.0 : 1.0);
if (node1->state != RESULT_COORD_ROOT) {
gsl_matrix_set(A, curr_row, node1->col + 0, -VV/D*DX*w);
gsl_matrix_set(A, curr_row, node1->col + 1, -VV/D*DY*w);
if (axes > 2)
gsl_matrix_set(A, curr_row, node1->col + 2, -VV/D*DZ*w);
}
if (node2->state != RESULT_COORD_ROOT) {
gsl_matrix_set(A, curr_row, node2->col + 0, VV/D*DX*w);
gsl_matrix_set(A, curr_row, node2->col + 1, VV/D*DY*w);
if (axes > 2)
gsl_matrix_set(A, curr_row, node2->col + 2, VV/D*DZ*w);
}
if (useVV)
gsl_matrix_set(A, curr_row, Vcol, D*w);
gsl_vector_set(b, curr_row, (mtr->userange - VV*D)*w);
curr_row = addrow(mls, ML_CONSTRAINT_RANGE, mtr);
}
/************/
/* angle */
/************/
// node 2 chirps
// node 1 send data
if (mls->useangles) {
if (mtr->use_t) {
if (fabsf(DX) < 1.0 || fabsf(DY) < 1.0) {
elog(LOG_WARNING, "skipping angle for %d->%d", node1->node, node2->node);
if (k>10) {
elog(LOG_CRIT, "DROPPING angle for %d->%d", node1->node, node2->node);
mtr->drop_t = 1;
}
goto skipangle;
}
double T = 1.0/(1.0+sqrf(DY/DX));
double mply = 226 * mtr->angle_conf;
if (node1->state != RESULT_COORD_ROOT) {
gsl_matrix_set(A, curr_row, node1->col + 0, mply * +T * (DY / sqrf(DX)));
gsl_matrix_set(A, curr_row, node1->col + 1, mply * -T * (1 / DX));
}
if (node2->state != RESULT_COORD_ROOT) {
gsl_matrix_set(A, curr_row, node2->col + 0, mply * -T * (DY / sqrf(DX)));
gsl_matrix_set(A, curr_row, node2->col + 1, mply * +T * (1 / DX));
}
gsl_vector_set(b, curr_row, mply* misc_normalize_angle_rad_d
((mtr->theta - node1->yaw) - (atan2f(DY, DX))));
skipangle:
curr_row = addrow(mls, ML_CONSTRAINT_THETA, mtr);
}
if (axes > 2 && mtr->use_p) {
/*
* weighing scheme:
* sigma for range 3.8 cm
* sigma for AZI 0.96 deg = 226x
* sigma for ZEN 45-45 3.6 deg = 60x
* sigma for ZEN 45-90 4.5 deg = 48x
*/
mreal use_phi = misc_normalize_angle_rad_d(mtr->phi);
#ifdef CORRECT_PHI
mreal corr = misc_normalize_angle_rad_d
(sin(mtr->theta)*node1->pitch + cos(mtr->theta)*node1->roll);
elog(LOG_DEBUG(11), "phi was %f, roll correction %f, now is %f",
r2d(use_phi), r2d(corr), r2d(corr+use_phi));
use_phi += corr;
#endif
double w = ((fabs(use_phi) > (45/180.0*M_PI)) ? 48.0 : 60.0) *
3.0 * mtr->angle_conf; //3.0
float D_sqr = sqrf(DX) + sqrf(DY);
if (D_sqr < 1.0) D_sqr = 1.0;
float D_prime = sqrtf(D_sqr);
float T_prime = 1.0/(1.0 + sqrf(DZ/D_prime));
float K = DZ * powf(D_sqr, -3.0/2.0);
if (node1->state != RESULT_COORD_ROOT) {
gsl_matrix_set(A, curr_row, node1->col + 0, w*T_prime*K*DX);
gsl_matrix_set(A, curr_row, node1->col + 1, w*T_prime*K*DY);
gsl_matrix_set(A, curr_row, node1->col + 2, -w*T_prime/D_prime);
}
if (node2->state != RESULT_COORD_ROOT) {
gsl_matrix_set(A, curr_row, node2->col + 0, -w*T_prime*K*DX);
gsl_matrix_set(A, curr_row, node2->col + 1, -w*T_prime*K*DY);
gsl_matrix_set(A, curr_row, node2->col + 2, +w*T_prime/D_prime);
}
gsl_vector_set(b, curr_row,
w*misc_normalize_angle_rad_d
(use_phi - misc_normalize_angle_rad_d(atan2f(DZ, D_prime))));
curr_row = addrow(mls, ML_CONSTRAINT_PHI, mtr);
}
}
}
elog(LOG_CRIT, "Just added %i rows", curr_row);
/************/
/* SVDecomp */
/************/
gsl_matrix *new_A;
gsl_matrix *V;
gsl_vector *s;
gsl_vector *x_res;
new_A = gsl_matrix_calloc(num_rows, num_cols + useVV);
V = gsl_matrix_calloc(num_cols + useVV, num_cols + useVV);
s = gsl_vector_calloc(num_cols + useVV);
x_res = gsl_vector_calloc(num_cols + useVV);
buf_t *bn = buf_new();
print_matrix(bn, A);
multilatbuf_to_file(mls, "Ais", bn);
buf_free(bn);
int res = gsl_matrix_memcpy(new_A, A);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error copying new matrix: %s\n", gsl_strerror(res));
exit(1);
}
elog(LOG_WARNING, "Starting svdecomp");
res = gsl_linalg_SV_decomp_jacobi(new_A, V, s);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error doing svdecomp: %s\n", gsl_strerror(res));
goto mlat_failed;
}
elog(LOG_WARNING, "Starting SV solve");
res = gsl_linalg_SV_solve(new_A, V, s, b, x_res);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error doing svdecomp Solve: %s\n", gsl_strerror(res));
goto mlat_failed;
}
elog(LOG_WARNING, "Printing state");
print_multitlat_state(mls, A, new_A, V, s, b, x_res, k);
elog(LOG_WARNING, "Done");
/*********************************/
/* update the results with x_res */
/*********************************/
int dobreak = 1;
if (useVV) {
VV += gsl_vector_get(x_res, Vcol);
elog(LOG_WARNING, "V is now %f", VV);
}
multilat_result_t *node;
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
if (node->state != RESULT_COORD_ROOT && node->col >= 0) {
node->x += (gsl_vector_get(x_res, node->col + 0));
node->y += (gsl_vector_get(x_res, node->col + 1));
if (axes > 2)
node->z += (gsl_vector_get(x_res, node->col + 2));
if (fabs(gsl_vector_get(x_res, node->col + 0)) > 0.01 ||
fabs(gsl_vector_get(x_res, node->col + 1)) > 0.01 ||
((axes > 2) && fabs(gsl_vector_get(x_res, node->col + 2)) > 0.01)) {
dobreak = 0;
}
}
}
#ifdef STANDALONE_MULTILAT
/* allow outlier rejection even if convergence failed */
if (k > 50) dobreak = 1;
#endif
/* only update orienation for first 10 iterations */
if (orient_count<10) {
orient_count++;
/*************************/
/* update yaw/pitch/roll */
/*************************/
mreal totx=0;
mreal toty=0;
int totsum=0;
//mreal max_err=0;
//int reset_orient_count = 0;
/* for angle-check-mode */
multilat_range_t *worst_angle = NULL;
mreal worst_angle_value = 0;
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
/* compute orientation for roots if there is more than one of them.
* otherwise, lock in specified orientation */
//if (num_roots > 1 || (result_view[i]->state != RESULT_COORD_ROOT))
{
mreal yaw[2] = {0,0};
mreal pitch[2] = {0,0};
mreal roll[2] = {0,0};
for (mtr = range_list_top(mls->multilat_lists);
mtr != NULL; mtr = range_list_next(mtr)) {
if (mtr->result == node && mtr->peer) {
multilat_result_t *chirp_node = mtr->peer->result;
mreal c[3];
mreal ctheta,cphi;
mreal dtheta,dphi;
/* unit vector of computed angle */
c[0] = chirp_node->x - node->x;
c[1] = chirp_node->y - node->y;
c[2] = chirp_node->z - node->z;
mreal D = sqrt(sqrf(c[0]) + sqrf(c[1]) + sqrf(c[2]));
c[0] /= D;
c[1] /= D;
c[2] /= D;
/* zenith and azimuth angles */
ctheta = atan2(c[1], c[0]);
cphi = misc_normalize_angle_rad_d(atan2(c[2], sqrt(sqrf(c[0])+sqrf(c[1]))));
/* diffs */
dtheta = ctheta - mtr->theta;
dphi = cphi - misc_normalize_angle_rad_d(mtr->phi);
/* if orient_count == 10, then we are in angle-check mode. */
if (orient_count == 10 && !mtr->drop_t) {
mreal diff = misc_normalize_angle_rad_d
(fabs(misc_normalize_angle_rad_d(dtheta) +
misc_normalize_angle_rad_d(node->yaw)));
if (diff > worst_angle_value) {
worst_angle_value = diff;
worst_angle = mtr;
}
}
if (!mtr->drop_t) {
/* sum (could weight by confidence..) */
yaw[0] += cos(dtheta)*cos(cphi);
yaw[1] += sin(dtheta)*cos(cphi);
}
if (!mtr->drop_p) { // && fabs(dphi) < (6/180.0*M_PI)) {
elog(LOG_DEBUG(20),
"dphi %f ctheta %f p += %f %f ",
r2d(dphi), r2d(ctheta),
fabs(cos(ctheta))*cos(dphi),
cos(ctheta)*sin(dphi));
elog(LOG_DEBUG(20),
"dphi %f ctheta %f r += %f %f ",
r2d(dphi), r2d(ctheta),
fabs(sin(ctheta))*cos(dphi),
sin(ctheta)*sin(dphi));
pitch[0] += fabs(cos(ctheta))*cos(dphi);
pitch[1] += cos(ctheta)*sin(dphi);
roll[0] += fabs(sin(ctheta))*cos(dphi);
roll[1] += sin(ctheta)*sin(dphi);
elog(LOG_DEBUG(20),
" == %f,%f (%f)",
pitch[0],pitch[1],
r2d(atan2(pitch[1],pitch[0])));
elog(LOG_DEBUG(20),
" == %f,%f (%f)",
roll[0],roll[1],
r2d(atan2(roll[1],roll[0])));
}
else {
elog(LOG_DEBUG(11), "skipping dphi=%f", dphi*180.0/M_PI);
}
}
}
node->yaw = -atan2(yaw[1],yaw[0]);
node->pitch = -atan2(pitch[1],pitch[0]);
node->roll = -atan2(roll[1],roll[0]);
elog(LOG_DEBUG(11), "****node %d: avg yaw=%f pitch=%f roll=%f [%f,%f,%f] ",
node->node, r2d(node->yaw),
r2d(node->pitch),
r2d(node->roll),
sqrt(sqrf(yaw[0])+sqrf(yaw[1])),
sqrt(sqrf(pitch[0])+sqrf(pitch[1])),
sqrt(sqrf(roll[0])+sqrf(roll[1])));
totx += cos(node->yaw);
toty += sin(node->yaw);
totsum++;
}
}
/* if orient_count == 10, then we are in angle-check mode. */
if (orient_count == 10) {
if (!mls->noreject && worst_angle_value > d2r(20)) {
elog(LOG_CRIT, "***DROPPING RANGE %d->%d because angle is off by %f!!!!",
worst_angle->chirp_from, worst_angle->data_from, r2d(worst_angle_value));
worst_angle->drop_r = worst_angle->drop_t = worst_angle->drop_p = 1;
//reset_orient_count = 1;
/* keep doing orientation if we dropped a range */
// if (reset_orient_count)
orient_count = 7;
}
}
mreal avgor = atan2(toty,totx);
elog(LOG_WARNING, "average orientation is %f", avgor);
#ifdef ORIENT_BY_ROOT
if (num_roots == 1) {
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
if (node->state == RESULT_COORD_ROOT) {
avgor = node->yaw;
elog(LOG_WARNING, "root node orientation is %f", avgor);
}
}
}
#endif
mreal max_diff = -1;
/* rotate all points and unorient */
for (node = result_list_top(mls->multilat_lists);
node; node = result_list_next(node)) {
if (node->col < 0 && node->state != RESULT_COORD_ROOT) continue;
node->yaw -= avgor;
mreal tmpx = node->x;
mreal tmpy = node->y;
node->x = cos(avgor)*tmpx - sin(avgor)*tmpy;
node->y = sin(avgor)*tmpx + cos(avgor)*tmpy;
if (node->state != RESULT_COORD_ROOT && node->col >= 0) {
mreal diff;
diff = fabs(gsl_vector_get(x_res, node->col + 0) +
(node->x - tmpx));
if (diff > max_diff) max_diff = diff;
diff = fabs(gsl_vector_get(x_res, node->col + 1) +
(node->y - tmpy));
if (diff > max_diff) max_diff = diff;
}
}
elog(LOG_WARNING, "MAX DIFF = %f", max_diff);
if (max_diff >= 0 && max_diff < 0.01) dobreak = 1;
/* don't break until we've completed orientation stuff */
dobreak = 0;
}
#if 0
/******************/
/* out put errors */
/******************/
/*
* This can be done in the mess above, but to keep it from getting
* too messy, we just repeat down here
*/
buf_t *resbuf = buf_new();
bufprintf(resbuf,
"#h chirper listener residual realrange realtheta realphi "
"calcrange calctheta calcphi real-calcrange real-calctheta real-calcphi "
"introdisterr introthetaerr introphierr\n");
buf_t *ares = buf_new();
bufprintf(ares, "#h c l angle res type dz\n");
for (i = 0; i < num_rows; ++i) {
mtr = get_row_range(mls, i);
if (mtr == NULL) {
elog(LOG_WARNING, "can't find range for row %d!!", i);
exit(1);
}
multilat_result_t *node1 = mtr->result;
multilat_result_t *node2 = mtr->peer->result;
/******************/
switch (get_row_type(mls, i)) {
case ML_CONSTRAINT_RANGE:
bufprintf(resbuf, "%i %i %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
mtr->chirp_from,
mtr->data_from,
gsl_vector_get(b, i),
mtr->real_distance,
mtr->real_theta,
mtr->real_phi,
sqrtf(m_pow_2(node1->x - node2->x) + m_pow_2(node1->y - node2->y)),
atan2f(node2->y - node1->y, node2->x - node1->x),
0.0,
mtr->real_distance -
sqrtf(m_pow_2(node1->x - node2->x) +
m_pow_2(node1->y - node2->y)),
mtr->real_theta -
atan2f(node2->y - node1->y, node2->x - node1->x),
0.0,
mtr->introerr_distance,
mtr->introerr_theta,
mtr->introerr_phi);
break;
case ML_CONSTRAINT_THETA:
bufprintf(ares, "%i %i %f %f theta 0\n",
mtr->chirp_from,
mtr->data_from,
r2d(mtr->theta),
gsl_vector_get(b, i));
break;
case ML_CONSTRAINT_PHI:
bufprintf(ares, "%i %i %f %f phi %f\n",
mtr->chirp_from,
mtr->data_from,
r2d(mtr->phi),
gsl_vector_get(b, i),
mtr->peer->result->z - mtr->result->z);
break;
default:
break;
}
}
char angleres[4096];
sprintf(angleres, "angleres%i", k);
multilatbuf_to_file(mls, angleres, ares);
buf_free(ares);
char errors[4096];
sprintf(errors, "errors%i", k);
multilatbuf_to_file(mls, errors, resbuf);
buf_free(resbuf);
#endif
/************************/
/* studentized residual */
/************************/
// H = X ( XT X )-1 XT.
{
studbuf = buf_new();
#if 0 /* use martin's weird but working version.. */
bufprintf(studbuf, "#h res stud real chirpfrom datafrom\n");
int l = 0;
gsl_matrix *X = gsl_matrix_calloc(num_rows, num_cols);
gsl_matrix *X2 = gsl_matrix_calloc(num_rows, num_cols);
gsl_matrix *XTrans = gsl_matrix_calloc(num_cols, num_rows);
gsl_matrix *XTrans2 = gsl_matrix_calloc(num_cols, num_rows);
gsl_matrix *XXTrans = gsl_matrix_calloc(num_cols, num_cols);
gsl_matrix *H = gsl_matrix_calloc(num_rows, num_rows);
gsl_vector *stud = gsl_vector_calloc(num_rows);
gsl_vector *eps = gsl_vector_calloc(num_rows);
double sum = 0.0;
int res = gsl_matrix_memcpy(X, A);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error copying new matrix: %s\n", gsl_strerror(res));
exit(1);
}
res = gsl_matrix_transpose_memcpy(XTrans, X);
if (res != GSL_SUCCESS) {
elog(LOG_CRIT, "Error transposing new matrix: %s\n", gsl_strerror(res));
exit(1);
}
gsl_matrix_memcpy(XTrans2, XTrans);
gsl_matrix_memcpy(X2, X);
gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, XTrans, X, 1.0, XXTrans);
gsl_blas_dtrsm(CblasRight, CblasUpper, CblasNoTrans, CblasNonUnit, 1.0, XXTrans, X2);
gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, X2, XTrans2, 1.0, H);
/* compute residuals and the sum of squares */
sum = 0;
for (l = 0; l < num_rows; ++l) {
mreal eps_sum = 0;
int k;
for (k = 0; k < num_cols; ++k) {
eps_sum += gsl_matrix_get(A, l, k) * gsl_vector_get(x_res, k);
}
//elog(LOG_WARNING, "epssum=%f, b=%f", eps_sum, gsl_vector_get(b, l));
eps_sum -= gsl_vector_get(b, l);
gsl_vector_set(eps, l, eps_sum);
sum += sqrf(eps_sum);
}
/* compute the weighted residuals */
mreal max_stud = 0;
for (l = 0; l < num_rows; ++l) {
mreal sigma = sqrt((sum - sqrf(gsl_vector_get(eps, l))) / (mreal)(num_rows - 3));
mreal hat = sqrt(1.0 - gsl_matrix_get(H, l, l));
mreal a = fabs(gsl_vector_get(eps, l) / (sigma * hat));
gsl_vector_set(stud, l, a);
if (a > max_stud) max_stud = a;
mtr = get_row_range(mls, l);
multilat_result_t *mrr2 = mtr->result;
multilat_result_t *mrr1 = mtr->peer->result;
bufprintf(studbuf, "%f %f %f %i %i\n",
gsl_vector_get(eps,l),
gsl_vector_get(stud,l),
/* $$$ customize based on type!! */
mtr->real_distance - sqrtf(m_pow_2(mrr1->x - mrr2->x) + m_pow_2(mrr1->y - mrr2->y)),
mtr->chirp_from,
mtr->data_from
);
}
bufprintf(studbuf, "\n");
gsl_vector_free(eps);
#else
bufprintf(studbuf, "#h res stud measured chirpfrom datafrom\n");
int l = 0;
gsl_matrix *X = gsl_matrix_calloc(num_rows, 2);
gsl_matrix *X2 = gsl_matrix_calloc(num_rows, 2);
gsl_matrix *XTrans = gsl_matrix_calloc(2, num_rows);
gsl_matrix *XTrans2 = gsl_matrix_calloc(2, num_rows);
gsl_matrix *XXTrans = gsl_matrix_calloc(2, 2);
gsl_matrix *H = gsl_matrix_calloc(num_rows, num_rows);
gsl_vector *stud = gsl_vector_calloc(num_rows);
double mean = 0.0;
double var = 0.0;
for (l = 0; l < num_rows; ++l) {
mreal resid = gsl_vector_get(b, l);
mean += resid;
gsl_matrix_set(X, l, 0, 1);
gsl_matrix_set(X, l, 1, resid);
gsl_matrix_set(X2, l, 0, 1);
gsl_matrix_set(X2, l, 1, resid);
gsl_matrix_set(XTrans, 0, l, 1);
gsl_matrix_set(XTrans, 1, l, resid);
gsl_matrix_set(XTrans2, 0, l, 1);
gsl_matrix_set(XTrans2, 1, l, resid);
}
mean = mean / (num_rows + 0.0);
elog(LOG_WARNING, "mean is %f", mean);
gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, XTrans, X, 1.0, XXTrans);
gsl_blas_dtrsm(CblasRight, CblasUpper, CblasNoTrans, CblasNonUnit, 1.0, XXTrans, X2);
// upper or lower does not matter // gsl_blas_dtrsm(CblasRight, CblasLower, CblasNoTrans, CblasNonUnit, 1.0, XXTrans, X2);
gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, X2, XTrans2, 1.0, H);
/* calculate the variance */
for (l = 0; l < num_rows; ++l) {
var += m_pow_2(gsl_vector_get(b,l) - mean);
// elog(LOG_WARNING, "%f", gsl_matrix_get(H,l,l));
}
var = var / (num_rows + 0.0);
elog(LOG_WARNING, "var is %f", var);
mreal max_stud = 0;
for (l = 0; l < num_rows; ++l) {
double a = gsl_vector_get(b, l) / (sqrtf(var) * sqrtf(1.0 - gsl_matrix_get(H,l,l)));
// gsl_vector_set(stud, l, a);
gsl_vector_set(stud, l, a >= 0 ? a : -a);
if (gsl_vector_get(stud, l) > max_stud)
max_stud = gsl_vector_get(stud, l);
mtr = get_row_range(mls, l);
//multilat_result_t *mrr2 = mtr->result;
//multilat_result_t *mrr1 = mtr->peer->result;
if (get_row_type(mls, l) == ML_CONSTRAINT_RANGE)
bufprintf(studbuf, "%f %f %f %i %i\n",
gsl_vector_get(b,l),
gsl_vector_get(stud,l),
mtr->distance,
mtr->chirp_from,
mtr->data_from
);
}
bufprintf(studbuf, "\n");
#endif
if (dobreak && mls->studthresh != 0) {
if (runagain == 0 && max_stud > mls->studthresh) {
for (l = 0; l < num_rows; ++l) {
if (gsl_vector_get(stud, l) == max_stud) {
last_drop_value = max_stud;
/* important! */
runagain = 1;
mtr = get_row_range(mls, l);
char *type = NULL;
switch (get_row_type(mls, l)) {
case ML_CONSTRAINT_RANGE:
type = "range";
mtr->drop_r = 1; mtr->drop_t = 1; mtr->drop_p = 1;
break;
case ML_CONSTRAINT_THETA:
type = "theta";
mtr->drop_t = 1; break;
case ML_CONSTRAINT_PHI:
type = "phi";
mtr->drop_p = 1; break;
}
elog(LOG_WARNING, "dropping %s %d->%d (val is %f at row %i)",
type, mtr->chirp_from, mtr->data_from, gsl_vector_get(stud, l), l);
bufprintf(droppedbuf, "%i %i %s %f %f %i\n", mtr->chirp_from, mtr->data_from, type,
gsl_vector_get(b,l),
gsl_vector_get(stud,l),
mls->global_run
);
multilatbuf_to_file(mls, "dropped", droppedbuf);
}
}
}
gsl_matrix_free(X);
gsl_matrix_free(X2);
gsl_matrix_free(XTrans);
gsl_matrix_free(XTrans2);
gsl_matrix_free(XXTrans);
gsl_matrix_free(H);
gsl_vector_free(stud);
}
multilatbuf_to_file(mls, "compare", studbuf);
elog(LOG_WARNING, " ----- All done!");
}
mreal avg_range_resid = 0;
mreal avg_angle_resid = 0;
mreal avg_phi_resid = 0;
mreal rms_range_resid = 0;
mreal rms_angle_resid = 0;
mreal rms_phi_resid = 0;
int range_count = 0;
int theta_count = 0;
int phi_count = 0;
int l;
for (l = 0; l < num_rows; ++l) {
switch (get_row_type(mls, l)) {
case ML_CONSTRAINT_RANGE:
avg_range_resid += fabs(gsl_vector_get(b,l));
rms_range_resid += sqrf(gsl_vector_get(b,l));
range_count++;
break;
case ML_CONSTRAINT_THETA:
avg_angle_resid += fabs(gsl_vector_get(b,l));
rms_angle_resid += sqrf(gsl_vector_get(b,l));
theta_count++;
break;
case ML_CONSTRAINT_PHI:
avg_phi_resid += fabs(gsl_vector_get(b,l));
rms_phi_resid += sqrf(gsl_vector_get(b,l));
phi_count++;
break;
}
}
if (range_count > 0) {
avg_range_resid /= (float)range_count;
rms_range_resid = sqrt(rms_range_resid/(float)range_count);
}
if (theta_count > 0) {
avg_angle_resid /= (float)theta_count;
rms_angle_resid = sqrt(rms_angle_resid/(float)theta_count);
}
if (phi_count > 0) {
avg_phi_resid /= (float)phi_count;
rms_phi_resid = sqrt(rms_phi_resid/(float)phi_count);
}
elog(LOG_CRIT, "**** average residuals:");
elog(LOG_CRIT, " range: %f angle: %f phi %f",
avg_range_resid, avg_angle_resid, avg_phi_resid);
elog(LOG_CRIT, "RMS range: %f angle: %f phi %f",
rms_range_resid, rms_angle_resid, rms_phi_resid);
/**************/
/* free stuff */
/**************/
gsl_matrix_free(A);
gsl_vector_free(b);
gsl_matrix_free(new_A);
gsl_matrix_free(V);
gsl_vector_free(s);
// gsl_vector_free(work);
gsl_vector_free(x_res);
// gsl_vector_free(check);
buf_t *firstpass = buf_new();
char thefile[4096];
memset(thefile, 0, 4096);
sprintf(thefile, "pass%i", k);
result_list_print(mls, firstpass);
multilatbuf_to_file(mls, thefile, firstpass);
buf_free(firstpass);
#ifndef STANDALONE_MULTILAT
/*
* check for explosion and update the status!
*/
/* pack up the answers and push them to the main thread */
buf_t *result = buf_new();
buf_t *answer = buf_new();
multilat_result_t *node1;
for (node1 = result_list_top(mls->multilat_lists);
node1; node1 = result_list_next(node1)) {
if (node1->col < 0 && node1->state != RESULT_COORD_ROOT) {
elog(LOG_WARNING, "skipping node %d that isn't in the matrix..", node1->node);
continue;
}
if (fabs(node1->x) > 100000 || fabs(node1->y) > 100000 ||
fabs(node1->z) > 100000 || fabs(node1->yaw) > 100000 ||
!isnormal(node1->x) || !isnormal(node1->y) ||
!isnormal(node1->z) || !isnormal(node1->yaw)) {
elog(LOG_CRIT, "oops.. it blew up!");
mls->failed_convergence = 1;
buf_free(answer);
buf_free(result);
goto mlat_failed;
}
coord_entry_t ce = {
node: node1->node,
coord: { node1->x*10, node1->y*10, node1->z*10 },
rpy: { r2d(-node1->roll)*10, r2d(-node1->pitch)*10, r2d(-node1->yaw)*10 },
valid: 1
};
bufcpy(answer, &ce, sizeof(ce));
}
buf_t *errors = mlat_errors_to_buf(mls, NULL);
bufcpy(result, &answer, sizeof(answer));
bufcpy(result, &errors, sizeof(errors));
bufcpy(result, &studbuf, sizeof(studbuf));
studbuf = NULL;
g_msg_queue_push(mls->results_queue, result);
#endif
if (dobreak) {
dobreak = 0;
break;
}
//#ifdef STANDALONE_MULTILAT
dump_errors(mls, k);
//#endif
}
/* print out the final error stuff */
buf_t *ce = buf_new();
bufprintf(ce, "#h node coorderror\n");
mreal rms = 0;
int count = 0;
for (mlr = result_list_top(mls->multilat_lists);
mlr; mlr = result_list_next(mlr)) {
if (mlr->state != RESULT_COORD_ROOT) {
bufprintf(ce, "%i %f\n", mlr->node,
sqrtf(m_pow_2(mlr->x - mlr->real_x) +
m_pow_2(mlr->y - mlr->real_y) +
m_pow_2(mlr->z - mlr->real_z))
);
rms += m_pow_2(mlr->x - mlr->real_x) +
m_pow_2(mlr->y - mlr->real_y) +
m_pow_2(mlr->z - mlr->real_z);
count++;
}
}
bufprintf(ce, "# rms: %f\n", sqrtf(rms / (count + 0.0)));
bufprintf(ce, "# Grms: %f\n", mls->guess_rms);
multilatbuf_to_file(mls, "coorderr", ce);
buf_free(ce);
iterations = k;
#ifdef STANDALONE_MULTILAT
analyse_result(mls);
#endif
/*************/
/* increment */
/*************/
if (runagain) {
total_passes++;
mls->global_run++;
runagain = 0;
goto repeate;
}
multilatbuf_to_file(mls, "dropped", droppedbuf);
buf_free(droppedbuf);
mls->global_run = 1000;
{
buf_t *firstpass = buf_new();
char thefile[4096];
memset(thefile, 0, 4096);
sprintf(thefile, "last");
result_list_print(mls, firstpass);
multilatbuf_to_file(mls, thefile, firstpass);
buf_free(firstpass);
}
#ifdef STANDALONE_MULTILAT
analyse_result(mls);
#endif
mls->failed_convergence = 2;
LOG_ENTRY("****multilat success, %d, %d", total_iterations, total_passes);
return 0;
mlat_failed:
LOG_ENTRY("****multilat failed, %d, %d", total_iterations, total_passes);
#ifdef STANDALONE_MULTILAT
exit(1);
#else
return -1;
#endif
}
#endif
void *multilat_thread_main(void *arg) {
ml_state_t *mls = (ml_state_t *) arg;
/* nice down */
nice(10);
do_multilat:
#ifndef STANDALONE_MULTILAT
/* wait for new data to appear */
pthread_mutex_lock(&(mls->range_snapshot_mutex));
while (!mls->master_mode || mls->latest_table == NULL) {
pthread_cond_wait(&(mls->range_snapshot_cond),
&(mls->range_snapshot_mutex));
}
int i;
multilat_range_t *mlr;
/* clear the last range set */
while ((mlr = range_list_pop(mls->multilat_lists))) {
free(mlr);
}
coord_guess_t *cgt;
while ((cgt = guess_list_pop(mls->multilat_lists))) {
free(cgt);
}
multilat_result_t *mrt;
while ((mrt = result_list_pop(mls->multilat_lists))) {
free(mrt);
}
mls->global_run = 0;
/* fill the new range set */
for (i = 0; i < mls->latest_table_count; ++i) {
mlr = g_new0(multilat_range_t, 1);
mlr->chirp_from = mls->latest_table[i].range_entry.source;
mlr->data_from = mls->latest_table[i].header.flow_id.src;
if (mlr->chirp_from == mlr->data_from ||
mlr->chirp_from == 0 || mlr->data_from == 0)
goto free_it;
/* from tenths of degrees to radians */
mlr->theta = (M_PI * (float) mls->latest_table[i].range_entry.theta) / 1800.0;
mlr->phi = (M_PI * (float) mls->latest_table[i].range_entry.phi) / 1800.0;
mlr->distance = mls->latest_table[i].range_entry.distance / 10.0;
if (mlr->distance == 0)
goto free_it;
#ifdef EMBEDDED_USECONF
mlr->angle_conf = mls->latest_table[i].range_entry.a_conf / 10.0;
mlr->conf = mls->latest_table[i].range_entry.conf / 10.0;
#else
mlr->angle_conf = 1;
mlr->conf = 10;
#endif
elog(LOG_WARNING, "Processing %d->%d, r=%f (cm) t=%f (%f) p=%f",
mlr->chirp_from, mlr->data_from, mlr->distance, mlr->theta, r2d(mlr->theta), mlr->phi);
range_list_push(mls->multilat_lists, mlr);
continue;
free_it:
free(mlr);
}
free(mls->latest_table);
mls->latest_table = NULL;
mls->latest_table_count = 0;
pthread_mutex_unlock(&(mls->range_snapshot_mutex));
#endif
elog(LOG_WARNING, "Other thread got new data, %d entries", range_list_qlen(mls->multilat_lists));
update_result_list(mls); /* add new nodes to the result list */
/* dump the current range table */
multilat_range_t *tmp;
elog(LOG_WARNING, "DUMPING RANGE TABLE:");
elog(LOG_WARNING, "src dst distance theta phi aconf conf state ur dr dt dp ur ut up us:");
for (tmp = range_list_top(mls->multilat_lists); tmp; tmp=range_list_next(tmp)) {
elog(LOG_WARNING, "%d %d %.1f %.2f %.2f %.1f %.1f %d %.1f %d %d %d %d %d %d %d",
tmp->chirp_from, tmp->data_from, tmp->distance, tmp->theta, tmp->phi,
tmp->angle_conf, tmp->conf, tmp->state, tmp->userange,
tmp->drop_r, tmp->drop_t, tmp->drop_p,
tmp->use_r, tmp->use_t, tmp->use_p, tmp->use_set);
}
initialize_guess_stage(mls);
if (!guess_coords(mls)) {
goto do_multilat;
}
buf_t *guessx = buf_new();
result_list_print(mls, guessx);
multilatbuf_to_file(mls, "step1", guessx);
buf_free(guessx);
#ifdef STANDALONE_MULTILAT
if (mls->addfuzz) {
add_fuzz_to_results(mls);
}
#endif
guessx = buf_new();
result_list_print(mls, guessx);
multilatbuf_to_file(mls, "step2", guessx);
buf_free(guessx);
#ifdef STANDALONE_MULTILAT
multilat_result_t *res = result_list_top(mls->multilat_lists);
mreal rms = 0;
int count = 0;
for ( ; res != NULL; res = result_list_next(res) ) {
if (res->state != RESULT_COORD_ROOT) {
rms += m_pow_2(res->x - res->real_x) +
m_pow_2(res->y - res->real_y) +
m_pow_2(res->z - res->real_z);
count++;
}
}
mls->guess_rms = sqrtf(rms / (count + 0.0));
#endif
/* note counts of nodes and ranges */
mls->result_element_count = result_list_qlen(mls->multilat_lists);
mls->range_element_count = range_list_qlen(mls->multilat_lists);
result_save(mls);
multilat_solver(mls);
#ifdef STANDALONE_MULTILAT
exit(1);
#endif
goto do_multilat;
}
void multilat_thread_init(ml_state_t *mls) {
/* setup mutex and cond */
pthread_mutex_init(&(mls->range_snapshot_mutex), NULL);
pthread_cond_init(&(mls->range_snapshot_cond), NULL);
/* spawn thread */
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
if (pthread_create(&(mls->multilat_thread), &thread_attr, multilat_thread_main, mls) < 0) {
elog(LOG_CRIT, "Failed to spawn compute thread: %m");
exit(1);
}
}
#ifdef STANDALONE_MULTILAT
int killpairs[3][20];
int killpairs_count = 0;
char *killpairs_file = NULL;
void read_killpairs()
{
FILE *f = fopen(killpairs_file, "r");
while (2 == fscanf(f, "%d %d", &(killpairs[0][killpairs_count]),
&(killpairs[1][killpairs_count]))) {
printf("read killpair %d %d\n",
killpairs[0][killpairs_count],
killpairs[1][killpairs_count]);
killpairs[2][killpairs_count] = (random()%100 < killpairs_prob*100);
killpairs_count++;
}
fclose(f);
}
/*
* for median finding
*/
struct sorter {
int index;
float value;
};
int sorter_cmp(const void *x, const void *y) {
return ((struct sorter *)x)->value - ((struct sorter *)y)->value;
}
int read_in_file(ml_state_t *mls)
{
if ((mls->fakedata = fopen(mls->filename, "r")) == NULL) {
elog(LOG_CRIT, "Unable to open file %s", mls->filename);
exit(1);
}
int res = 0;
int chirper = 0;
int listener = 0;
float distance = 0;
float theta = 0;
float phi = 0;
float temp = 0;
float real_distance = 0;
float real_theta = 0;
float real_phi = 0;
float real_x = 0;
float real_y = 0;
float real_z = 0;
float real_yaw = 0;
float conf = 10;
float aconf = 1;
char input[8192];
memset(&input, 0, 8192);
while (1) {
if (fgets(input,8192,mls->fakedata) == NULL) {
break;
}
if (input[0] == '#') {
continue;
}
if (mls->include_conf) {
res = sscanf(input, "%d %d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
&chirper, &listener, &distance, &theta, &phi,
&real_x, &real_y, &real_z, &temp, &temp, &temp, &temp,
&temp, &real_distance, &real_theta, &real_phi,
&conf, &aconf);
} else {
res = sscanf(input, "%d %d %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
&chirper, &listener, &distance, &theta, &phi,
&real_x, &real_y, &real_z, &temp, &temp, &temp, &temp,
&temp, &real_distance, &real_theta, &real_phi);
}
if (res == EOF) {
elog(LOG_WARNING, "End of input file %s", mls->filename);
break;
}
if (res != (mls->include_conf ? 18:16)) {
elog(LOG_WARNING, "error in file %s; status was %d", mls->filename, res);
continue;
}
multilat_range_t *mlr = g_new0(multilat_range_t, 1);
mlr->chirp_from = chirper;
mlr->data_from = listener;
if (mls->input_in_degrees) {
mlr->theta = theta/180.0*M_PI;
mlr->phi = phi/180.0*M_PI;
}
else {
mlr->theta = theta;
mlr->phi = phi;
}
mlr->distance = distance;
mlr->real_distance = real_distance;
mlr->real_theta = real_theta;
mlr->real_phi = real_phi;
mlr->introerr_distance = mlr->real_distance - mlr->distance;
mlr->introerr_theta = mlr->real_theta - mlr->theta;
mlr->introerr_phi = mlr->real_phi - mlr->phi;
mlr->conf = conf;
mlr->angle_conf = aconf;
int ll;
for (ll=0; ll<killpairs_count; ll++) {
if ((chirper == killpairs[0][ll] &&
listener == killpairs[1][ll]) ||
(chirper == killpairs[1][ll] &&
listener == killpairs[0][ll])) {
if (killpairs[2][ll]) {
/*
* used for simulating reflections.\
* you can set a list of pairs to remove in a file you
* pass in. then you can also specify specific
* ranges to cause to reflect.
* reflections add 10m and may or may not add a 45 degree
* angular error.
*/
int disterr = 1000;
int angleerr = 0 * (chirper == killpairs[1][ll] ? +1 : -1);
printf("offsetting %d,%d by %d cm, %d deg\n",
chirper, listener, disterr, angleerr);
mlr->distance += disterr;
mlr->theta += angleerr*M_PI/180.0;
}
else {
printf("nuking %d,%d\n",
chirper, listener);
mlr->conf = 0;
}
break;
}
}
if (mlr->conf == 0 || mlr->distance == 0) {
elog(LOG_WARNING, "skipping 0 range %d->%d",
mlr->chirp_from, mlr->data_from);
free(mlr);
goto skip;
}
range_list_push(mls->multilat_lists, mlr);
result_list_initnode(mls, listener);
result_list_initnode(mls, chirper);
multilat_result_t *mtr = result_list_get(mls, chirper);
mtr->real_x = real_x;
mtr->real_y = real_y;
mtr->real_z = real_z;
//mtr->nogt = 0; // get it from the map file!!
// update_result_list(mls); /* add new nodes to the result list */
skip:
elog(LOG_DEBUG(0), "read entry: %d %d %f %f %f", chirper, listener, theta, phi, distance);
}
fclose(mls->fakedata);
if (mls->gt_filename) {
FILE *f = fopen(mls->gt_filename, "r");
if (f == NULL) {
elog(LOG_WARNING, "unable to read gt from file %s", mls->gt_filename);
exit(1);
}
while (1) {
if (fgets(input,8192,f) == NULL) {
break;
}
if (input[0] == '#') {
continue;
}
int node;
res = sscanf(input, "%d %f %f %f %f",
&node, &real_x, &real_y, &real_z, &real_yaw);
if (res == EOF) {
elog(LOG_WARNING, "End of input file %s", mls->gt_filename);
break;
}
if (res != 5) {
elog(LOG_WARNING, "error in file %s", mls->filename);
continue;
}
result_list_initnode(mls, node);
multilat_result_t *mtr = result_list_get(mls, node);
mtr->real_x = real_x*100.0;
mtr->real_y = real_y*100.0;
mtr->real_z = real_z*100.0;
mtr->real_yaw = real_yaw;
mtr->nogt = 0;
elog(LOG_WARNING, "read %d %f %f %f",
node, real_x, real_y, real_z);
}
fclose(f);
}
/* prune duplicates, keep median phi angle */
multilat_range_t *ptr;
multilat_range_t *tmp;
for (ptr = range_list_top(mls->multilat_lists); ptr; ptr = tmp) {
multilat_range_t *ptr2;
multilat_range_t *tmp2;
multilat_stages_t lists;
memset(&lists, 0, sizeof(lists));
/* move dups into list */
for (ptr2 = range_list_next(ptr); ptr2; ptr2 = tmp2) {
tmp2 = range_list_next(ptr2);
if (ptr->chirp_from == ptr2->chirp_from &&
ptr->data_from == ptr2->data_from) {
range_list_remove(mls->multilat_lists, ptr2);
range_list_push(&lists, ptr2);
}
}
/* inc and move this one into list */
tmp = range_list_next(ptr);
range_list_remove(mls->multilat_lists, ptr);
range_list_push(&lists, ptr);
int r_count = range_list_qlen(&lists);
struct sorter s[r_count];
/* now process list */
int i;
int q[5] = {0,0,0,0,0};
for (i=0, ptr2 = range_list_top(&lists); ptr2; i++, ptr2 = range_list_next(ptr2)) {
s[i].index = i;
s[i].value = ptr2->theta;
if (s[i].value < 0)
s[i].value += (M_PI*2.0);
q[(int)(s[i].value/(M_PI/2.0))]++;
}
q[3] += q[4];
q[4] = 0;
int maxq;
int maxind=-1;
for (i=0; i<4; i++) {
int thisq = q[i] + q[(i+1)%4];
if (maxind < 0 || thisq > maxq) {
maxind = i;
maxq = thisq;
}
}
/* flip? */
if (maxind == 3) {
for (i=0; i<r_count; i++)
if (s[i].value > M_PI/2.0 && s[i].value < 3.0*M_PI/2.0)
s[i].index = -1;
else
if (s[i].value > M_PI)
s[i].value -= (2.0*M_PI);
}
else {
for (i=0; i<r_count; i++) {
int q_num = ((int)(s[i].value / (M_PI/2.0)));
if (q_num == 4) q_num = 3;
if (q_num != maxind && q_num != maxind+1)
s[i].index = -1;
}
}
/* filter stuff out of 2 quadrants */
int drops=0;
for (i=0; i<r_count; i++) {
if (s[i].index < 0) {
elog(LOG_WARNING, "dropping outlier value %f, for pair %d->%d",
s[i].value, ptr->chirp_from, ptr->data_from);
drops++;
}
else if (drops > 0) {
s[i-drops] = s[i];
}
}
r_count -= drops;
/* sort and keep median */
if (r_count > 0) {
qsort(&s, r_count, sizeof(struct sorter), sorter_cmp);
/* keep median */
int med_idx = s[r_count/2].index;
for (i=0, ptr2=range_list_top(&lists); i<med_idx;
i++, ptr2=range_list_next(ptr2));
range_list_remove(&lists, ptr2);
range_list_push_front(mls->multilat_lists, ptr2);
elog(LOG_WARNING, "keeping median: %d->%d %f %f %f",
ptr2->chirp_from, ptr2->data_from, ptr2->theta,
ptr2->phi, ptr2->distance);
}
/* free dups */
while ((ptr2 = range_list_pop(&lists))) free(ptr2);
}
return 0;
}
#define OUTPUTPREFIX "/tmp/"
int main(int argc, char **argv) {
ml_state_t mls = {
master_mode: 1
};
misc_init(&argc, argv, CVSTAG);
char *tempstr1;
char *tempstr2;
float studthresh = 0;
mls.filename = misc_parse_out_option(&argc, argv, "file", 'f');
if (mls.filename == NULL || strcmp(mls.filename, "") == 0) {
elog(LOG_CRIT, "Please input valid filename!");
exit(1);
}
char *kp;
if ((kp = misc_parse_out_option(&argc, argv, "kp", 0))) {
sscanf(kp, "%d,%d", &killpairs[0][0], &killpairs[1][0]);
killpairs[2][0] = 1;
killpairs_count = 1;
}
misc_parse_option_as_float(&argc, argv, "kprob", 0, &killpairs_prob);
killpairs_file = misc_parse_out_option(&argc, argv, "killpairs", 0);
if (killpairs_file)
read_killpairs(killpairs_file);
mls.gt_filename = misc_parse_out_option(&argc, argv, "gt", 0);
mls.outputprefix = misc_parse_out_option(&argc, argv, "outputprefix", 'p');
if (mls.outputprefix == NULL || strcmp(mls.outputprefix, "") == 0) {
elog (LOG_CRIT, "no output prefix set, setting to /tmp");
mls.outputprefix = OUTPUTPREFIX;
}
mls.noreject = misc_parse_out_switch(&argc, argv, "no_reject", 0);
mls.addfuzz = misc_parse_out_switch(&argc, argv, "fuzz", 'z');
mls.useangles = misc_parse_out_switch(&argc, argv, "useangle", 'a');
mls.input_in_degrees = misc_parse_out_switch(&argc, argv, "degrees", 0);
mls.include_conf = misc_parse_out_switch(&argc, argv, "useconf", 0);
if (misc_parse_option_as_float(&argc, argv, "studres", 's', &studthresh) != 0) {
studthresh = 0;
}
mls.studthresh = studthresh;
tempstr1 = misc_parse_out_option(&argc, argv, "one", '1');
if (tempstr1 != NULL) {
sscanf(tempstr1, "%i:%lf,%lf,%lf,%lf",
&mls.anode1, &mls.x1, &mls.y1, &mls.z1, &mls.a1);
mls.a1 = mls.a1/180.0*M_PI;
elog(LOG_WARNING, "fixed node %i at %f %f %f, angle %f",
mls.anode1, mls.x1, mls.y1, mls.z1, mls.a1);
}
tempstr2 = misc_parse_out_option(&argc, argv, "two", '2');
if (tempstr2 != NULL) {
sscanf(tempstr2, "%i:%lf,%lf,%lf,%lf",
&mls.anode2, &mls.x2, &mls.y2, &mls.z2,&mls.a2);
mls.a2 = mls.a2/180.0*M_PI;
elog(LOG_WARNING, "fixed node %i at %f %f %f angle %f",
mls.anode2, mls.x2, mls.y2, mls.z2, mls.a2);
}
mls.multilat_lists = g_new0(multilat_stages_t, 1);
range_list_init(mls.multilat_lists);
guess_list_init(mls.multilat_lists);
result_list_init(mls.multilat_lists);
read_in_file(&mls);
multilat_thread_main(&mls);
exit(1);
}
#endif
| CENS CVS Mailing List |
Powered by ViewCVS 0.9.2 |