# Double ANN: SignalDecomposition.jl + TimeseriesSurrogates.jl

**URL:** https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072
**Category:** Package Announcements
**Tags:** package, announcement
**Created:** [May 24, 2020, 12:32pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072 "2020-05-24T12:32:26Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)
#### Post date: [May 24, 2020, 12:32pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/1 "2020-05-24T12:32:27Z")

</div>

Because I have been posting a lot of announcements lately, and because I don’t want people to start hating me for unending spam, I will announce **two** new packages in [JuliaDynamics](https://juliadynamics.github.io/JuliaDynamics/) in this post: SignalDecomposition.jl and TimeseriesSurrogates.jl ! Both packages provide tools about timeseries analysis and have a very common API and are in 1.0.

[SignalDecomposition.jl](https://github.com/JuliaDynamics/SignalDecomposition.jl) allows one to decompose an input signal/timeseries into basic components. This is used for example to _de-seasonalize_ a signal, or to do _noise-reduction_. [TimeseriesSurrogates.jl](https://github.com/JuliaDynamics/TimeseriesSurrogates.jl) is a package that creates surrogates. These are new timeseries created from the input timeseries that preserve some properties in the original timeseries and are used in hypothesis testing. Have a look at the docs for a more detailed information on surrogate timeseries!

Both packages have similar API: a function `surrogate(s, method)` or `decompose(s, method)` that makes surrogates / decomposes `s` via multiple dispatch on the `method`.

Hope they are useful!

---

<div class="post-metadata">

### Author: ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)
#### Post date: [May 24, 2020, 12:34pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/2 "2020-05-24T12:34:49Z")

</div>

Sweet animated logo 😃

---

<div class="post-metadata">

### Author: ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)
#### Post date: [May 24, 2020, 12:35pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/3 "2020-05-24T12:35:28Z")

</div>

It uses your method as well, so that should make you doubly happy 😉

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 24, 2020, 1:36pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/4 "2020-05-24T13:36:21Z")

</div>

> [@Datseris](#):
>
> for unending spam

for unending ~~spam~~ awesome packages.

---

<div class="post-metadata">

### Author: ![DoktorMike](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doktormike/32/2736_2.png) [@DoktorMike](https://discourse.julialang.org/u/DoktorMike)
#### Post date: [May 24, 2020, 3:59pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/5 "2020-05-24T15:59:31Z")

</div>

Very nice! 👍🏻🙏🏻

---

<div class="post-metadata">

### Author: ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)
#### Post date: [May 25, 2020, 2:19pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/6 "2020-05-25T14:19:14Z")

</div>

Nice! Thanks for the announcement.

---

<div class="post-metadata">

### Author: ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)
#### Post date: [May 25, 2020, 2:25pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/7 "2020-05-25T14:25:53Z")

</div>

@Balinus, I have actually done some extentions of SignalDecomposition.jl in my private code, because I use it for climate data. E.g. I made it work with date times better, and also dispatch on DimensionalArrays. Maybe you are interested to talk about this.

---

<div class="post-metadata">

### Author: ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)
#### Post date: [May 25, 2020, 2:30pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/8 "2020-05-25T14:30:19Z")

</div>

Absolutely! This is an important aspect of climate analysis and I’ll certainly add this dep in ClimateTools. 😀

---

<div class="post-metadata">

### Author: ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)
#### Post date: [July 25, 2025, 1:35pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/9 "2025-07-25T13:35:49Z")

</div>

SignalDecomposition.jl now has several different methods for detrending and/or smoothing: [Documentation · SignalDecomposition.jl](https://juliadynamics.github.io/SignalDecomposition.jl/stable/#Detrending-methods)

I also wanted to add a method based on Empirical Mode Decomposition, where a user specifies the first `n` modes to be taken as “trend” and the rest as residual. But I unfortunately didn’t find a codebase whose source code was explained enough in terms of what the keyword arguments mean. If anyone has a codebase that I can wrap or directly include in the repo I would appreciate it! The EMD method is broadly very useful.

---

<div class="post-metadata">

### Author: ![Fliks](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fliks/32/2494_2.png) [@Fliks](https://discourse.julialang.org/u/Fliks)
#### Post date: [July 26, 2025, 9:14pm UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/10 "2025-07-26T21:14:46Z")

</div>

I implemented EMD a few years ago and could look into reviving the package. Then we could wrap it in SignalDecomposition.jl

---

<div class="post-metadata">

### Author: ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)
#### Post date: [July 28, 2025, 9:52am UTC](https://discourse.julialang.org/t/double-ann-signaldecomposition-jl-timeseriessurrogates-jl/40072/11 "2025-07-28T09:52:07Z")

</div>

Hi Felix, yes this sounds good. We are in fact using your codebase in a project with a student that gave birth to these new detrending methods (most of them are wraps). We are using your EMD code, but I felt that the codebase is not at a state that it can be wrapped in a registered package, so we left this method out of the online version. For me primarily the problem was understanding which entries in the returned vector are which modes, which modes have the most variance, and why the vector of modes returned has always an extra vector that is just zeros. If you are happy to update the codebase with docs regarding the keyword arguments and output type that would be great. The way I think of it is I’d like an EMD method that has two options: specify how many modes to decompose to, or specify an insignificance threshold for decomposition that when the last mode exceeds this threshold then the decomposition stops. I think in some papers people use an “explained variance” threshold. Then in SignalDecomposition.jl the user would specify what method to use to create the modes, and how many modes to keep as the “trend”. The rest become the residual.
