stupid_filter.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014 Swift Navigation Inc.
00003  * Contact: Ian Horn <ian@swift-nav.com>
00004  *
00005  * This source is subject to the license found in the file 'LICENSE' which must
00006  * be be distributed together with this source. All other rights reserved.
00007  *
00008  * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
00009  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
00010  * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
00011  */
00012 
00013 #include <math.h>
00014 #include <string.h>
00015 #include <cblas.h>
00016 #include <stdio.h>
00017 
00018 #include "constants.h"
00019 #include "stupid_filter.h"
00020 #include "amb_kf.h"
00021 #include "linear_algebra.h"
00022 
00023 #include <lapacke.h>
00024 
00054 void amb_from_baseline(u8 num_sats, double *DE, double *dd_meas,
00055                        double b[3], s32 *N)
00056 {
00057   double N_float[num_sats-1];
00058   /* Solve for ambiguity vector using the observation equation, i.e.
00059    *   N_float = dd_meas - DE . b / lambda
00060    * where N_float is a real valued vector */
00061 
00062   /* N_float <= dd_meas
00063    * alpha <= - 1.0 / GPS_L1_LAMBDA_NO_VAC
00064    * beta <= 1.0
00065    * N_float <= beta * N_float + alpha * (DE . b)
00066    */
00067   memcpy(N_float, dd_meas, (num_sats-1) * sizeof(double));
00068   cblas_dgemv(
00069     CblasRowMajor, CblasNoTrans, num_sats-1, 3,
00070     -1.0 / GPS_L1_LAMBDA_NO_VAC, DE, 3, b, 1,
00071     1.0, N_float, 1
00072   );
00073 
00074   /* Round the values of N_float to estimate the integer valued ambiguities. */
00075   for (u8 i=0; i<num_sats-1; i++) {
00076     N[i] = (s32)lround(N_float[i]);
00077   }
00078 }
00079 
00080 void init_stupid_filter(stupid_filter_state_t *s, u8 num_sats, sdiff_t *sdiffs,
00081                         double *dd_meas, double b[3], double ref_ecef[3])
00082 {
00083   double DE[(num_sats-1)*3];
00084 
00085   /* Calculate DE matrix */
00086   assign_de_mtx(num_sats, sdiffs, ref_ecef, DE);
00087 
00088   amb_from_baseline(num_sats, DE, dd_meas, b, s->N);
00089 }
00090 
00091 
00092 static void rebase_N(s32 *N, u8 num_sats, u8 *old_prns, u8 *new_prns)
00093 {
00094   u8 old_ref = old_prns[0];
00095   u8 new_ref = new_prns[0];
00096 
00097   s32 new_N[num_sats-1];
00098   s32 index_of_new_ref_in_old = find_index_of_element_in_u8s(num_sats, new_ref, &old_prns[1]);
00099   s32 val_for_new_ref_in_old_basis = N[index_of_new_ref_in_old];
00100   for (u8 i=0; i<num_sats-1; i++) {
00101     u8 new_prn = new_prns[1+i];
00102     if (new_prn == old_ref) {
00103       new_N[i] = - val_for_new_ref_in_old_basis;
00104     }
00105     else {
00106       s32 index_of_this_sat_in_old_basis = find_index_of_element_in_u8s(num_sats, new_prn, &old_prns[1]);
00107       new_N[i] = N[index_of_this_sat_in_old_basis] - val_for_new_ref_in_old_basis;
00108     }
00109   }
00110   memcpy(N, new_N, (num_sats-1) * sizeof(s32));
00111 }
00112 
00113 void rebase_stupid_filter(stupid_filter_state_t *s, u8 num_sats, u8 *old_prns, u8 *new_prns)
00114 {
00115   rebase_N(&(s->N[0]), num_sats, old_prns, new_prns);
00116 }
00117 
00118 //assumes both sets are ordered
00119 u8 intersect_o_tron(u8 num_sats1, u8 num_sats2, u8 *sats1, sdiff_t *sdiffs, double *dd_meas,
00120                   sdiff_t *intersection_sats, double *intersection_dd_meas,
00121                   s32* N, s32 *intersection_N)
00122 {
00123   u8 i, j, n = 0;
00124 
00125   /* Loop over sats1 and sdffs and check if a PRN is present in both. */
00126   for (i=0, j=0; i<num_sats1 && j<num_sats2; i++, j++) {
00127     if (sats1[i] < sdiffs[j].prn)
00128       j--;
00129     else if (sats1[i] > sdiffs[j].prn)
00130       i--;
00131     else {
00132       memcpy(&intersection_sats[n], &sdiffs[j], sizeof(sdiff_t));
00133       intersection_dd_meas[n] = dd_meas[j];
00134       intersection_N[n] = N[i];
00135       n++;
00136     }
00137   }
00138   return n;
00139 }
00140 
00141 void update_sats_stupid_filter(stupid_filter_state_t *s, u8 num_old, u8 *old_prns, u8 num_new,
00142                                sdiff_t *sdiffs, double *dd_meas, double ref_ecef[3])
00143 {
00144   // find intersection of old and new
00145 
00146   double intersection_dd_meas[num_new];
00147   sdiff_t intersection_sats[num_new];
00148   memcpy(&intersection_sats[0], &sdiffs[0], sizeof(sdiff_t));
00149   s32 intersection_N[MAX_CHANNELS];
00150   u8 n_intersection = intersect_o_tron(num_old-1, num_new-1, &old_prns[1], &sdiffs[1], dd_meas, &intersection_sats[1], intersection_dd_meas, s->N, intersection_N);
00151 
00152   if ((num_old-1) == (num_new-1) && (num_old-1) == n_intersection) {
00153     u8 flag = 0;
00154     for (u8 i=0; i<n_intersection+1; i++) {
00155       if (intersection_sats[i].prn != old_prns[i])
00156         flag = 1;
00157     }
00158     if (flag == 0)
00159       // No changes!
00160       return;
00161   }
00162 
00163   printf("====== UPDATE =======\n");
00164 
00165   // ok to overwite s->N because we are going to call init in a second anyway
00166   memcpy(&(s->N), intersection_N, n_intersection*sizeof(s32));
00167   // calc least sq. b from intersection sat using new data
00168   double b[3];
00169   update_stupid_filter(s, n_intersection, intersection_sats, intersection_dd_meas, b, ref_ecef);
00170 
00171   // call init with the new sat set and b as initial baseline
00172   init_stupid_filter(s, num_new, sdiffs, dd_meas, b, ref_ecef);
00173 }
00174 
00175 void lesq_solution(u8 num_dds, double *dd_meas, s32 *N, double *DE, double b[3], double *resid)
00176 {
00177   double DE_work[num_dds*3];
00178   memcpy(DE_work, DE, num_dds * 3 * sizeof(double));
00179 
00180   /* Solve for b via least squares, i.e.
00181    * dd_meas = DE . b + N
00182    *  =>  DE . b = (dd_meas - N) * lambda */
00183 
00184   /* min | A.x - b | wrt x
00185    * A <= DE
00186    * x <= b
00187    * b <= (dd_meas - N) * lambda
00188    */
00189   double rhs[MAX(num_dds, 3)];
00190   for (u8 i=0; i<num_dds; i++) {
00191     rhs[i] = (dd_meas[i] - N[i]) * GPS_L1_LAMBDA_NO_VAC;
00192   }
00193 
00194   int jpvt[3] = {0, 0, 0};
00195   int rank;
00196   /* TODO: This function calls malloc to allocate work area, refactor to use
00197    * LAPACKE_dgelsy_work instead. */
00198   LAPACKE_dgelsy(
00199     LAPACK_ROW_MAJOR, num_dds, 3,
00200     1, DE_work, 3,
00201     rhs, 1, jpvt,
00202     -1, &rank
00203   );
00204   memcpy(b, rhs, 3*sizeof(double));
00205 
00206   if (resid) {
00207     /* Calculate Least Squares Residuals */
00208 
00209     memcpy(DE_work, DE, num_dds * 3 * sizeof(double));
00210 
00211     /* resid <= dd_meas - N
00212      * alpha <= - 1.0 / GPS_L1_LAMBDA_NO_VAC
00213      * beta <= 1.0
00214      * resid <= beta * resid + alpha * (DE . b)
00215      */
00216     for (u8 i=0; i<num_dds; i++) {
00217       resid[i] = dd_meas[i] - N[i];
00218     }
00219     cblas_dgemv(
00220       CblasRowMajor, CblasNoTrans, num_dds, 3,
00221       -1.0 / GPS_L1_LAMBDA_NO_VAC, DE_work, 3, b, 1,
00222       1.0, resid, 1
00223     );
00224   }
00225 }
00226 
00227 
00228 
00229 void update_stupid_filter(stupid_filter_state_t *s, u8 num_sats, sdiff_t *sdiffs,
00230                         double *dd_meas, double b[3], double ref_ecef[3])
00231 {
00232   double DE[(num_sats-1)*3];
00233 
00234   /* Calculate DE matrix */
00235   assign_de_mtx(num_sats, sdiffs, ref_ecef, DE);
00236   lesq_solution(num_sats-1, dd_meas, s->N, DE, b, 0);
00237 
00238 }
00239 
00240 
00241 
00242 
00243 
00244 
00245 
00246 
00247 
00248 
00249 


swiftnav
Author(s):
autogenerated on Sat Jun 8 2019 18:56:15