diff --git a/VERSION b/VERSION
index 83981c0e3aabbb291048f2d619c53f3bb686f5c7..a6b4ce84014c146e09687bcb2615f45705efc402 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-175
\ No newline at end of file
+176
\ No newline at end of file
diff --git a/lib/+artoa/+controller/+file/loadInterim.m b/lib/+artoa/+controller/+file/loadInterim.m
index ff28195d4ff814160f95adaaa62afdfadc9672c5..c6ecba3fb7b57ddcadbc3e4c7d8d536e095cac86 100644
--- a/lib/+artoa/+controller/+file/loadInterim.m
+++ b/lib/+artoa/+controller/+file/loadInterim.m
@@ -25,6 +25,8 @@ artoa.controller.track.trajectoryOutput.close();
 %% Load mat file
 load(fullfile(pathname, filename), '-mat');
 
+%% Initialize plugins
+artoa.plugins.initialize();
 %% Initialize tracking parameter
 artoa.controller.track.parameter.updateGui();
 %% Initialize offsets
diff --git a/lib/+artoa/+controller/+main/collectTrackingMethods.m b/lib/+artoa/+controller/+main/collectTrackingMethods.m
new file mode 100644
index 0000000000000000000000000000000000000000..3523deaa632230fdddd9b8219fbefff7b91fa69c
--- /dev/null
+++ b/lib/+artoa/+controller/+main/collectTrackingMethods.m
@@ -0,0 +1,15 @@
+function [trackingMethods] = collectTrackingMethods()
+%INITIALIZE Summary of this function goes here
+%   Detailed explanation goes here
+
+global artoaWorkspace;
+
+%% Get default tracking methods
+trackingMethods = artoaWorkspace.defaults.trackingMethods;
+
+%% Get plugin methods
+if (artoa.data.hasMember(artoaWorkspace, {'plugins', 'tracking', 'functionHandles'}))
+    trackingMethods = [trackingMethods fieldnames(artoaWorkspace.plugins.tracking.functionHandles)];
+end
+
+end
diff --git a/lib/+artoa/+controller/+main/open.m b/lib/+artoa/+controller/+main/open.m
index 17801e7f51139f6c8426e89dc9bceed920a397c3..a68584f059512ffb357a267148d5b8ab13f2547a 100644
--- a/lib/+artoa/+controller/+main/open.m
+++ b/lib/+artoa/+controller/+main/open.m
@@ -62,14 +62,12 @@ callbacks.buttonEmpiricalToNan = @artoa.controller.edit.offsets.buttonEmpiricalT
 artoaWorkspace.defaults.mainCallbacks = callbacks;
 
 %% Start artoa4
-
 artoa.gui.main( ...
     callbacks, ...
-    artoaWorkspace.defaults.trackingMethods, ...
+    artoa.controller.main.collectTrackingMethods(), ...
     artoaWorkspace.defaults.interpolationMethods, ...
     artoaWorkspace.defaults.soundspeedMethods ...
     );
 
 
 end
-
diff --git a/lib/+artoa/+controller/initializeArtoa4.m b/lib/+artoa/+controller/initializeArtoa4.m
index 17c1dc6e3651b9d5407ba04ff84cbe692a68375a..4b624487d7779aba2346dd09f2cc515f5f893aba 100644
--- a/lib/+artoa/+controller/initializeArtoa4.m
+++ b/lib/+artoa/+controller/initializeArtoa4.m
@@ -1,6 +1,6 @@
 function [] = initializeArtoa4()
 %INITIALIZEARTOA4 Initializes variables required for artoa4 and creates the main window if required.
-%   
+%
 
 global artoaDataInput artoaWorkspace artoaGui;
 
@@ -36,6 +36,9 @@ artoaWorkspace.defaults.soundspeedMethods = { ...
 };
 artoaWorkspace.defaults.pickPointMarkerSize = 80;
 
+artoaWorkspace.plugins = struct();
+artoaWorkspace.plugins.tracking = struct();
+
 artoaGui = struct();
 artoaGui.figures = struct();
 artoaGui.main = struct();
