# MainModule

This is the main unit containing the **PosDefManifold** *module* (FourierAnalysis.jl).

## dependencies

standard Julia packages | external packages |
---|---|

LinearAlgebra | FFTW |

Statistics | AbstractFFTs |

RecipesBase | |

DSP |

The main module does not contains functions, but it declares all **types** and objects holding data (named **data objects**) used in all units.

Contents |
---|

types |

data objects |

tips & tricks |

## types

### fInterval

`fInterval = Union{IntOrReal,Tuple{IntOrReal, IntOrReal}, Colon}`

In several functions you are allowed to select a **frequency range** (in Hz). This can be

- a single frequency (in Hz), given as an integer or a real number, e.g., 10,
- a 2-tuple of integers or reals holding the lower and upper frequency limit (in Hz), e.g. (8, 10.5),
- a colon, to indicate as usual in Julia all available frequencies.

Frequency ranges are used as argument in the functions `mean`

, `extract`

, `meanAmplitude`

, `concentration`

, `meanDirection`

, `comodulation`

and `coherence`

. They apply both to frequency domain and to time-frequency domain data. In the frequency domain, the frequencies are the Fourier discrete frequencies with resolution $sr/wl$, with or without the DC level in the first position, depending on how the object has been constructed. In the time-frequency domain, the frequencies actually are the center frequencies of the filter bank used for constructing the object. Thus, the actual frequencies actually contained in a given position depends on the `bandwidth`

argument used to construct the oject. See `filterbank`

.

### tInterval

`tInterval = Union{Int, Tuple{Int, Int}, Colon}`

In several functions you are allowed to select a **time range** (in samples). This can be

- a single sample, given as an integer, e.g., 16,
- a 2-tuple of integers holding the lower and upper time limit (in sampes), e.g. (1, 120),
- a colon, to indicate as usual in Julia all available samples.

These ranges are used as argument in the same functions where fInterval ranges are used. Obviously, they apply only to time-frequency domain data.

### Smoother

```
@enum Smoother begin
noSmoother = 1
hannSmoother = 2
hammingSmoother = 3
blackmanSmoother = 4
end
```

An instance of this type is requested by the `smooth`

function, and as an optional keyword argument by several constructors. It apply both to objects created in the frequency domain and in the time-frequency domain.

`noSmoother`

corresponds to no smoothing.`hannSmoother`

is the*Hann*smoothing window (3-points)`hammingSmoother`

is the*Hamming*smoothing window (3-points)`blackmanSmoother`

is the*Blackman*smoothing window (5-points)

See `smooth`

for details on these windows.

### SpectraVector

A vector of Spectra objects.

### CrossSpectraVector

A vector of CrossSpectra objects.

### CoherenceVector

A vector of Coherence objects.

**CoherenceVector₂**

A vector of CoherenceVector objects.

### TFAnalyticSignalVector

A vector of TFAnalyticSignal objects.

### TFAmplitudeVector

A vector of TFAmplitude objects.

### TFPhaseVector

A vector of TFPhase objects.

### FDobjects

An object in the frequency domain (FD), that is, the union of Spectra, CrossSpectra and Coherence objects.

### FDobjectsVector

A vector of objects in the frequency domain (FD), that is, the union of SpectraVector, CrossSpectraVector and CoherenceVector types.

### TFobjects

An object in the time-frequency (TF) domain, that is, the union of TFAnalyticSignal, TFAmplitude, TFPhase objects.

### TFobjectsVector

A vector of objects in the time-frequency (TF) domain, that is, the union of TFAnalyticSignalVector, TFAmplitudeVector and TFPhaseVector types.

## data objects

*FourierAnalysis* creates an *operator object*, the `Planner`

, which is used to create FFTW plans for FFT computations, and several *data objects*. All of them are Julia structures. Data objects all have a corresponding vector type:

data objects | domain | vector type |
---|---|---|

Taper | time | none |

Spectra | frequency | SpectraVector |

CrossSpectra | frequency | CrossSpectraVector |

Coherence | frequency | CoherenceVector |

TFAnalyticSignal | time-frequency | TFAnalyticSignalVector |

TFAmplitude | time-frequency | TFAmplitudeVector |

TFPhase | time-frequency | TFPhaseVector |

For all data objects, *FourierAnalysis* overwrites the Julia Base.show function to display in the REPL relevant information about the name and value of the struct's fields in an easily-readable tabular form.

