Source code for energy_analysis_toolbox.timeseries.resample.interpolate

"""Apply basic maths transformations to be applied to timeseries of physical values.

This module defines utilities used to create fine-sampled timeseries from
coarse sampled one:

    - :py:func:`piecewise_affine`
    - :py:func:`piecewise_constant`

Resampling to coarser resolution may be done as well, but the relevance may
be questioned VS a well-chosen aggregation.

.. seealso:: In case the series to be resampled must satisfy conservation laws

    :py:mod:`energy_analysis_toolbox.timeseries.power.conservative`

"""

import numpy as np
import pandas as pd


[docs] def piecewise_affine( timeseries: pd.Series | float, target_instants: pd.DatetimeIndex, ) -> pd.Series: """Return resampled timeseries assuming a piecewise affine function of time. Parameters ---------- timeseries : pd.Series or float Series of values of a function of time, indexed using DateTimeIndex. target_instants : pd.DatetimeIndex Dates at which the series values are required, sorted in ascending order. Returns ------- new_series : pd.Series Values of the function, interpolated at target times, indexed with ``target_instants``. .. warning:: The returned values may not be relevant when some target times are required outside the convex span of the input samples: the corresponding border value is used for these target times. .. seealso:: :py:func:`np.interp` on which the interpolation is based. """ try: ref_time = target_instants[0] except IndexError: return pd.Series([], dtype=timeseries.dtype, index=target_instants.copy()) target_offsets = (target_instants - ref_time).total_seconds() sample_dts = (timeseries.index - ref_time).total_seconds() new_values = np.interp(target_offsets, sample_dts, timeseries.values) new_series = pd.Series( new_values, index=target_instants.copy(), name=timeseries.name, ) new_series.index.name = timeseries.index.name return new_series
[docs] def piecewise_constant( timeseries: pd.Series, target_instants: pd.DatetimeIndex, left_pad: float | None = None, ) -> pd.Series: """Return resampled timeseries assuming a piecewise constant function of time. Parameters ---------- timeseries : pd.Series or float Series of values of a function of time, indexed using DateTimeIndex. target_instants : pd.DatetimeIndex A sequence of target timestamps, sorted in ascending order. left_pad : float or None, optional A value to be used for target instants which are located before the first instant in ``timeseries``. The default is |None| in which case, the value of the first instant is used. Returns ------- new_series : pd.Series Values of the series interpolated at target times, indexed with ``target_instants``. .. seealso:: :py:func:`np.digitize` on which the function is based. """ try: ref_time = target_instants[0] except IndexError: return pd.Series([], dtype=timeseries.dtype, index=target_instants.copy()) target_offsets = (target_instants - ref_time).total_seconds() sample_dts = (timeseries.index - ref_time).total_seconds() ix_select = np.digitize(target_offsets, sample_dts, right=False) - 1 if left_pad is None: ix_select[ix_select < 0] = 0 # index 0 new_values = timeseries.iloc[ix_select].to_numpy() else: new_values = timeseries.iloc[ix_select].to_numpy() new_values[ix_select < 0] = left_pad new_series = pd.Series(new_values, index=target_instants, name=timeseries.name) new_series.index.name = timeseries.index.name return new_series