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;