Skip to content
Snippets Groups Projects
ls_converge.m 6.26 KiB
% ls_converge   Tracking with the least squares procedure.
%
% SYNOPSIS:
%   function [x_new] = ls_converge (xgu, nals, sspos, dist, sv)
%
% DESCRIPTION:  Return the [latitude longitude] (radians) of a position
%               based on the least squares tracking method.
%
% ARGUMENTS:  
%   xgu   is the guess at the position, usually the previous position.
%         Stored as [lat lon] degrees.
%         If the drift is to be computed it is stored as the third
%         element of the vector, xgu(3).
%
%   nals  is the number of sound sources.
%  
%   sspos  is the sound source positions corresponding to distances.
% 
%   dist  is distance to sound source, km.
%
%   sv    is the sound velocity (km/sec) as determined from the current
%         temperature.
%
% Code by Roger Goldsmith, WHOI
% kindly provided by Heather D. Hunt, WHOI
%

function [x_new] =  ls_converge (xgu, nals, sspos, dist, sv)

RAD = 180/pi;
KM_PER_DEG = 111.324;
mtry = 30;
rate = sv;

% fprintf ('LS1 %10.4f %10.4f\n', dist(1)/sv, dist(2)/sv);
% fprintf ('LS2 %10.4f %10.4f %10.4f\n', dist(1)/sv, dist(2)/sv, dist(3)/sv);
drft_init = 0.0;
drft = 0.0;
do_time = 0;
oldpos(1:2) = xgu(1:2);
%oldpos(2) = xgu(2);
if (length (xgu) > 2)
  do_time = 1;
  drft_init = xgu(3);
  drft = drft_init;
end  % if
%
xpos = xgu/RAD;%    convert 'oldpos' (degrees) to 'xpos' (radians).

itry = 0;   % start value for number of iterations performed.

cradius = 100.0;   % the start value for the convergence radius
while cradius > 0.05
  alpha_beta = 0.0;
  alpha_sqd = 0.0;
  alpha_tau = 0.0;
  beta_sqd = 0.0;
  beta_tau = 0.0;
  sum_alpha = 0.0;
  sum_beta = 0.0;
  sum_tau = 0.0;
  
% Loop through the sources collecting terms. Throw out the source if zero.
  nals_act = 0;
  for i = 1:nals
    %if (dist(i) >= 0)     % NOT A GOOD TEST, LOOK FOR TIME = 0
    if (~isnan(dist(i)))  % Is this a better approach?
%    		Get the distance from last position to source.
%    		Contrary to the documentation in ELLIPK2, the bearing 	is returned in degrees.
    		sosopos = [sspos(i,1)  sspos(i,2)];
    		[db(1), db(2)] = artoa.data.calculateEllipk2 (xpos, sosopos/RAD);
    		dst = db(1);
    		beta  = cos (db(2)/RAD )/rate;
    		alpha = sin (db(2)/RAD )/rate;
    		tau = (dist(i) - dst)/rate - drft_init + drft;
%   		fprintf ('TAU: %3d %2d %8.2f %8.2f %8.2f %8.2f %8.2f\n', itry,i,dist(i),dst,drft_init,drft,tau);
    		alpha_beta = alpha_beta + alpha*beta;
    		alpha_sqd = alpha_sqd + alpha*alpha;
    		alpha_tau = alpha_tau + alpha*tau;
    		beta_sqd = beta_sqd + beta*beta;
    		beta_tau = beta_tau + beta*tau;
%    		fprintf ('LS3   %d %7.2f %7.2f %7.2f %6.2f\n', i, dist(i), dst, tau, db(2) );
    		if (do_time == 1)
       		sum_alpha = sum_alpha + alpha;
     			sum_beta = sum_beta + beta;
     	  		sum_tau = sum_tau + tau;
    		end  % if
    		nals_act = nals_act + 1;  % the actual number of available sosos.
  	  end  % if distance was greater zero
  end  % for i = loop over all sources
  if (itry == 0  &  nals_act ~= nals) 
    if (nals_act < 2) % less than two sources available
      fprintf (' *** NOT ENOUGHT VALID POINTS.\n');
      x_new = NaN*size (oldpos);
      return;
    end  % if
  end  % if
  
%    Set the test criteria to one degree.
  stest = sin (1.0/RAD) * nals_act/rate;
  stest = stest*stest;
  
