Skip to main content

Combining signals

In this tutorial, you'll learn how to combine signals and how to perform scalar operations.

As a reminder, timeseries are often expressed as a combination of 3 components: trend, seasonality and noise. If the interaction is additive the formula is: yt=St+Tt+Nty_t = S_t + T_t + N_t, with StS_t the seasonal component, TtT_t the trend-cycle component and NtN_t the Noise component, at period tt.
Alternatively, if the interaction is multiplicative, the relation is: yt=Stโˆ—Ttโˆ—Nty_t = S_t * T_t * N_t.

The point is: to combine signals, you add or multiply them.
It's easy in mockseries: just use the standard operators + and * !
You can write complex signals mixing additive and multiplicative interactions, such as:

yt=noiseโˆ—(flat_trend+(seasonal_1โˆ—linear_trend)+seasonal_2)y_t = noise * (flat\_trend + (seasonal\_1 * linear\_trend) + seasonal\_2)

Simple examples#

Lets add a linear trend and a sinusoidal signal:

# matplotlib config for whole tutorial
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (20,7)
from datetime import timedelta
from mockseries.trend import LinearTrend
from mockseries.seasonality import SinusoidalSeasonality
linear_trend = LinearTrend(coefficient=2, time_unit=timedelta(days=1))
seasonality = SinusoidalSeasonality(amplitude=2, period=timedelta(hours=12))
additive_timeseries = linear_trend + seasonality
# quick preview function !
additive_timeseries.preview_week()

png

Now if we multiply them:

multiplicative_timeseries = linear_trend * seasonality
multiplicative_timeseries.preview_week()

png

Complex example#

Let's implement the example in the introduction:
yt=noiseโˆ—(flat_trend+(seasonal_1โˆ—linear_trend)+seasonal_2)y_t = noise * (flat\_trend + (seasonal\_1 * linear\_trend) + seasonal\_2).

To give more context, it could represent something like the temperature on Earth:

  • the temperature has an average value (flat_trendflat\_trend)
  • the temperature is rising linear_trendlinear\_trend
  • the yearly pattern seasonal_1seasonal\_1 is multiplicative with the trend: this means global warming results in bigger yearly patterns
  • the daily pattern is additive: it's not impacted by the trend.
  • a noise is multiplicative by all of the above: this means it tends to get bigger when temperatures are bigger

NB: This model is an un-documented simulation, it is not linked to any research and is obviously incorrect.
NB: For the sake of simplicity, we'll use sinusoidal signals for seasonalities. Check out the next tutorial for more realistic patterns !

from mockseries.trend import FlatTrend
from mockseries.noise import GaussianNoise
noise = GaussianNoise(mean=1, std=0.05)
average = FlatTrend(12)
warming = LinearTrend(0.1, timedelta(days=365.25), flat_base=1)
yearly_seasonality = SinusoidalSeasonality(amplitude=15, period=timedelta(days=365.25))
daily_seasonality = SinusoidalSeasonality(amplitude=5, period=timedelta(days=1))
temperature = noise * ( average + (warming * yearly_seasonality) + daily_seasonality)
temperature.preview_year(num_years=4)

png

Scalars operations:#

mockseries also supports simple scalar operations:

  • negate a signal: -my_signal
  • add a constant to a signal: 3 + my_signal
  • multiply a signal: 3 * my_signal
# negate a signal:
from datetime import datetime
from mockseries.utils.dates import datetime_range
from mockseries.utils.plot import plot_timeseries
one_week_index = datetime_range(
granularity=timedelta(hours=1),
start_time=datetime(2021, 8, 23),
end_time=datetime(2021, 8, 23) + timedelta(days=7),
)
trend = LinearTrend(coefficient=3, time_unit=timedelta(days=1))
negated_trend = -trend
plot_timeseries(
one_week_index,
[trend.generate(one_week_index), negated_trend.generate(one_week_index)]
)

png

# add a constant to a signal
sinusoid = SinusoidalSeasonality(1, timedelta(days=1))
sinusoid_plus_three = 3 + sinusoid
plot_timeseries(
one_week_index,
[sinusoid.generate(one_week_index),sinusoid_plus_three.generate(one_week_index)]
)

png

# multiply a signal
sinusoid = SinusoidalSeasonality(1, timedelta(days=1))
sinusoid_times_three = 3 * sinusoid
plot_timeseries(
one_week_index,
[sinusoid.generate(one_week_index),sinusoid_times_three.generate(one_week_index)]
)

png

You're now able to combine timeseries and use scalar broadcasting!
You should be able to build all kinds of timeseries with this simple primitives.

Go to the next page to learn how to create periodic signals based on (time, value) constraints. This is helpful when you simulate real life timeseries.