@@ -58,6 +61,9 @@ catch ex
     error([mfilename ': Reading soundsource file failed with the following message: ' ex.message]);
 end
 
+%% Initialize all plugins
+artoa.plugins.initialize();
+
 %% Open main gui
 artoa.controller.main.open();
 
@@ -70,4 +76,3 @@ if artoa.data.getMember(artoaDataInput.ini, {'view', 'hidedeleteddatapoints'}, f
 end
 
 end
-
diff --git a/lib/+artoa/+plugins/+tracking/callTrackingMethod.m b/lib/+artoa/+plugins/+tracking/callTrackingMethod.m
new file mode 100644
index 0000000000000000000000000000000000000000..49652d630415acee899d74b59778529db5f82af8
--- /dev/null
+++ b/lib/+artoa/+plugins/+tracking/callTrackingMethod.m
@@ -0,0 +1,22 @@
+function [positions, clockError] = callTrackingMethod(pTrackingMethod, pData, pSoundsourcePositions, pCombinationDetails)
+%CALLTRACKINGMETHOD Summary of this function goes here
+%   Detailed explanation goes here
+
+global artoaWorkspace;
+
+positions = [];
+clockError = [];
+
+if ~artoa.data.hasMember(artoaWorkspace, {'plugins', 'tracking', 'functionHandles', pTrackingMethod})
+    return;
+end
+
+[positions, clockError] = artoaWorkspace.plugins.tracking.functionHandles.(pTrackingMethod)( ...
+    pData, ...
+    pSoundsourcePositions, ...
+    pCombinationDetails ...
+    );
+
+
+end
+
diff --git a/lib/+artoa/+plugins/findTrackingMethods.m b/lib/+artoa/+plugins/findTrackingMethods.m
new file mode 100644
index 0000000000000000000000000000000000000000..066b74c90c3b8aefb5275e3f3735e2237a8e3bcb
--- /dev/null
+++ b/lib/+artoa/+plugins/findTrackingMethods.m
@@ -0,0 +1,35 @@
+function [trackingMethods] = findTrackingMethods()
+%INITIALIZE Summary of this function goes here
+%   Detailed explanation goes here
+
+%% Find all tracking methods
+[filePath, ~, ~] = fileparts(mfilename('fullpath'));
+filePath = fullfile(filePath, '..', '..', '..');
+
+trackingMethods = dir(fullfile(filePath, 'plugins', 'tracking', '*.m'));
+
+plugins = {};
+for oTrackingMethods = 1:size(trackingMethods)
+    if (trackingMethods(oTrackingMethods).isdir)
+        continue;
+    end
+    plugins{end + 1} = fullfile( ...
+        trackingMethods(oTrackingMethods).folder, ...
+        trackingMethods(oTrackingMethods).name ...
+    );
+end
+
+trackingHandles = function_handle(plugins);
+
+%% Convert them to struct
+trackingMethods = struct();
+if ~iscell(trackingHandles)
+    trackingMethods.(func2str(trackingHandles)) = trackingHandles;
+    return;
+end
+
+for i = 1:size(trackingHandles)
+    trackingMethods.(func2str(trackingHandles{i})) = trackingHandles{i};
+end
+
+end
diff --git a/lib/+artoa/+plugins/initialize.m b/lib/+artoa/+plugins/initialize.m
new file mode 100644
index 0000000000000000000000000000000000000000..d092d2e326f666b085d1c468793549072928e66d
--- /dev/null
+++ b/lib/+artoa/+plugins/initialize.m
@@ -0,0 +1,19 @@
+function [] = initialize()
+%INITIALIZE Summary of this function goes here
+%   Detailed explanation goes here
+
+global artoaWorkspace;
+
+%% Check if workspace supports plugins
+
+if ~artoa.data.hasMember(artoaWorkspace, {'plugins', 'tracking'})
+    warning('Loaded artoaWorkspace does not support tracking plugins! Aborting ...');
+    return;
+end
+
+%% Get tracking methods
+artoaWorkspace.plugins.tracking.functionHandles = ...
+    artoa.plugins.findTrackingMethods();
+
+
+end
diff --git a/lib/+artoa/+trajectory/calculate.m b/lib/+artoa/+trajectory/calculate.m
index 8b1044e1b23ff2589d00bfb64d4f8c5a60eaa713..bc7d9213273b38cb4c784bf9c6af3a3675e30740 100644
--- a/lib/+artoa/+trajectory/calculate.m
+++ b/lib/+artoa/+trajectory/calculate.m
@@ -233,11 +233,11 @@ for oCombination = 1:size(soundsourceCombinations, 1)
         currentCombination.referencePosition{1} = num2str(trajectory(end, :));
     end
     [segmentPositions, segmentDates, segmentClockError, segmentResiduals] = artoa.trajectory.calculateCombinationSegment( ...
-            preparedData, ...
-            currentCombination, ...%trajectory(end, :), ...
-            floatReferenceTime, ...
-            pSoundVelocity(oCombination, :), ...
-            pTrackingParameter.trackingMethodString ...
+        preparedData, ...
+        currentCombination, ...%trajectory(end, :), ...
+        floatReferenceTime, ...
+        pSoundVelocity(oCombination, :), ...
+        pTrackingParameter.trackingMethodString ...
     );
     
     % remove NaNs from segment
diff --git a/lib/+artoa/+trajectory/calculateCombinationSegment.m b/lib/+artoa/+trajectory/calculateCombinationSegment.m
index 2451093d9e5b32b7436642d1f4a822d9e3a44497..105bd21c27c366420aa1f25a6aa0f94ee946876a 100644
--- a/lib/+artoa/+trajectory/calculateCombinationSegment.m
+++ b/lib/+artoa/+trajectory/calculateCombinationSegment.m
@@ -62,9 +62,12 @@ referencePosition = cellfun(@str2double, strsplit(pCombinationDetails.referenceP
 %% Filter toa data
 intersectedToaDates = pCorrectedData.(soundsourceNames{1}).toaDate;
 soundsourcePositions = [pCorrectedData.(soundsourceNames{1}).position];
+pluginSoundsourcePositions = struct();
+pluginSoundsourcePositions.(soundsourceNames{1}) = pCorrectedData.(soundsourceNames{1}).position;
 for i = 2:length(soundsourceNames)
     [intersectedToaDates] = intersect(intersectedToaDates, pCorrectedData.(soundsourceNames{i}).toaDate);
     soundsourcePositions = [soundsourcePositions; pCorrectedData.(soundsourceNames{i}).position];
+    pluginSoundsourcePositions.(soundsourceNames{i}) = pCorrectedData.(soundsourceNames{i}).position;
 end
 
 %% Remove all dates that are out of bounds
@@ -73,12 +76,22 @@ intersectedToaDates = intersectedToaDates( ...
     & intersectedToaDates <= segmentEnd ...
 );
 
+%% Create a table for every soundsource (required by tracking plugin system)
+pluginTables = struct();
+for i = 1:length(soundsourceNames)
+    pluginTables.(soundsourceNames{i}) = table();
+end
+
+%% Prepare data
 distanceToSoundsources = {};
 %segmentPositions = [pStartposition];
 segmentPositions = referencePosition;
+segmentToas = {};
+warning('off'); % disable warnings because creating the tables are not consistent
 for oDates = 1:length(intersectedToaDates)
     currentDateValue = intersectedToaDates(oDates);
     distanceToSoundsources{oDates} = [];
+    segmentToas{oDates} = [];
     for i = 1:length(soundsourceNames)
         currentName = soundsourceNames{i};
         selection = pCorrectedData.(currentName).toaDate == currentDateValue;
@@ -105,12 +118,18 @@ for oDates = 1:length(intersectedToaDates)
             + windowStartTime ...
             + leapseconds ...
             + floatWindowStart;
+        segmentToas{oDates} = [segmentToas{oDates}; relativeToa];
         
         % calculate distance to the source
         distanceToSoundsources{oDates} = [ ...
             distanceToSoundsources{oDates}; ...
             relativeToa * (pSoundVelocity(i)/1000)
         ];
+    
+        % store in pluginTables
+        pluginTables.(currentName).date{oDates} = currentDateValue;
+        pluginTables.(currentName).toa{oDates} = relativeToa;
+        pluginTables.(currentName).distance{oDates} = distanceToSoundsources{oDates}(i);
 %         distanceToSoundsources{oDates} = [ ...
 %             distanceToSoundsources{oDates}; ...
 %             (...
@@ -123,6 +142,7 @@ for oDates = 1:length(intersectedToaDates)
     end
 
 end
+warning('on');
 
 if strcmp(trackingMethod, 'hyperbolic') && (length(soundsourceNames) < 3)
     trackingMethod = 'circular';
@@ -171,6 +191,16 @@ switch trackingMethod
             end
             segmentClockError = [segmentClockError; currentClockError];
         end
+    otherwise
+        % prepare soundsource infos
+        [segmentPositions, segmentClockError] = artoa.plugins.tracking.callTrackingMethod( ...
+            pTrackingMethod, ...
+            pluginTables, ...
+            pluginSoundsourcePositions, ...
+            pCombinationDetails ...
+            );
+        
+        segmentPositions = [referencePosition; segmentPositions];
         
 %         if length(unique(sosonr)) < 3;   % check if 3 sources have been specified in track panel
 %             fprintf(1,'Hyperbolic tracking not possible: only 2 sound sources specified, using circular tracking\r');
diff --git a/lib/vendor/FEX-function_handle/function_handle.m b/lib/vendor/FEX-function_handle/function_handle.m
new file mode 100644
index 0000000000000000000000000000000000000000..168c3593d46f3d54a3bb3116620180205fba394c
--- /dev/null
+++ b/lib/vendor/FEX-function_handle/function_handle.m
@@ -0,0 +1,147 @@
+function h = function_handle(fcn)
+% FUNCTION_HANDLE        Construct function handle from string or
+%                        cell array of strings
+%
+% FUNCTION_HANDLE constructs a <a href="matlab:help([matlabroot '/toolbox/matlab/datatypes/function_handle'])">function_handle</a> for built-in or
+% user-defined functions.
+%
+% When constructing a <a href="matlab:help([matlabroot
+% '/toolbox/matlab/datatypes/function_handle'])">function_handle</a> directly with <a href="matlab:help('@')">@</a> or <a href="matlab:help('str2func')">str2func</a>,
+% it is only possible to succesfully evaluate the resulting handle when
+% the function the handle refers to was on the MATLAB search at the time
+% the handle was created. To create valid handles to arbitrarty
+% functions possibly not on the search path, use the FUNCTION_HANDLE
+% constructor.
+%
+% F = FUNCTION_HANDLE(fcn) for string or cell string [fcn] creates a
+% function_handle or cell array of function handles for each of the
+% handles or strings in [fcn]. Any string in [fcn] may include the
+% path to the function of interest. An error is issued in case the
+% path information is incorrect, of the specified file is not an
+% executable MATLAB function.
+%
+% EXAMPLES:
+%
+%    >> F = function_handle('./path/to/function/myFcn.m')
+%    F =
+%         @myFcn
+%
+%    >> A = function_handle(...
+%               {@cos, '../dir/not/on/MATLAB/path/myFunction.m'})
+%    A =
+%         @cos    @myFunction
+%
+%    >> A{1}(pi)
+%    ans =
+%       -1
+%
+%    >> functions(A{1})
+%    ans =
+%         function: 'min'
+%             type: 'simple'
+%             file: ''
+%
+%    >> functions(A{2})
+%    ans =
+%         function: 'myFunction'
+%             type: 'simple'
+%             file: '/fullpath/dir/not/on/MATLAB/path/myFunction.m'
+%
+%  See also <a href="matlab:help([matlabroot '/toolbox/matlab/datatypes/function_handle'])">function_handle (built-in)</a>, str2func, functions.
+
+
+% Please report bugs and inquiries to:
+%
+% Name       : Rody P.S. Oldenhuis
+% E-mail     : oldenhuis@gmail.com
+% Licence    : 2-clause BSD (See License.txt)
+
+
+% Changelog
+%{
+2014/March/19 (Rody Oldenhuis)
+ - NEW: first version
+%}
+
+
+% If you find this work useful, please consider a donation:
+% https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6G3S5UYM7HJ3N
+
+    %% Initialize
+
+    % Quick exit
+    if isa(fcn, 'function_handle')
+        h = fcn; return; end
+
+    if ~iscell(fcn)
+        fcn = {fcn}; end
+
+    % Extract everything that already is a function handle
+    h    = cell(size(fcn));
+    F    = cellfun('isclass', fcn, 'function_handle');
+    h(F) = fcn(F);
+    if all(F)
+        return; end
+
+    % Continue with the ones specified as strings
+    fcn = fcn(~F);
+    if ~iscellstr(fcn)
+        throwAsCaller(MException(...
+            'function_handle:invalid_objects',...
+            'Invalid types detected in input. Expected types are ''function_handle'' or ''char''.'));
+    end
+    hF = cell(size(fcn));
+
+    %% Get to work
+
+    % Make sure we always end up where we started
+    prevDir = pwd;
+    clean__ = onCleanup(@(~)cd(prevDir));
+
+    for ii = 1:numel(fcn)
+
+        % Valid inputs
+        if any(exist(fcn{ii})==[2 3 5 6 8]) %#ok<EXIST>
+
+            [pth,name] = fileparts(fcn{ii});
+
+            % non-builtin
+            if ~isempty(pth)
+                if exist(pth,'dir')==7
+                    cd(pth);
+                        hF{ii} = str2func(['@' name]);
+                    cd(prevDir);
+                else
+                    throwAsCaller(MException(...
+                        'function_handle:dir_not_found',...
+                        'Directory ''%s'' not found.', pth));
+                end
+
+            % builtin
+            elseif exist(fcn{ii},'builtin')==5
+                hF{ii} = str2func(fcn{ii});
+
+            % unrecognized
+            else
+                throwAsCaller(MException(...
+                    'function_handle:fcn_not_found',...
+                    ['Function ''%s'' is not on the MATLAB search path, and does not seem ',...
+                    'to be a builtin.'], name));
+            end
+
+        % Invalid input
+        else
+            throwAsCaller(MException(...
+                'function_handle:fcn_invalid',...
+                'Function or file ''%s'' not found.', fcn{ii}));
+        end
+    end
+
+    % Final assignment
+    h(~F) = hF;
+
+    % Make output more intuitive
+    if numel(h)==1
+        h = h{1}; end
+
+end
diff --git a/plugins/tracking/sampleTrackingMethod.m b/plugins/tracking/sampleTrackingMethod.m
new file mode 100644
index 0000000000000000000000000000000000000000..e9c0d03693bc4f75bc9c9885b217cadd94efa775
--- /dev/null
+++ b/plugins/tracking/sampleTrackingMethod.m
@@ -0,0 +1,34 @@
+function [positions, clockError] = sampleTrackingMethod(pData, pSoundsourcePositions, pCombinationDetails)
+%SAMPLETRACKINGMETHOD A sample function to write your own tracking algorithms
+%
+%   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.
+%
+%
+%   Returns:
+%       positions (double):
+%           The calculated list of segment positions as a X x 2 column vector.
+%       clockError (double):
+%           The estimated clock error.
+
+%% Get reference position and all soundsource names that are involved
+referencePosition = cellfun(@str2double, strsplit(pCombinationDetails.referencePosition{1}));
+soundsourceNames = strsplit(pCombinationDetails.soundsources{1});
+
+%% Show all data that has been passed to the plugin method
+pData
+pCombinationDetails
+pSoundsourcePositions
+
+%% Return NaN because this is a sample
+positions = NaN(size(pData.(soundsourceNames{1}).date, 1), 2);
+clockError = [];
+
+end
\ No newline at end of file