The field holding the data of all data objects is consistently named `.y`

. As a summary, this is what `.y`

holds in all data objects:

Taper: for all simple tapers, a real $t$-vector holding the tapering window. For Slepians tapers (multi-tapering), a real $t$x$h$ matrix where each column holds the tapering window for one of the $h$ Slepian tapering windows.

Spectra: a real $f$x$n$ matrix, where $f$ is the number of Fourier discrete frequencies and $n$ the number of time-series. Each column of

`y`

holds the spectrum for the corresponding time-series. In the case of one time-series only,`y`

is a vector.CrossSpectra: a $f$-vector of complex $n$x$n$ matrices where $f$ is the number of Fourier discrete frequencies and $n>1$ the number of time-series that have generated the cross-spectra. Each matrix is the cross-spectral matrix for the corresponding frequency.

Coherence: a $f$-vector of real $n$x$n$ matrices where $f$ is the number of Fourier discrete frequencies and $n>1$ the number of series that have generated the coherence. Each matrix is the coherence matrix for the corresponding frequency.

TFAnalyticSignal: a complex $f$x$t$ matrix, where $f$ is the number of band-pass regions of the filter bank used to generate the analytic signal and $t$ is the number of time samples (time-frequency representation).

TFAmplitude: a real $f$x$t$ matrix, where $f$ is the number of band-pass regions of the filter bank used to generate the amplitude and $t$ is the number of time samples (time-frequency representation).

TFPhase: a real $f$x$t$ matrix, where $f$ is the number of band-pass regins of the filter bank used to generate the phase and $t$ is the number of time samples (time-frequency representation).

## tips & tricks

See recipes.jl for tips on how to plot tapering windows, spectra and time-frequency data.

By convention, the *frequency* dimension of data arrays in data objects is always the first dimension. For instance, the data of multivariate Spectra and of all time-frequency objects (TFobjects), that is, TFAnalyticSignal, TFAmplitude and TFPhase, is a matrix in which the first dimension unrolls frequencies. This is the case also for CrossSpectra and Coherence objects, which data is a vector of cross-spectral or coherence matrices across frequencies.

#### window length in FFTW

For effective use of the FFTW package, keep in mind that in FFTW the window length $wl$ does not need to be a power of two, however FFTW is best for window lengths of the form $2^a, 3^b, 5^c, 7^d, 11^e, 13^f$, where $e+f$ is either $0$ or $1$, and the other exponents are arbitrary.

#### derive your own time-frequency measures

All functions implemented in unit timefrequencyuni.jl and timefrequencybi.jl allow to compute time-frequency measures averaging across several analytic signal objects. For each analytic signal you can extract a time-frequency region passing with argument `mode`

the `extract`

function (default) or the average in such a region passing with argument `mode`

the `mean`

function.

Argument `func`

allows you to apply any function to the extracted regions or means. Using this you can obtain a lot of new averaging procedures. As an example, suppose that you want to use the `meanAmplitude`

of a TFAnalyticSignalVector object, but instead of the arithmetic mean of the amplitude you want to compute the geometric mean of the power. You will then pass as argument to the `meanAmplitude`

function `func=x->log.(x.^2)`

and take the `exp.`

function of the output. It is as simple as that and works both using the `mode=extract`

argument (default) or the `mode=mean`

argument.

#### Threads

Some functions in *FourierAnalysis* calls BLAS routine implicitly via Julia. You can set the number of threads the BLAS library should use by:

```
using LinearAlgebra
BLAS.set_num_threads(n)
```

where `n`

is the number of threads. By default, *FourierAnalysis* reserves to BLAS all CPU threads available on your computer (given by the output of `Sys.CPU_THREADS`

). The number of threads used by Julia for multi-threaded computations is given by the output of `Threads.nthreads()`

. In Windows this latter number of threads is set to half the available threads. In Linux and OSX defaults to one and is controlled by an environment variable, i.e.,

`export JULIA_NUM_THREADS=4`

In Linux, working with the Atom IDE, you also have to set to `global`

the field found in Atom under `Settings(or Preferences)/julia-client/Settings/Julia Options/Number of Threads`

.

In Windows, set the desired number of threads in the settings of the julia-client Juno package.

See this post, this post and julia doc on threads.

Notice that *FourierAnalysis* features many multi-threaded functions and these may allow a gain in computation time only if Julia is instructed to use at least two threads.