libltfat - Large Time-Frequency Analysis Toolbox Library

Fork libltfat on Github

This is the documentation page for the standalone back end library of LTFAT the Matlab/Octave toolbox for working with time-frequency analysis and synthesis. It is intended both as an educational and a computational tool. The toolbox provides a large number of linear transforms including Gabor and wavelet transforms along with routines for constructing windows (filter prototypes) and routines for manipulating coefficients

Modules

The following modules are included in the libltfat repository and can be optionally compiled:

Function naming convention

The function names are in the following format:

ltfat_<function_name>[_<d|s|dc|sc>](<parameters>)

The ltfat_ prefix is present in all function names while the suffix is optional and identifies the data type the function is working with:

Data type suffix
SuffixData type
ddouble
sfloat
dcltfat_complex_d
scltfat_complex_s
Note
In the documentation the prefix and the suffix will be omitted when introducing a non-unique function and when referring to the function group. Similarly, the real data type (float or double) will be referred to as LTFAT_REAL and the complex data type (ltfat_complex_s or ltfat_complex_d) as LTFAT_COMPLEX.
Additionally, the LTFAT_TYPE type will be used whenever there is a version of the function for each of the four aforementioned types.

Compatibility

The source code of the library complies with both C99 and C++11 standards.

When compiled with C99 enabled, ltfat_complex_d and ltfat_complex_s are effectively the following typedefs:

typedef complex double ltfat_complex_d;
typedef complex float ltfat_complex_s;

Where complex double and complex float types are a C99 feature.

When compiled with C++11 enabled, the following typedefs are used:

typedef std::complex<double> ltfat_complex_d;
typedef std::complex<float> ltfat_complex_s;

The description can be found here std::complex.

Arrays of complex data types from both C99 and C++11 are binary compatible with simple arrays of basic types with the real and the imaginary parts interleaved in memory.

Therefore, in C99 it is legal to do the following casts

complex double c[] = {{1.0,2.0},{3.0,4.0},{5.0,6.0}};
double (*c2)[2] = (double(*)[2]) c;
// c2[n][0] is identical to creal(c[n]) and c2[n][1] is identical to cimag(c[n])
// Or even
double *c3 = (double*) c;
// and c3[2*n] is identical to creal(c[n]) and c3[2*n+1] is identical to cimag(c[n])

Similarly, in C++11 one can do

std::complex<double> c[] = {{1.0,2.0},{3.0,4.0},{5.0,6.0}};
double (*c2)[2] = reinterpret_cast<double(*)[2]>(c);
// c2[n][0] is identical to real(c[n]) and c2[n][1] is identical to imag(c[n])
// Or even
double *c3 = reinterpret_cast<double*>( c);
// and c3[2*n] is identical to real(c[n]) and c3[2*n+1] is identical to imag(c[n])
Warning
The other way around i.e. casting double* (memory allocated as an array of double) to complex double* or std::complex<double>* might not work. See this stackoverflow question.

Linking

The following table summarizes what type the ltfat_complex_d expands to depending on the compiler

Single numberArrayPointer
C99complex double complex double[]complex double*
C++11std::complex<double> std::complex<double>[]std::complex<double>*
Compatibility (C++11 and LTFAT_CINTERFACE defined)double[2]double[][2]double(*)[2]

ltfat_complex_s expands the same way.

Arrays, matrices and naming conventions

The multidimensional arrays are contiguous in memory and therefore, they are reffered to by a single pointer and the individual dimensions are accessed trough an offset.

When an array represents a matrix, it is assumed that the columns are the first dimension and therefore they are stored continuously in memory.

In the function headers, the data arrays are denoted with array brackets [] and a pointer is used whenever referring to a single object. This distinction is just cosmetics as the arrays decay to pointers anyway.

Array sizes, indexes etc. are represented using ltfat_int , which is defined as:

#ifdef LTFAT_LARGEARRAYS
typedef ptrdiff_t ltfat_int;
#else
typedef int ltfat_int;
#endif
Note
Size of ptrdiff_t is system dependent.

Use ltfat_int_is_compatible() to test whether your signed integer type size is compatible with the one libltfat was compiled with. It is crucial the sizes match whenever an array of integers is passed to a libltfat function.

Further, the following naming conventions are used consistently:

Argument naming
Arg. nameDefinition
fTime domain signal
g,gd,gtWindow (filter), canonical dual window, canonical tight window
cCoefficients
aInteger. Time hop size.
MInteger. Number of frequency channels (FFT length).
M2Integer. Number of unique frequency channels for real signals: M2=M/2+1.
LInteger. Length of the signal.
NInteger. Number of time shifts: N=L/a.
WInteger. Number of signal channels.

Error handling

Every function which returns a status code should be checked by the user. Additionally, the error message is printed to the standard error stream. This behavior can be turned off or a custom error handler can be registered. For details see Error handling

Plans

When repeated computations with the same settings are desired, it is convenient to create a plan using the appropriate *_init function, call the *_execute function multiple times and destroy the plan by calling the *_done function. The plan usually contains some precomputed read-only data, working arrays and other plans. The plan is represented as a pointer to an opaque structure and here is an example how to use it:

ltfat_dgt_long_plan_d* plan = NULL;
ltfat_dgt_long_init_d(f, g, L, W, a, M, c, ptype, FFTW_ESTIMATE, &plan)
// Fill in c after calling init. The FFTW planning routine migh have written
// something to it.
ltfat_dgt_long_execute_d(plan);
// Refresh data in f and call execute again
ltfat_dgt_long_done_d(&plan);
Note
Please note that due to the limitation of FFTW the *_init routines are not re-entrant because of the FFTW planning happening in them. Therefore, the *_init functions cannot be called simultaneously on different threads even when creating completely separate plans.
Further, the *_execute functions are reentrant and thread-safe, but not when executed on a single plan concurrently on separate threads. This is a contrast with the FFTW execute function, which is thread safe even for a single plan. This limitation comes from the fact that the LTFAT plan contains some working buffers.

States

A state is a plan which additionally holds some data which persists between the execute calls.