Skip to content
Snippets Groups Projects
SingleSource.m 5.31 KiB
Newer Older
function [positions, clockError] = SingleSource(pData, pSoundsourcePositions, pCombinationDetails, pStartEndPosition)
%SINGLESOURCE Estimates the trajectory by using only one soundsource.
%
%   Parameters:
%       pData (struct):
%           Data structured by soundsource. The toa is already corrected
%           (e.g. doppler correction etc.)
%       pSoundsourcePositions (struct):
%           The soundsource positions [deg].
%       pCombinationDetails (table):
%           Contains all information of the current soundsource
%           combination.
%       pStartEndPosition (double, logical):
%           Set to false if it has not been passed by artoa. Contains the
%           desired start and end position as a matrix of row vectors.
%
%
%   Returns:
%       positions (double):
%           The calculated list of segment positions as a X x 2 column vector.
%       clockError (double):
%           The estimated clock error.


%% Check input
leprob001's avatar
leprob001 committed
referencePositionStart = cellfun( ...
    @str2double, ...
    strsplit(pCombinationDetails.referencePosition{1}) ...
    );
referencePositionEnd = cellfun( ...
    @str2double, ...
    strsplit(pCombinationDetails.referencePositionEnd{1}) ...
    );

if any(isnan(referencePositionStart)) || any(isnan(referencePositionEnd))
    error([mfilename ': SingleSource algorithm requires BOTH (Reference) Positions to be set!']);
end

%% Get required data
leprob001's avatar
leprob001 committed
% use only the first soundsource, even if there are more available
soundsourceName = strsplit(pCombinationDetails.soundsources{1});
soundsourceName = soundsourceName{1};

%% Prepare data for calculations
% get a date vector (does not matter which one)
dates = cell2mat(pData.(soundsourceName).date);
distances = cell2mat(pData.(soundsourceName).distance);
soundsourcePosition = pSoundsourcePositions.(soundsourceName);

% initialize return variables
positions = [ ...
    referencePositionStart; ...
    ];
leprob001's avatar
leprob001 committed
%endPosition = str2num(pCombinationDetails.referencePositionEnd{:});
%clockError = [];

%% Algorithm
dateLength = length(dates);  % number of points to calculate trajectory for
leprob001's avatar
leprob001 committed
% time between position fixes   %!!!  needs generalization accordind to float's RAFOS schedule
timeStep = diff(dates(1:2)) * 86400;
averageHorizontalVelocity = ( ...
    distance(str2num(pCombinationDetails.referencePositionEnd{:}), ...
    str2num(pCombinationDetails.referencePosition{:})) * 60 * 1852) ...
    / ( ...
        (pCombinationDetails.combinationEnd - pCombinationDetails.combinationBegin) ...
        * 86400 ...
    );   % in meter per second

% calculate main loop values
maxJ = length(averageHorizontalVelocity:.05:5 * averageHorizontalVelocity);
j = 0;
% initialize container for calculated positions
positions_calculated(1:maxJ,:,1:2) = NaN*ones(maxJ,dateLength,2);

for horizontalVelocity = averageHorizontalVelocity:.05:5 * averageHorizontalVelocity
    j = j + 1;

    for i = 1:dateLength
leprob001's avatar
leprob001 committed
        % get current distance [km] according to current toa
        currentDistance = distances(i);

        if i == 1
            lastFloatPosition(1) = referencePositionStart(1);
            lastFloatPosition(2) = referencePositionStart(2);
leprob001's avatar
leprob001 committed
            [~, oldbearing] = distance( ...
                referencePositionStart(1), ...
                referencePositionStart(2), ...
                referencePositionEnd(1), ...
                referencePositionEnd(2) ...
                );
leprob001's avatar
leprob001 committed

        [lat, lon] = scxsc( ...
            soundsourcePosition(1), ...
            soundsourcePosition(2), ...
            km2deg(currentDistance), ...
            lastFloatPosition(1), ...
            lastFloatPosition(2), ...
leprob001's avatar
leprob001 committed
            km2deg(horizontalVelocity * timeStep / 1000) ...
            );
         %% So we have usually 2 solution, which one to select? --> the one closer towards the final point
         
         [helper, newbearing] = distance( ...
             lastFloatPosition(1), ...
             lastFloatPosition(2), ...
             lat, ...
             lon ...
             );
         %! besser: der punkt der sich auf der Verbindungsachse zwischen
         % A und B in Richtung B bewegt
leprob001's avatar
leprob001 committed
        if ~isnan(helper(1)) %  intersection found
            helper = abs(newbearing - oldbearing);
            helperindi = find(helper == min(helper));
            oldbearing = newbearing(helperindi);

            lastFloatPosition(1) = lat(helperindi);
            lastFloatPosition(2) = lon(helperindi);
leprob001's avatar
leprob001 committed
            positions_calculated(j,i,1) = lastFloatPosition(1);
            positions_calculated(j,i,2) = lastFloatPosition(2);
        else
            break;
leprob001's avatar
leprob001 committed
validdata = find(~isnan(positions_calculated(:, end, 1)));
helper = distance( ...
    referencePositionEnd(1), ...
    referencePositionEnd(2), ...
    positions_calculated(validdata, end, 1), ...
    positions_calculated(validdata, end, 2) ...
    );
jindi = find(helper == min(helper));

positions(1:dateLength, 1) = positions_calculated(validdata(jindi), :, 1)';
positions(1:dateLength, 2) = positions_calculated(validdata(jindi), :, 2)';

% ich vermute mal das dies der Unterschied gemessene toa zu der
% "von der errechneten Position abgeleiteten toa".   der ist null da wir
% ihn of 0 zwingen.
clockError = zeros(length(positions_calculated), 1);