# Arbitrary tasks

This document describes how to use arbitrary tasks with the ECGkit.

## Description

Sometimes the task you need to perform on ECG signals is too simple to develop a new ECGtask, like computing some statistics, or apply a linear filter, or any type of transformation you may need to perform to the signal. For those cases you may found arbitrary tasks useful.

## Input Arguments

The properties that this task uses are the following:

`progress_handle` — Used to track the progress within your function. `[] (default)`

> progress_handle, is a handle to a progress_bar object, that can be used to track the progress within your function.

`tmp_path` — The path to store temporary data. `tempdir() (default)`

> Full path to a directory with write privileges.

`only_ECG_leads` — Process only ECG signals `true (default)`

> Boolean value. Find out which signals are ECG based on their `ECG_header.desc` description.

`payload` — An arbitrary format variable to be passed to your function. `[] (default)`

> This variable can be useful for passing data to your own function.

`signal_payload` — Consider the result of your arbitrary function as a signal. `false (default)`

> Boolean value that indicates the ECGwrapper to produce a signal instead of a result payload.

`lead_idx` — The signal indexes that your function will affect. `[] (default)`

> A positive integer array with values from 1 to `ECG_header.nsig`.

`function_pointer` — The pointer to your arbitrary function. `[] (default)`

Your function must follow this prototype:

    function result = your_function( ECG_matrix, ECG_header, progress_handle, payload_in)

where the arguments are:

> ECG_matrix, is a matrix size `[ECG\_header.nsamp ECG\_header.nsig]`

> ECG_header, is a struct with info about the ECG signal, such as:

> > - freq, is the sampling frequency of ECG_matrix signal.
> > - desc, description strings about each of the leads/signals.
> > - nsamp is the number of samples of ECG_matrix.
> > - nsig is the amount of leads or signals of ECG_matrix.
> > - gain is a vector of [nsig × 1] with the gain of each lead ( ADCsamples / μV ).
> > - adczero is a vector of [nsig × 1] with the offset of each lead in ADC samples.

> > and others described in the Physionet header.

> progress_handle, is a handle to a progress_bar object, that can be used to track the progress within your function.

> payload_in, is a user variable, of arbitrary format, allowed to be sent to your function. It is sent via the payload property of this class, for example:

    % One variable
    this_ECG_wrapper.ECGtaskHandle.payload = your_variable;

    % Several variables with a cell container
    this_ECG_wrapper.ECGtaskHandle.payload = {your_var1 your_var2};

    % Or the result of a previous task, in this case QRS manual correction (if available)
    % or the automatic detection if not.
    cached_filenames = this_ECG_wrapper.GetCahchedFileName({'QRS_corrector' 'QRS_detection'});
    this_ECG_wrapper.ECGtaskHandle.payload = load(cached_filenames);

and the output of your function must be a struct variable result, or if it is a signal, ensure to make `true` the `signal_payload` property.

`finish_func_pointer` — A pointer to your arbitrary finish function. `@default_finish_function (default)`

A function that will operate over the whole result of your arbitrary function, after the payloads resulting of each iteration were concatenated. This is only used when the result of your `function_pointer` is not a signal (`signal_payload = false`). Your function must follow this prototype:

    payload = your_finish_function(payload, ECG_header)

where the arguments are:

> payload, is the complete payload.

> ECG_header, is a struct with info about the ECG signal, see above for reference.

and this function will change the payload variable as according to your needs and return it to the ECGwrapper object.

`concate_func_pointer` — The pointer to your arbitrary concatenate function. `@default_concatenate_function (default)`

A function that will concatenate or integrate the information produced in each part of your recording, when the result of your `function_pointer` is not a signal (`signal_payload = false`). Your function must follow this prototype:

    payload = your_concatenate_function(plA, plB)

where the arguments are:

> plA and plB are the two payloads to concatenate

and this function will integrate or concatenate both payloads into the resulting payload. This resulting payload, will be plA in the next iteration of concatenation. The `default_concatenate_function` just concatenate payloads:

    % The default behavior of the concatenate function is to concatenate
    % payloads vertically or row-wise.
    if( isempty(plA) )
            payload = plB;
    else
            payload = [plA; plB];
    end

## Examples

1. Arbitrary task producing a signal as a result

> This example is used in the QRScorrector function to perform template-matching on an ECGwrapper (arbitrary big recording) object.

>     aux_w = ECGwrapper('recording_name', 'your_path/recname');
>     aux_w.ECGtaskHandle = 'arbitrary_function';

>     % This is in case you want always to recalculate results, no caching
>     aux_w.cacheResults = false;

>     % Use first and third columns-signals
>     aux_w.ECGtaskHandle.lead_idx = [1 3];

>     % Produce a signal as a result
>     aux_w.ECGtaskHandle.signal_payload = true;

>     % Add a user-string to identify the run
>     aux_w.ECGtaskHandle.user_string = ['similarity_calc_for_lead_' num2str(sort(lead_idx)) ];

>     % add your function pointer
>     aux_w.ECGtaskHandle.function_pointer = @similarity_calculation;

>     % and any data your function may need.
>     aux_w.ECGtaskHandle.payload = pattern2detect;
>     % and you are ready to go !
>     aux_w.Run

2. Arbitrary task producing an arbitrary result

> This is achieved by defining 3 properties (function handles) that perform:

> - The arbitrary task, which produces an arbitrary result `function_pointer`
> - The concatenation of these results `concate_func_pointer`
> - The final result calculation, when all results are concatenated. `finish_func_pointer`

> The configuration of the ECGwrapper object is quite simple:

> > >     cd your_path\ecg-kit\examples
> > >     ECGw = ECGwrapper( 'recording_name', 'your_path\ecg-kit\recordings\208')
> > >     % no overlapp needed between signal partitions
> > >     ECGw.partition_mode = 'ECG_contiguous';
> > >     ECGw.ECGtaskHandle = 'arbitrary_function';
> > >     ECGw.ECGtaskHandle.function_pointer = @my_mean;
> > >     ECGw.ECGtaskHandle.concate_func_pointer = @my_concatenate_mean;
> > >     ECGw.ECGtaskHandle.finish_func_pointer = @my_finish_mean;
> > >     ECGw.Run

> > The result is stored in a `mat` file.

>     Description of the process:
>      + Recording: d:\mariano\misc\ecg-kit\recordings\208.dat
>      + Task name: arbitrary_function

>     ##############
>     # Work done! #
>     ##############

>     Results saved in
>      + your_path\ecg-kit\recordings\208_arbitrary_function.mat

> The arbitrary functions used to calculate the mean in an arbitrary large recording are:

> > - `\ecg-kit\examples\my_mean.m` In this function we only accumulate and count the size of the accumulation.

> >     function result = my_mean(x)

> >     result.the_sum = sum(x);
> >     result.the_size = size(x,1);

> > - `\ecg-kit\examples\my_concatenate_mean.m` This function calculate the final accumulation and counting.

> >     function payload = my_concatenate_mean(plA, plB)

> >     if( isempty(plA) )
> >             payload = plB;
> >     else
> >             payload.the_sum = plA.the_sum + plB.the_sum;
> >             payload.the_size = plA.the_size + plB.the_size;
> >     end

> > - `\ecg-kit\examples\my_finish_mean.m` In this function the mean calculation is performed.

> >     function result_payload = my_finish_mean(payload, ECG_header)

> >     result_payload.mean = payload.the_sum ./ payload.the_size;

## Results format

The format of the results depends on the `signal_payload` property, if it is a signal it will be in MIT format. Otherwise, the results depends on the user-defined output of

## See Also

> ECGtask | QRS detection | ECG delineation | examples