Delay coordinates embedding

A timeseries recorded in some manner from a dynamical system can be used to gain information about the dynamics of the entire state space of the system. This can be done by constructing a new state space from the timeseries. One method that can do this is what is known as delay coordinates embedding or delay coordinates reconstruction.

The main functions to use for embedding some input data are embed or genembed. Both functions return a StateSpaceSet.

Timeseries embedding

DelayEmbeddings.embedFunction
embed(s, d, τ [, h])

Embed s using delay coordinates with embedding dimension d and delay time τ and return the result as a StateSpaceSet. Optionally use weight h, see below.

Here τ > 0, use genembed for a generalized version.

Description

If τ is an integer, then the $n$-th entry of the embedded space is

\[(s(n), s(n+\tau), s(n+2\tau), \dots, s(n+(d-1)\tau))\]

If instead τ is a vector of integers, so that length(τ) == d-1, then the $n$-th entry is

\[(s(n), s(n+\tau[1]), s(n+\tau[2]), \dots, s(n+\tau[d-1]))\]

The resulting set can have same invariant quantities (like e.g. Lyapunov exponents) with the original system that the timeseries were recorded from, for proper d and τ. This is known as the Takens embedding theorem [Takens1981] [Sauer1991]. The case of different delay times allows embedding systems with many time scales, see[Judd1998].

If provided, h can be weights to multiply the entries of the embedded space. If h isa Real then the embedding is

\[(s(n), h \cdot s(n+\tau), h^2 \cdot s(n+2\tau), \dots,h^{d-1} \cdot s(n+γ\tau))\]

Otherwise h can be a vector of length d-1, which the decides the weights of each entry directly.

References

[Takens1981] : F. Takens, Detecting Strange Attractors in Turbulence — Dynamical Systems and Turbulence, Lecture Notes in Mathematics 366, Springer (1981)

[Sauer1991] : T. Sauer et al., J. Stat. Phys. 65, pp 579 (1991)

source
Embedding discretized data values

If the data values are very strongly discretized (e.g., integers or floating-point numbers with very small bits), this can result to distances between points in the embedded space being 0. This is problematic for several library functions. Best practice here is to add noise to your original timeseries before embedding, e.g., s = s .+ 1e-15randn(length(s)).


Here are some examples of embedding a 3D continuous chaotic system:

using DelayEmbeddings

x = cos.(0:0.1:1)
11-element Vector{Float64}:
 1.0
 0.9950041652780258
 0.9800665778412416
 0.955336489125606
 0.9210609940028851
 0.8775825618903728
 0.8253356149096783
 0.7648421872844885
 0.6967067093471654
 0.6216099682706644
 0.5403023058681398
embed(x, 3, 1)
3-dimensional StateSpaceSet{Float64} with 9 points
 1.0       0.995004  0.980067
 0.995004  0.980067  0.955336
 0.980067  0.955336  0.921061
 0.955336  0.921061  0.877583
 0.921061  0.877583  0.825336
 0.877583  0.825336  0.764842
 0.825336  0.764842  0.696707
 0.764842  0.696707  0.62161
 0.696707  0.62161   0.540302
`τ` and `Δt`

Keep in mind that whether a value of τ is "reasonable" for continuous time systems depends on the sampling time Δt.

Embedding Structs

The high level function embed utilizes a low-level interface for creating embedded vectors on-the-fly. The high level interface simply loops over the low level interface.

DelayEmbeddings.DelayEmbeddingType
DelayEmbedding(γ, τ, h = nothing) → `embedding`

Return a delay coordinates embedding structure to be used as a function-like-object, given a timeseries and some index. Calling

embedding(s, n)

will create the n-th delay vector of the embedded space, which has γ temporal neighbors with delay(s) τ. γ is the embedding dimension minus 1, τ is the delay time(s) while h are extra weights, as in embed for more.

Be very careful when choosing n, because @inbounds is used internally. Use τrange!

