## Signal

The signal entity is a general purpose container of time-ordered values. We recognize two types of signals:

- measured signals - signals of this type typically store discrete values as they come through the filter chain
- returns discrete values and bounds if requested through an appropriate method call
- uses the approximator entity to approximate/interpolate the discrete values and thus calculate the continuous levels

- calculated signals - signals produced by a signal model
- do not work with discrete values and/or bounds, corresponding methods return
`E_NOTIMPL`

- use a custom implementation to calculate continuous levels, do not use any approximator

- do not work with discrete values and/or bounds, corresponding methods return

An interface definition for a signal entity is called `scgms::ISignal`

and is defined as follows:

class ISignal : public virtual refcnt::IReferenced {
public:
virtual HRESULT IfaceCalling Get_Discrete_Levels(double* const times, double* const levels, const size_t count, size_t *filled) const = 0;
virtual HRESULT IfaceCalling Get_Discrete_Bounds(TBounds* const time_bounds, TBounds* const level_bounds, size_t *level_count) const = 0;
virtual HRESULT IfaceCalling Update_Levels(const double *times, const double *levels, const size_t count) = 0;
virtual HRESULT IfaceCalling Get_Continuous_Levels(IModel_Parameter_Vector *params, const double* times, double* const levels,
const size_t count, const size_t derivation_order) const = 0;
virtual HRESULT IfaceCalling Get_Default_Parameters(IModel_Parameter_Vector *parameters) const = 0;
};

Here, `TBounds`

is a simple bounds container:

struct TBounds {
double Min, Max;
};

Above defined methods often works with `times`

and `levels`

pointers. These are pointers to arrays containing the time and level values. Both of these arrays are the same size, which is determined by the `count`

parameter. The value at a given index in the `levels`

array was recorded with a time at the same index in the `times`

array.

`Get_Discrete_Levels`

- fills the`times`

and`levels`

arrays with internally stored**time-ordered**(oldest to newest) discrete values; the maximum count is determined by the`count`

parameter, the actual count is stored into the`filled`

parameter- a call to
`Get_Discrete_Bounds`

usually comes prior to this method call to obtain the actual count of values - the returned times and values are ordered from the oldest to the newest
- measured signals implements this method to return measured values
- calculated signals return
`E_NOTIMPL`

- a call to
`Get_Discrete_Bounds`

- fills the`time_bounds`

with bounds of recorded time, fills the`level_bounds`

with bounds of recorded values and`level_count`

with the count of levels stored- any of the parameters may be set to
`nullptr`

to signalize we are not interested in such bounds or counts; this may improve performance - measured signals return valid bounds and counts, if requested
- calculated signals return
`E_NOTIMPL`

- any of the parameters may be set to
`Update_Levels`

- stored a new set of time-value pairs (given in`times`

and`levels`

arrays) into the internal storage- measured signals should store new levels
- calculated signals return
`E_NOTIMPL`

`Get_Continuous_Levels`

- retrieves levels (or level derivation) at given arbitrary times, that do not necessarily match the recorded discrete levels times`params`

could be`nullptr`

, typically when calling this method on a measured signal, or when use of default parameters is intended- the
`levels`

array must be equal in size to the`times`

array (pre-allocated prior the method call) `derivation_order`

contains the desired order of derivation to be retrieved; one may use the pre-defined constants for levels-only (scgms::apxNo_Derivation) or first-order derivation (scgms::apxFirst_Order_Derivation)- in a measured signal, this retrieves the derivation approximation given by the approximator entity
- calculated signal calculates the derivation by its own internal rules
- however, it is
**not**required to support any derivation order greater than 0, i.e.; the only required implementation is for retrieving the levels-only

`Get_Default_Parameters`

- retrieves a default parameter set for a given signal- measured signals return
`E_NOTIMPL`

- calculated signals return the default parameter set copied to the pre-allocated container (via the container
`set`

method)

- measured signals return

### Example implementation

Please, refer to the signal model subpage to see an example of a model signal implementation. To implement a measured signal, do not inherit from the calculated signal parent, but rather implement every method in your class.

### Use of a signal entity

Many scientific papers and engineering work relies on data series to process signals. Each signal is a dedicated data series. `ISignal`

interface provides
a convenient way to update the data series with new levels measured at specific times, to query their bounds and the levels - see the methods containing `_Discrete_`

. Moreover, it provide approximation/interpolation
of the data series, which is done using the IAproximator interface - see the `Get_Continuous_Levels`

method.

When it comes to performance, the main advantage is that entire signal is processed at once, possibly using vectorized instructions. For example, you can have the glucose sensor measured levels, which are transparently transformed to a more precise blood glucose level estimate using the diffusion model. We achieve such functionality with the Signal Model.

#### Warning

Be aware that we provide this interface as a convenience only. For a practical use, we strongly discourage its use in favor to the CCircular_Buffer template available with the Native Scripts.
With the circular buffer, you have fixed memory use, which is important with low-power, embedded devices. `ISignal`

can accomodate as many glucose levels as desired, thus
possibly leading to memory exhaustion on devices with limited amounts of RAM.

In a realistic experimental setup, it is also much more reasonable to calculate new signal values from the recent value(s) of possibly one or several signal(s) only. Therefore, the circular buffer results to faster, memory constant, inexpensive code, which is suitable for practictal, glucose-management, low-power devices. On high-performance servers, it can yield considerably greater performance. You just need to start using the per-partes computation instead of the classic signal processing.

When peer reviewing various conference and journal papers, we found that many of them goes the wrong direction by not considering the limited amount of RAM on low-power devices.
Actually, they did not address limited-computing issues to prove that their work is feasible for a practical use. Therefore, you may find the `ISignal`

convenient when
porting an older project. For a new project, we strongly suggest to use the circular buffer instead.