From 2b2263a797c8efcdf2d350b4f90b6a2decb37274 Mon Sep 17 00:00:00 2001
From: Lewin Probst <info@emirror.de>
Date: Mon, 21 Oct 2019 09:37:05 +0200
Subject: [PATCH] Added ls_converge function to the vendor package.

---
 lib/+artoa/+vendor/ls_converge.m | 200 +++++++++++++++++++++++++++++++
 1 file changed, 200 insertions(+)
 create mode 100644 lib/+artoa/+vendor/ls_converge.m

diff --git a/lib/+artoa/+vendor/ls_converge.m b/lib/+artoa/+vendor/ls_converge.m
new file mode 100644
index 0000000..acaa6a5
--- /dev/null
+++ b/lib/+artoa/+vendor/ls_converge.m
@@ -0,0 +1,200 @@
+% 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;
+
-- 
GitLab