diff --git a/VERSION b/VERSION
index d25720879e9d5b2c8db60c8e908af0c01017e831..95c8a676e9d535b85485c6a8d1ee1991c9391ad0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-112
\ No newline at end of file
+113
\ No newline at end of file
diff --git a/lib/+artoa/+controller/+edit/+offsets/buttonCalculateOffsets.m b/lib/+artoa/+controller/+edit/+offsets/buttonCalculateOffsets.m
index b7a8c59d8e453a1cf713ef2d89e486b81ca329bd..1d4102e88370acdc9a4aee1f8d15769b210de4f3 100644
--- a/lib/+artoa/+controller/+edit/+offsets/buttonCalculateOffsets.m
+++ b/lib/+artoa/+controller/+edit/+offsets/buttonCalculateOffsets.m
@@ -13,7 +13,9 @@ satData = artoaWorkspace.satData;
 [
     artoaWorkspace.editOffsets.calculatedMatrixA, ...
     artoaWorkspace.editOffsets.calculatedMatrixB, ...
-    artoaWorkspace.editOffsets.calculatedMatrixX ...
+    artoaWorkspace.editOffsets.calculatedMatrixX, ...
+    ~, ...
+    ~ ...
 ] = artoa.offsets.solve( ...
     artoaDataInput.rfb, ...
     soundsources, ...
@@ -28,20 +30,22 @@ satData = artoaWorkspace.satData;
 %% Store offsets in table
 [offsets, drifts] = artoa.offsets.extractOffsetsDriftsFromSolved(artoaWorkspace.editOffsets.calculatedMatrixX);
 
-soundsourceNames = fieldnames(soundsources);
+soundsourceNames = fieldnames(artoa.controller.getSoundsourcesWithAppliedToa());
 for o = 1:length(soundsourceNames)
     if ~any(contains(artoaWorkspace.editOffsets.soundsourceOffsets.Properties.RowNames, soundsourceNames{o}))
         continue;
     end
-    artoaWorkspace.editOffsets.soundsourceOffsets{soundsourceNames{o}, 'OptimumTotalOffset'} = offsets(o);
-    artoaWorkspace.editOffsets.soundsourceOffsets{soundsourceNames{o}, 'OptimumTotalDrift'} = drifts(o);
+    artoaWorkspace.editOffsets.soundsourceOffsets{soundsourceNames{o}, 'OptimumTotalOffset'} = offsets(o + 1);
+    artoaWorkspace.editOffsets.soundsourceOffsets{soundsourceNames{o}, 'OptimumTotalDrift'} = drifts(o + 1);
 end
 
-artoa.controller.edit.offsets.tableSoundsourceOffsetsEdit();
+% store float in table
+artoaWorkspace.editOffsets.soundsourceOffsets{'Float', 'OptimumTotalOffset'} = offsets(1);
+artoaWorkspace.editOffsets.soundsourceOffsets{'Float', 'OptimumTotalDrift'} = drifts(1);
 
+%% Recalculate
+artoa.controller.edit.recalculateToaGpsAndPlot();
 
 
-artoa.controller.edit.timeOfArrival.plot();
-
 end
 
diff --git a/lib/+artoa/+controller/+edit/+offsets/checkboxUseOffsets.m b/lib/+artoa/+controller/+edit/+offsets/checkboxUseOffsets.m
index f040e604a61143fcffba938510087e0583c9ad05..245fab93cd334b597fc69bb52f3a478a2239f18a 100644
--- a/lib/+artoa/+controller/+edit/+offsets/checkboxUseOffsets.m
+++ b/lib/+artoa/+controller/+edit/+offsets/checkboxUseOffsets.m
@@ -2,33 +2,14 @@ function [newValue] = checkboxUseOffsets(~, ~)
 %CHECKBOXDOPPLERCORRECTION Summary of this function goes here
 %   Detailed explanation goes here
 
-global artoaGui artoaWorkspace artoaDataInput;
+global artoaGui artoaWorkspace;
 
 newValue = logical(artoaGui.editOffsets.checkboxUseOffsets.Value);
 
 artoaWorkspace.editOffsets.useOffsets = newValue;
 
-%% Update TOA
-
-% combine initial toa and current applied soundsources
-toaData = artoaWorkspace.toaData;
-toaData.toa = artoaDataInput.toaData.toa;
-
-%% Recalculate drift
-artoa.controller.edit.offsets.updateWorkspaceOffsetsTable();
-artoa.controller.edit.offsets.updateGui();
-
-%% Select offset and drift from the table
-artoa.controller.edit.offsets.selectOffsetsAndDrift();
-
-artoaWorkspace.toaData = artoa.toa.recalculate( ...
-    artoaWorkspace.float, ...
-    toaData, ...
-    artoaWorkspace.editOffsets.selectedOffsets ...
-);
-
-artoa.controller.edit.timeOfArrival.plot();
-
+%% Recalculate
+artoa.controller.edit.recalculateToaGpsAndPlot();
 
 end
 
diff --git a/lib/+artoa/+controller/+edit/+offsets/selectOffsetsAndDrift.m b/lib/+artoa/+controller/+edit/+offsets/selectOffsetsAndDrift.m
deleted file mode 100644
index 63c93298fc5d11ee8ca81f070861fe0c3f77f8b2..0000000000000000000000000000000000000000
--- a/lib/+artoa/+controller/+edit/+offsets/selectOffsetsAndDrift.m
+++ /dev/null
@@ -1,69 +0,0 @@
-function [] = selectOffsetsAndDrift()
-%SELECTOFFSETSANDDRIFT Summary of this function goes here
-%   Detailed explanation goes here
-
-global artoaWorkspace;
-
-%% Initialize required variables
-selectedOffsets = table();
-
-%% Get required variables
-offsetsTable = artoaWorkspace.editOffsets.soundsourceOffsets;
-
-%% Select float offset and drift
-if artoaWorkspace.editOffsets.useOffsets
-    tmp = table();
-    tmp.offset = offsetsTable{'Float', 'OptimumTotalOffset'};
-    tmp.drift = offsetsTable{'Float', 'OptimumTotalDrift'};
-    selectedOffsets('Float', :) = tmp;
-    clear tmp;
-else
-    selectedOffsets('Float', :) = selectFromRow(offsetsTable('Float', :));
-end
-
-%% Run through all soundsources
-variableNames = offsetsTable.Properties.RowNames;
-for i = 1:length(variableNames)
-    if strcmp('Float', variableNames{i})
-        continue;
-    end
-    if artoaWorkspace.editOffsets.useOffsets
-        tmp = table();
-        tmp.offset = offsetsTable{variableNames{i}, 'OptimumTotalOffset'};
-        tmp.drift = offsetsTable{variableNames{i}, 'OptimumTotalDrift'};
-        selectedOffsets(variableNames{i}, :) = tmp;
-        clear tmp;
-    else
-        selectedOffsets(variableNames{i}, :) = selectFromRow(offsetsTable(variableNames{i}, :));
-    end
-end
-
-%% Store selected values
-artoaWorkspace.editOffsets.selectedOffsets = selectedOffsets;
-
-    function [selected] = selectFromRow(pTableRow)
-        % offset
-        offset = 0;
-        if ~isnan(pTableRow.EmpiricalOffset)
-            offset = pTableRow.EmpiricalOffset;
-        elseif ~isnan(pTableRow.OffsetStart)
-            offset = pTableRow.OffsetStart;
-        elseif ~isnan(pTableRow.OptimumTotalOffset)
-            offset = pTableRow.OptimumTotalOffset;
-        end
-        % drift
-        drift = 0;
-        if ~isnan(pTableRow.EmpiricalDrift)
-            drift = pTableRow.EmpiricalDrift;
-        elseif ~isnan(pTableRow.Drift)
-            drift = pTableRow.Drift;
-        elseif ~isnan(pTableRow.OptimumTotalDrift)
-            drift = pTableRow.OptimumTotalDrift;
-        end
-        selected = table();
-        selected.offset = offset;
-        selected.drift = drift;
-    end
-
-end
-
diff --git a/lib/+artoa/+controller/+edit/+offsets/tableSoundsourceOffsetsEdit.m b/lib/+artoa/+controller/+edit/+offsets/tableSoundsourceOffsetsEdit.m
index e27bfec559d9f1652c53919f7a97dbc1714101dd..00cc304281ee02301035006817933cfea26fa4e1 100644
--- a/lib/+artoa/+controller/+edit/+offsets/tableSoundsourceOffsetsEdit.m
+++ b/lib/+artoa/+controller/+edit/+offsets/tableSoundsourceOffsetsEdit.m
@@ -3,15 +3,15 @@ function [] = tableSoundsourceOffsetsEdit(~, event)
 %   Detailed explanation goes here
 
 
-global artoaGui artoaWorkspace artoaDataInput;
+global artoaGui artoaWorkspace;
 
 %% Get data
 try
     selectedColumn = event.Indices(2);
+    %selectedRow = event.Indices(:, 1);
 catch
     selectedColumn = NaN;
-    artoa.controller.edit.offsets.updateGui();
-    return;
+    %return;
 end
 
 %% Check if the column that has been edited is locked
@@ -27,28 +27,10 @@ end
 %% Save to workspace
 artoaWorkspace.editOffsets.soundsourceOffsets(:, :) = artoaGui.editOffsets.tableSoundsourceOffsets.Data;
 
-%% Recalculate drift
+%% Update workspace (required because this function is call by time of arrival window)
 artoa.controller.edit.offsets.updateWorkspaceOffsetsTable();
 
-%% Select offset and drift from the table
-artoa.controller.edit.offsets.selectOffsetsAndDrift();
-% combine initial toa and current applied soundsources
-toaData = artoaWorkspace.toaData;
-toaData.toa = artoaDataInput.toaData.toa;
-
-artoaWorkspace.toaData = artoa.toa.recalculate( ...
-    artoaWorkspace.float, ...
-    toaData, ...
-    artoaWorkspace.editOffsets.selectedOffsets ...
-);
-
-%% Calculate GPS TOAs
-artoa.controller.edit.timeOfArrival.calculateGpsToas();
-
-%% Update GUI
-artoa.controller.edit.offsets.updateGui();
-
-%% Replot TOA window
-artoa.controller.edit.timeOfArrival.plot();
+%% Recalculate
+artoa.controller.edit.recalculateToaGpsAndPlot();
 
 end
diff --git a/lib/+artoa/+controller/+edit/+offsets/updateGui.m b/lib/+artoa/+controller/+edit/+offsets/updateGui.m
index f81d42f4fc4880bcf8ea54c57b213f86d194fede..a20d116d0482471a82128b2a1ff9a0dac1757594 100644
--- a/lib/+artoa/+controller/+edit/+offsets/updateGui.m
+++ b/lib/+artoa/+controller/+edit/+offsets/updateGui.m
@@ -17,7 +17,7 @@ for i = 1:length(fieldNames)
     currentValue = fields.(fieldNames{i});
     switch fieldNames{i}
         case 'useOffsets'
-            artoaGui.editOffsets.checkboxForceOptimumOffsets.Value = currentValue;
+            artoaGui.editOffsets.checkboxUseOffsets.Value = currentValue;
         case 'soundsourceOffsets'
             artoaGui.editOffsets.tableSoundsourceOffsets.Data = table2cell( ...
                 currentValue ...
diff --git a/lib/+artoa/+controller/+edit/+timeOfArrival/calculateGpsToas.m b/lib/+artoa/+controller/+edit/+timeOfArrival/calculateGpsToas.m
index b3d78a53150cc7d94ddf701ac6063a35e8692c58..eb49b7cd9b7b56d183d911f8e6e1a164216e2612 100644
--- a/lib/+artoa/+controller/+edit/+timeOfArrival/calculateGpsToas.m
+++ b/lib/+artoa/+controller/+edit/+timeOfArrival/calculateGpsToas.m
@@ -34,10 +34,11 @@ for o = 1:length(fnames)
     );
 
     % add soundsource drift
-    if artoa.data.hasMember(artoaWorkspace, {'editOffsets', 'selectedOffsets'}) ...
-            && any(contains(artoaWorkspace.editOffsets.selectedOffsets.Properties.RowNames, fnames{o}))
-        offset = artoaWorkspace.editOffsets.selectedOffsets{fnames{o}, 'offset'};
-        drift = artoaWorkspace.editOffsets.selectedOffsets{fnames{o}, 'drift'};
+    if artoa.data.hasMember(artoaWorkspace, {'editOffsets', 'soundsourceOffsets'}) ...
+            && any(contains(artoaWorkspace.editOffsets.soundsourceOffsets.Properties.RowNames, fnames{o})) ...
+            && artoaWorkspace.editOffsets.useOffsets
+        offset = artoaWorkspace.editOffsets.soundsourceOffsets{fnames{o}, 'EmpiricalOffset'};
+        drift = artoaWorkspace.editOffsets.soundsourceOffsets{fnames{o}, 'EmpiricalDrift'};
         % no sorting required, because fourth parameter contains timesteps
         predictedToas = artoa.toa.addDrift( ...
             predictedToas, ...
diff --git a/lib/+artoa/+controller/+edit/recalculateToaGpsAndPlot.m b/lib/+artoa/+controller/+edit/recalculateToaGpsAndPlot.m
new file mode 100644
index 0000000000000000000000000000000000000000..9dacd578e97be3ddabd470b733fef04a2bab20ca
--- /dev/null
+++ b/lib/+artoa/+controller/+edit/recalculateToaGpsAndPlot.m
@@ -0,0 +1,33 @@
+function [] = recalculateToaGpsAndPlot()
+%RECALCULATETOAGPSANDPLOT Summary of this function goes here
+%   Detailed explanation goes here
+
+global artoaWorkspace artoaDataInput;
+
+%% Recalculate TOAs
+
+% combine initial toa and current applied soundsources
+toaData = artoaWorkspace.toaData;
+toaData.toa = artoaDataInput.toaData.toa;
+
+if artoaWorkspace.editOffsets.useOffsets
+    artoaWorkspace.toaData = artoa.toa.recalculate( ...
+        artoaWorkspace.float, ...
+        toaData, ...
+        artoaWorkspace.editOffsets.soundsourceOffsets ...
+    );
+else
+    artoaWorkspace.toaData = toaData;
+end
+
+%% Calculate GPS TOAs
+artoa.controller.edit.timeOfArrival.calculateGpsToas();
+
+%% Update Offsets GUI
+artoa.controller.edit.offsets.updateGui();
+
+%% Replot all windows
+artoa.controller.edit.updateAvailablePlots();
+
+end
+
diff --git a/lib/+artoa/+controller/+track/run.m b/lib/+artoa/+controller/+track/run.m
index 75c5de06c6f47f3ef80d2c0d4d9423d99b19f458..d72f4741a45783535efade5f5f4bcdf4d00d04fd 100644
--- a/lib/+artoa/+controller/+track/run.m
+++ b/lib/+artoa/+controller/+track/run.m
@@ -63,6 +63,10 @@ pressureAndDate = { ...
     artoaWorkspace.rafosDate(artoaWorkspace.statusPressure == 1) ...
 };
 
+% restore initial toa, because it is required by the calculate function
+toaData = artoaWorkspace.toaData;
+toaData.toa = artoaDataInput.toaData.toa;
+
 [ ...
     trajectory, ...
     trajectoryDates, ...
@@ -74,9 +78,10 @@ pressureAndDate = { ...
     artoaWorkspace.float, ...
     pressureAndDate, ...
     artoaWorkspace.satData, ...
-    artoaWorkspace.toaData, ...
+    toaData, ...
     artoaWorkspace.filteredSoundsources, ...
     artoaWorkspace.trackParameter, ...
+    artoaWorkspace.editOffsets, ...
     soundVelocity, ...
     artoaDataInput.ini.leapseconds ...
 );
diff --git a/lib/+artoa/+offsets/createCalculationMatrices.m b/lib/+artoa/+offsets/createCalculationMatrices.m
new file mode 100644
index 0000000000000000000000000000000000000000..b8a62a0ceeba29a392bc7f11c9c4aef60cfa5898
--- /dev/null
+++ b/lib/+artoa/+offsets/createCalculationMatrices.m
@@ -0,0 +1,132 @@
+function [a, b] = createCalculationMatrices(pRfb, pSoundsources, pTrackingParameter, pToaData, pSatData, pAppliedTemperature, pAppliedPressure, pLeapsecondsMatrix)
+%CREATECALCULATIONMATRICES Summary of this function goes here
+%   Detailed explanation goes here
+
+%% Initialize required variables
+%pSoundsources = artoa.controller.getSoundsourcesWithAppliedToa();
+satPositions = [pSatData.lat_sat, pSatData.lon_sat];
+satDates = artoa.convert.dmy2rd(pSatData.day_sat, pSatData.month_sat, pSatData.year_sat);
+toaDates = [];
+satToas = [];
+satDistances = [];
+floatDetails = pRfb.FLOAT;
+
+%% Create table
+results = struct();
+
+%% Calculate SAT TOAs for every soundsource and get nearest neighbor measured toa
+fnames = fieldnames(pSoundsources);
+for i = 1:length(fnames)
+    results.(fnames{i}) = table();
+    [date, toa] = artoa.toa.predictFromGps( ...
+        pRfb, ...
+        pSoundsources.(fnames{i}), ...
+        struct( ...
+            'temperature', pAppliedTemperature, ...
+            'pressure', pAppliedPressure, ...
+            'method', pTrackingParameter.soundspeedMethodString, ...
+            'soundSource', NaN ...
+        ), ...
+        pLeapsecondsMatrix ...
+    );
+    results.(fnames{i}).satDate = date;
+    results.(fnames{i}).satToa = toa;
+    results.(fnames{i}).daysSinceStart = ...
+        date ...
+        - artoa.convert.dmy2rd( ...
+            pSoundsources.(fnames{i}).begemis(3), ...
+            pSoundsources.(fnames{i}).begemis(2), ...
+            pSoundsources.(fnames{i}).begemis(1) ...
+        );
+    tmpDistances = [];
+    % calculate distances
+    for oDistance = 1:length(toa)
+        if isnan(toa(oDistance)) | any(isnan(satPositions(oDistance, :)))
+            tmpDistances = [tmpDistances; NaN];
+            continue;
+        end
+        tmpDistances = [ ...
+            tmpDistances; ...
+            artoa.data.calculateGeodist( ...
+                satPositions(oDistance, :), ...
+                pSoundsources.(fnames{i}).position ...
+            ) ...
+        ];
+    end
+    results.(fnames{i}).satDistances = tmpDistances;
+    % find nearest neighbor toa
+    tmpMeasuredToas = NaN(size(results.(fnames{i}).satDate));
+    tmpIndexBelongingToSoso = strcmp(pToaData.soundSource, fnames{i});
+    if ~any(tmpIndexBelongingToSoso)
+        results.(fnames{i}).measuredToa = tmpMeasuredToas;
+        continue;
+    end
+    tmpIndexBelongingToSoso = tmpIndexBelongingToSoso & (pToaData.status ~= 2);
+    tmpToaDate = pToaData.toaDate(tmpIndexBelongingToSoso);
+    tmpToa = pToaData.toa(tmpIndexBelongingToSoso);
+    
+    % interpolate toa data
+    [ ...
+        tmpToaDate, ...
+        tmpToa, ...
+        ~ ...
+    ] = artoa.data.interpolateRafosData( ...
+        tmpToaDate, ...
+        tmpToa, ...
+        pTrackingParameter.interpolationInterval, ...
+        pTrackingParameter.gapSize, ...
+        lower(pTrackingParameter.interpolationMethodString) ...
+    );
+    
+    % find nearest neighbor
+    for oSatDates = 1:length(results.(fnames{i}).satDate)
+        neighborDate = artoa.data.findNearestNeighbor( ...
+            tmpToaDate, ...
+            results.(fnames{i}).satDate(oSatDates) ...
+        );
+        tmpMeasuredToas(oSatDates) = tmpToa(tmpToaDate == neighborDate);
+    end
+    results.(fnames{i}).measuredToa = tmpMeasuredToas;
+    clear tmpDistances;
+end
+
+%% Construct matrices A and B
+
+rowCount = length(satDates) * length(fnames);
+
+aCore = zeros(rowCount, 2 * length(fnames));
+b = zeros(rowCount, 1);
+distances = zeros(rowCount, 1);
+daysSinceFloatStart = NaN(rowCount, 1);
+
+for i = 1:length(fnames)
+    rowIndices = ((i - 1) * length(satDates) + 1):i * length(satDates);
+    startColIndex = (2 * (i - 1)) + 1;
+    distances(rowIndices, 1) = results.(fnames{i}).satDistances;
+    aCore(rowIndices, startColIndex) = 1;
+    aCore(rowIndices, startColIndex + 1) = results.(fnames{i}).daysSinceStart;
+    b(rowIndices, 1) = results.(fnames{i}).measuredToa;
+    daysSinceFloatStart(rowIndices, 1) = ...
+        results.(fnames{i}).satDate ...
+        - artoa.convert.dmy2rd( ...
+            floatDetails.launchtime(3), ...
+            floatDetails.launchtime(2), ...
+            floatDetails.launchtime(1) ...
+        );
+    % construct b
+%     foundToas = findCorrespondingToas(fnames{i}, results.(fnames{i}).satDate);
+end
+
+a = [ ...
+    distances, aCore, ones(size(daysSinceFloatStart)), daysSinceFloatStart ...
+];
+
+% remove all NaN from matrix
+indicesToUse = all(~isnan(a), 2) & all(aCore >= 0, 2) & ~isnan(b);
+
+a = a(indicesToUse, :);
+b = b(indicesToUse, :);
+
+
+end
+
diff --git a/lib/+artoa/+offsets/extractOffsetsDriftsFromSolved.m b/lib/+artoa/+offsets/extractOffsetsDriftsFromSolved.m
index d0800d43a151975b2ce35d6b656a09c51b28246c..f92fd65b17ed4bcad6612a597f2962f6aace1a0f 100644
--- a/lib/+artoa/+offsets/extractOffsetsDriftsFromSolved.m
+++ b/lib/+artoa/+offsets/extractOffsetsDriftsFromSolved.m
@@ -1,6 +1,9 @@
 function [offsets, drifts] = extractOffsetsDriftsFromSolved(pX)
-%EXTRACTOFFSETSDRIFTSFROMSOLVED Summary of this function goes here
-%   Detailed explanation goes here
+%EXTRACTOFFSETSDRIFTSFROMSOLVED Extracts the vectors in a specific manner.
+%   Creates for each output a vector, that first value is belonging to the
+%   float, and all others following are belonging to the soundsources as
+%   they are returned from the
+%   artoa.controller.getSoundsourcesWithAppliedToa function.
 
 soundsourceCount = (length(pX) - 3) / 2;
 
diff --git a/lib/+artoa/+offsets/filterCalculationMatrices.m b/lib/+artoa/+offsets/filterCalculationMatrices.m
new file mode 100644
index 0000000000000000000000000000000000000000..51542ca25c107fb25c5f6730fa3be4b8961e76a2
--- /dev/null
+++ b/lib/+artoa/+offsets/filterCalculationMatrices.m
@@ -0,0 +1,25 @@
+function [A, B] = filterCalculationMatrices(pA, pB)
+%FILTERCALCULATIONMATRICES Summary of this function goes here
+%   Detailed explanation goes here
+
+%% Initialize return variables
+A = pA;
+B = pB;
+
+%% Get soundsource count
+soundsourceCount = length(A(end, 2:end - 2)) / 2;
+
+%% Split matrix A
+distance = A(:, 1);
+soundsources = A(:, 2:end - 2);
+float = A(:, end - 1:end);
+
+%% Remove all soundsources that have only zeros
+soundsourcesToUse = any(soundsources, 1);
+soundsources = soundsources(:, soundsourcesToUse);
+
+%% Rebuild A
+A = [distance, soundsources, float];
+
+end
+
diff --git a/lib/+artoa/+offsets/solve.m b/lib/+artoa/+offsets/solve.m
index 1e5bd984aa22e183638b11ef195927225ac1b98f..c44e026ec901d63296752b1af89ab5641ed86dbd 100644
--- a/lib/+artoa/+offsets/solve.m
+++ b/lib/+artoa/+offsets/solve.m
@@ -1,144 +1,24 @@
-function [a, b, x] = solve(pRfb, pSoundsources, pTrackingParameter, pToaData, pSatData, pAppliedTemperature, pAppliedPressure, pLeapsecondsMatrix)
+function [unfilteredA, unfilteredB, X, A, B] = solve(pRfb, pSoundsources, pTrackingParameter, pToaData, pSatData, pAppliedTemperature, pAppliedPressure, pLeapsecondsMatrix)
 %UNTITLED Summary of this function goes here
 %   Detailed explanation goes here
 
-%% Initialize required variables
-%pSoundsources = artoa.controller.getSoundsourcesWithAppliedToa();
-satPositions = [pSatData.lat_sat, pSatData.lon_sat];
-satDates = artoa.convert.dmy2rd(pSatData.day_sat, pSatData.month_sat, pSatData.year_sat);
-toaDates = [];
-satToas = [];
-satDistances = [];
-floatDetails = pRfb.FLOAT;
-
-%% Create table
-results = struct();
-
-%% Calculate SAT TOAs for every soundsource and get nearest neighbor measured toa
-fnames = fieldnames(pSoundsources);
-for i = 1:length(fnames)
-    results.(fnames{i}) = table();
-    [date, toa] = artoa.toa.predictFromGps( ...
-        pRfb, ...
-        pSoundsources.(fnames{i}), ...
-        struct( ...
-            'temperature', pAppliedTemperature, ...
-            'pressure', pAppliedPressure, ...
-            'method', pTrackingParameter.soundspeedMethodString, ...
-            'soundSource', NaN ...
-        ), ...
-        pLeapsecondsMatrix ...
-    );
-    results.(fnames{i}).satDate = date;
-    results.(fnames{i}).satToa = toa;
-    results.(fnames{i}).daysSinceStart = ...
-        date ...
-        - artoa.convert.dmy2rd( ...
-            pSoundsources.(fnames{i}).begemis(3), ...
-            pSoundsources.(fnames{i}).begemis(2), ...
-            pSoundsources.(fnames{i}).begemis(1) ...
-        );
-    tmpDistances = [];
-    % calculate distances
-    for oDistance = 1:length(toa)
-        if isnan(toa(oDistance)) | any(isnan(satPositions(oDistance, :)))
-            tmpDistances = [tmpDistances; NaN];
-            continue;
-        end
-        tmpDistances = [ ...
-            tmpDistances; ...
-            artoa.data.calculateGeodist( ...
-                satPositions(oDistance, :), ...
-                pSoundsources.(fnames{i}).position ...
-            ) ...
-        ];
-    end
-    results.(fnames{i}).satDistances = tmpDistances;
-    % find nearest neighbor toa
-    tmpMeasuredToas = NaN(size(results.(fnames{i}).satDate));
-    tmpIndexBelongingToSoso = strcmp(pToaData.soundSource, fnames{i});
-    if ~any(tmpIndexBelongingToSoso)
-        results.(fnames{i}).measuredToa = tmpMeasuredToas;
-        continue;
-    end
-    tmpIndexBelongingToSoso = tmpIndexBelongingToSoso & (pToaData.status ~= 2);
-    tmpToaDate = pToaData.toaDate(tmpIndexBelongingToSoso);
-    tmpToa = pToaData.toa(tmpIndexBelongingToSoso);
-    
-    % interpolate toa data
-    [ ...
-        tmpToaDate, ...
-        tmpToa, ...
-        ~ ...
-    ] = artoa.data.interpolateRafosData( ...
-        tmpToaDate, ...
-        tmpToa, ...
-        pTrackingParameter.interpolationInterval, ...
-        pTrackingParameter.gapSize, ...
-        lower(pTrackingParameter.interpolationMethodString) ...
-    );
-    
-    % find nearest neighbor
-    for oSatDates = 1:length(results.(fnames{i}).satDate)
-        neighborDate = artoa.data.findNearestNeighbor( ...
-            tmpToaDate, ...
-            results.(fnames{i}).satDate(oSatDates) ...
-        );
-        tmpMeasuredToas(oSatDates) = tmpToa(tmpToaDate == neighborDate);
-    end
-    results.(fnames{i}).measuredToa = tmpMeasuredToas;
-    clear tmpDistances;
-end
-
 %% Construct matrices A and B
+[unfilteredA, unfilteredB] = artoa.offsets.createCalculationMatrices(pRfb, ...
+    pSoundsources, ...
+    pTrackingParameter, ...
+    pToaData, ...
+    pSatData, ...
+    pAppliedTemperature, ...
+    pAppliedPressure, ...
+    pLeapsecondsMatrix ...
+);
+
+%% Optimize matrices for calculation
+[A, B] = artoa.offsets.filterCalculationMatrices(unfilteredA, unfilteredB);
+
+%% Solve it!
+X = pinv(A) * B;
 
-rowCount = length(satDates) * length(fnames);
-
-aCore = zeros(rowCount, 2 * length(fnames));
-b = zeros(rowCount, 1);
-distances = zeros(rowCount, 1);
-daysSinceFloatStart = NaN(rowCount, 1);
-
-for i = 1:length(fnames)
-    rowIndices = ((i - 1) * length(satDates) + 1):i * length(satDates);
-    startColIndex = (2 * (i - 1)) + 1;
-    distances(rowIndices, 1) = results.(fnames{i}).satDistances;
-    aCore(rowIndices, startColIndex) = 1;
-    aCore(rowIndices, startColIndex + 1) = results.(fnames{i}).daysSinceStart;
-    b(rowIndices, 1) = results.(fnames{i}).measuredToa;
-    daysSinceFloatStart(rowIndices, 1) = ...
-        results.(fnames{i}).satDate ...
-        - artoa.convert.dmy2rd( ...
-            floatDetails.launchtime(3), ...
-            floatDetails.launchtime(2), ...
-            floatDetails.launchtime(1) ...
-        );
-    % construct b
-%     foundToas = findCorrespondingToas(fnames{i}, results.(fnames{i}).satDate);
-end
-
-a = [ ...
-    distances, aCore, ones(size(daysSinceFloatStart)), daysSinceFloatStart ...
-];
-
-% remove all NaN from matrix
-indicesToUse = all(~isnan(a), 2) & all(aCore >= 0, 2) & ~isnan(b);
-
-a = a(indicesToUse, :);
-b = b(indicesToUse, :);
-
-x = pinv(a) * b;
-
-
-%     function [toas] = findCorrespondingToas(soundsourceName, satDate)
-%         toas = NaN(size(satDate));
-%         for o = 1:length(satDate)
-%             if isnan(satDate(o))
-%                 continue;
-%             end
-%             neighbor = artoa.data.findNearestNeighbor(pToaData.date, satDate(o));
-%         end
-%     end
 
 
 end
diff --git a/lib/+artoa/+toa/recalculate.m b/lib/+artoa/+toa/recalculate.m
index 8ed1bf77dd21941867a4b84ce637b1b72f8fe7f0..d1225a16e92b2db20848cac60adbda5873b92d0d 100644
--- a/lib/+artoa/+toa/recalculate.m
+++ b/lib/+artoa/+toa/recalculate.m
@@ -15,6 +15,10 @@ function [toaData] = recalculate(pFloat, pToaData, pOffsetsTable, pAppliedSounds
 %   Returns:
 %       toaData (struct):       The toa data structure with adjusted TOAs
 
+%% Prepare constants
+driftColumnName = 'EmpiricalDrift';
+offsetColumnName = 'EmpiricalOffset';
+
 %% Prepare return variable
 toaData = pToaData;
 
@@ -37,8 +41,8 @@ for i = 1:stepSize:length(toaData.toa)
     endIndex = i + stepSize - 1;
     toaData.toa(startIndex:endIndex) = artoa.toa.addDrift( ...
         toaData.toa(startIndex:endIndex), ...
-        pOffsetsTable{'Float', 'offset'}, ...
-        pOffsetsTable{'Float', 'drift'}, ...
+        pOffsetsTable{'Float', offsetColumnName}, ...
+        pOffsetsTable{'Float', driftColumnName}, ...
         floor(min(toaData.toaDate) - floatLaunchRafosTime) ...
     );
 end
@@ -72,8 +76,8 @@ for i = 1:length(fnames)
     % calculate drift of soundsource
     toa = artoa.toa.addDrift( ...
         toa, ...
-        pOffsetsTable{fnames{i}, 'offset'}, ...
-        pOffsetsTable{fnames{i}, 'drift'}, ...
+        pOffsetsTable{fnames{i}, offsetColumnName}, ...
+        pOffsetsTable{fnames{i}, driftColumnName}, ...
         floor(toaDate - rafosBeginEmission) ...
     );
 
diff --git a/lib/+artoa/+trajectory/calculate.m b/lib/+artoa/+trajectory/calculate.m
index 188dc995d6710623bef98e5e17758e175d7fb5fd..809287d0cf0dc49068416601ef793f76f976b7bd 100644
--- a/lib/+artoa/+trajectory/calculate.m
+++ b/lib/+artoa/+trajectory/calculate.m
@@ -1,4 +1,4 @@
-function [trajectory, trajectoryDates, trajectoryClockError, trajectoryResiduals, trajectoryVelocities, trajectoryTimeDivergenceToGps] = calculate(pFloatDetails, pPressureAndDate, pSatData, pToaData, pSoundsources, pTrackingParameter, pSoundVelocity, pLeapsecondsMatrix)
+function [trajectory, trajectoryDates, trajectoryClockError, trajectoryResiduals, trajectoryVelocities, trajectoryTimeDivergenceToGps] = calculate(pFloatDetails, pPressureAndDate, pSatData, pToaData, pSoundsources, pTrackingParameter, pOffsetsParameter, pSoundVelocity, pLeapsecondsMatrix)
 %CALCULATETRAJECTORY Calculates the trajectory using the given details.
 %   Applies all required corrections to the data and calculates the trajectory
 %   segment by segment afterwards.
@@ -45,6 +45,20 @@ trajectoryResiduals = false;
 trajectoryTimeDivergenceToGps = false;
 trajectoryVelocities = false;
 
+%% Add drift and offsets to soundsources and float
+soundsourceStruct = struct();
+for i = 1:length(involvedSoundsourceNames)
+    soundsourceStruct.(involvedSoundsourceNames{i}) = involvedSoundsources{i};
+end
+if pOffsetsParameter.useOffsets
+    pToaData = artoa.toa.recalculate( ...
+        pFloatDetails, ...
+        pToaData, ...
+        pOffsetsParameter.soundsourceOffsets, ...
+        soundsourceStruct ...
+    );
+end
+
 %% Prepare data for every sound source
 preparedData = struct();
 for i = 1:length(involvedSoundsources)
@@ -88,21 +102,21 @@ for i = 1:length(involvedSoundsources)
         pFloatDetails.cycle(11) ...
     );
 
-    % calculate soundsource offsets and dates
-    [offsets, dates] = artoa.data.calculateOffsetsAndDates( ...
-        [rafosFloatDateCycleBegin, rafosFloatDateCycleEnd], ...
-        [rafosBeginEmission, rafosEndEmission], ...
-        currentSoundsource.offset, ...
-        currentSoundsource.drift, ...
-        currentSoundsource.schedule ...
-    );
-
-    % check overlap between float and sound source deployment and add sound
-    % source offset
-    for oDates = 1:length(dates)
-        kx = find(abs(currentToaDate - dates(oDates)) < 1/2);
-        currentToa(kx) = currentToa(kx) - offsets(oDates);
-    end
+%     % calculate soundsource offsets and dates
+%     [offsets, dates] = artoa.data.calculateOffsetsAndDates( ...
+%         [rafosFloatDateCycleBegin, rafosFloatDateCycleEnd], ...
+%         [rafosBeginEmission, rafosEndEmission], ...
+%         currentSoundsource.offset, ...
+%         currentSoundsource.drift, ...
+%         currentSoundsource.schedule ...
+%     );
+% 
+%     % check overlap between float and sound source deployment and add sound
+%     % source offset
+%     for oDates = 1:length(dates)
+%         kx = find(abs(currentToaDate - dates(oDates)) < 1/2);
+%         currentToa(kx) = currentToa(kx) - offsets(oDates);
+%     end
 
     % interpolate toa data
     [ ...