source
DelayEmbeddings.τrangeFunction
τrange(s, de::AbstractEmbedding)

Return the range r of valid indices n to create delay vectors out of s using de.

source

Generalized embeddings

DelayEmbeddings.genembedFunction
genembed(s, τs, js = ones(...); ws = nothing) → ssset

Create a generalized embedding of s which can be a timeseries or arbitrary StateSpaceSet, and return the result as a new StateSpaceSet.

The generalized embedding works as follows:

  • τs denotes what delay times will be used for each of the entries of the delay vector. It is recommended that τs[1] = 0. τs is allowed to have negative entries as well.
  • js denotes which of the timeseries contained in s will be used for the entries of the delay vector. js can contain duplicate indices.
  • ws are optional weights that weight each embedded entry (the i-th entry of the delay vector is weighted by ws[i]). If provided, it is recommended that ws[1] == 1.

τs, js, ws are tuples (or vectors) of length D, which also coincides with the embedding dimension. For example, imagine input trajectory $s = [x, y, z]$ where $x, y, z$ are timeseries (the columns of the StateSpaceSet). If js = (1, 3, 2) and τs = (0, 2, -7) the created delay vector at each step $n$ will be

\[(x(n), z(n+2), y(n-7))\]

Using ws = (1, 0.5, 0.25) as well would create

\[(x(n), \frac{1}{2} z(n+2), \frac{1}{4} y(n-7))\]

js can be skipped, defaulting to index 1 (first timeseries) for all delay entries, while it has no effect if s is a timeseries instead of a StateSpaceSet.

See also embed. Internally uses GeneralizedEmbedding.

source
DelayEmbeddings.GeneralizedEmbeddingType
GeneralizedEmbedding(τs, js = ones(length(τs)), ws = nothing) -> `embedding`

Return a delay coordinates embedding structure to be used as a function. Given a timeseries or trajectory (i.e. StateSpaceSet) s and calling

embedding(s, n)

will create the delay vector of the n-th point of s in the embedded space using generalized embedding (see genembed).

js is ignored for timeseries input s (since all entries of js must be 1 in this case) and in addition js defaults to (1, ..., 1) for all τ.

Be very careful when choosing n, because @inbounds is used internally. Use τrange!

source

StateSpaceSet reference

StateSpaceSets.StateSpaceSetType
StateSpaceSet{D, T} <: AbstractStateSpaceSet{D,T}

A dedicated interface for sets in a state space. It is an ordered container of equally-sized points of length D. Each point is represented by SVector{D, T}. The data are a standard Julia Vector{SVector}, and can be obtained with vec(ssset::StateSpaceSet). Typically the order of points in the set is the time direction, but it doesn't have to be.

When indexed with 1 index, StateSpaceSet is like a vector of points. When indexed with 2 indices it behaves like a matrix that has each of the columns be the timeseries of each of the variables. When iterated over, it iterates over its contained points. See description of indexing below for more.

StateSpaceSet also supports almost all sensible vector operations like append!, push!, hcat, eachrow, among others.

Description of indexing

In the following let i, j be integers, typeof(X) <: AbstractStateSpaceSet and v1, v2 be <: AbstractVector{Int} (v1, v2 could also be ranges, and for performance benefits make v2 an SVector{Int}).

  • X[i] == X[i, :] gives the ith point (returns an SVector)
  • X[v1] == X[v1, :], returns a StateSpaceSet with the points in those indices.
  • X[:, j] gives the jth variable timeseries (or collection), as Vector
  • X[v1, v2], X[:, v2] returns a StateSpaceSet with the appropriate entries (first indices being "time"/point index, while second being variables)
  • X[i, j] value of the jth variable, at the ith timepoint

Use Matrix(ssset) or StateSpaceSet(matrix) to convert. It is assumed that each column of the matrix is one variable. If you have various timeseries vectors x, y, z, ... pass them like StateSpaceSet(x, y, z, ...). You can use columns(dataset) to obtain the reverse, i.e. all columns of the dataset in a tuple.