% 
%        Compute corrections.
  alpha_sqd = alpha_sqd - sum_alpha*sum_alpha/nals_act;
  alpha_beta = alpha_beta - sum_alpha*sum_beta/nals_act;
  alpha_tau = alpha_tau - sum_alpha*sum_tau/nals_act;
  beta_sqd = beta_sqd - sum_beta*sum_beta/nals_act;
  beta_tau = beta_tau - sum_beta*sum_tau/nals_act;
  denom = alpha_sqd*beta_sqd - alpha_beta*alpha_beta;
  
  if (denom == 0)
    denom = stest;
    end  % if
  if (abs (denom) < stest)
    denom = sign (denom)*stest;
    end  % if
  
  xx = (alpha_tau*beta_sqd - alpha_beta*beta_tau)/denom;
  yy = (alpha_sqd*beta_tau - alpha_beta*alpha_tau)/denom;
  
%        Update guess then test radius for threshold.
  cradius = xx*xx + yy*yy;
  if (do_time == 1)
    drft_corr = (-sum_tau + xx*sum_alpha + yy*sum_beta)/nals_act;
    cradius = cradius + (drft_corr*rate).^2;
    drft = drft + drft_corr;
    end  % if
% fprintf ('LS4 %3d %10.2f %10.4f%10.6f %10.3f%10.5f %10.2f%10.4f\n', itry, -sum_tau, xx, sum_alpha, yy, sum_beta, drft_corr, drft );
  
  if (cradius > 0) 
    cradius = sqrt (cradius);
   else
    cradius = 0.0;
   end  % if
  
  bear = atan2 (xx, yy);
  t1p = sin (oldpos(1)/RAD) * cos (cradius/KM_PER_DEG/RAD) + ...
       cos (oldpos(1)/RAD) * sin (cradius/KM_PER_DEG/RAD) * ...
       cos (bear);
  t1 = cos ((90.0-oldpos(1))/RAD) * cos (cradius/KM_PER_DEG/RAD) + ...
       sin ((90.0-oldpos(1))/RAD) * sin (cradius/KM_PER_DEG/RAD) * ...
       cos (bear);
  t1_rad = acos (t1);
  t1p_rad = acos (t1p);
  t1_deg = 90.0 - t1_rad*RAD;
  t1p_deg = 90.0 - t1p_rad*RAD;
  t2 = sin (cradius/KM_PER_DEG/RAD) * sin (bear) / sin (t1_rad);
  t2p = sin (cradius/KM_PER_DEG/RAD) * sin (bear) / sin (t1_rad);
  if (abs (t2) > 1.0) 
    t2 = sign (t2);
    end  % if
  if (abs (t2p) > 1.0) 
    t2p = sign (t2p);
    end  % if
  t2_rad = asin (t2) + oldpos(2)/RAD;
  t2p_rad = asin (t2p) + oldpos(2)/RAD;
  t2_deg = t2_rad*RAD;
  t2p_deg = t2p_rad*RAD;
  xpos = [t1_deg/RAD  t2_rad];
  xposp = [t1p_deg/RAD  t2p_rad];
% fprintf ('LS5 %3d %5.3f  %6.2f %6.2f  %6.2f %6.1f  %8.4f %9.4f\n', itry, denom, xx, yy, cradius, bear*RAD, xpos(2)*RAD, xpos(1)*RAD)
                                             
  itry = itry + 1;
  if (itry > mtry)
    fprintf (' *** NO CONVERGENCE AFTER %d ITERATIONS.\n', mtry);
    x_new = NaN*size (oldpos);
    return;
    end  % if
  
  oldpos = xpos*RAD;
  %oldpos(2) = xpos(2)*RAD;
  oldposp = xposp*RAD;
  %oldposp(2) = xposp(2)*RAD;
  oldpos = xposp*RAD;
  %oldpos(2) = xposp(2)*RAD;
  
end   % while cradius
  
x_new = xpos;
if (do_time == 1)
  x_new(3) = drft;
end  % if
%fprintf ('   #S%2d ', nals_act);
%fprintf('ls-');

clear  alpha  alpha_beta  alpha_sqd  alpha_tau;
clear  beta  beta_sqd  beta_tau  
clear  cradius;
clear  db  denom  dst;
clear  i  itry;
clear  rate;
clear  ssq  stest;
clear  sosopos;
clear  sum_alpha  sum_beta  sum_tau;
clear  t1  t1_rad  t1_deg;
clear  tau;
clear  xpos  oldpos;
clear  xx  yy;