02 — Time series and resampling¶
Concept: a TimeSeries is one value per step of a grid, tagged with what it measures (kW, kWh, €/kWh or a dimensionless shape). Profiles are held as average power, which does not depend on the step, and resampling between any two grids conserves energy.
You will learn: how quantities combine, why power and energy resample differently, and what happens when a grid reaches outside the data.
from datetime import UTC, datetime, timedelta
import numpy as np
from myenergy.domain.errors import CoverageError, SeriesError
from myenergy.domain.series import Quantity, TimeSeries
from myenergy.domain.time import TimeGrid
start = datetime(2026, 1, 1, tzinfo=UTC)
quarter = TimeGrid(start=start, end=start + timedelta(hours=2), step=timedelta(minutes=15))
load = TimeSeries(
grid=quarter,
values=np.array([0.4, 0.4, 0.5, 2.1, 2.3, 0.6, 0.5, 0.4]),
quantity=Quantity.POWER_KW,
)
load.values, load.energy().total()
(array([0.4, 0.4, 0.5, 2.1, 2.3, 0.6, 0.5, 0.4]), 1.8)
Power (kW) times the step (h) gives energy (kWh): energy() does exactly that, and total() only exists for energy, because summing kW has no meaning.
try:
load.total()
except SeriesError as error:
print(error)
total() is for energy; use time_mean() for kW
Resampling¶
One overlap-weighted method serves every pair of steps. Power becomes a time-weighted mean; energy is summed or split in proportion to the overlap. Either way, the energy over the period is unchanged, even for steps that do not divide each other (15 → 20 minutes).
for minutes in (60, 20, 5):
other = load.resample(quarter.with_step(timedelta(minutes=minutes)))
print(
f"{minutes:>2} min: {len(other):>2} steps, "
f"{other.energy().total():.6f} kWh, mean {other.time_mean():.4f} kW"
)
60 min: 2 steps, 1.800000 kWh, mean 0.9000 kW 20 min: 6 steps, 1.800000 kWh, mean 0.9000 kW 5 min: 24 steps, 1.800000 kWh, mean 0.9000 kW
Going to a finer grid holds the power and splits the energy:
hourly = load.resample(quarter.with_step(timedelta(hours=1)))
hourly.values, hourly.resample(quarter).values
(array([0.85, 0.95]), array([0.85, 0.85, 0.85, 0.85, 0.95, 0.95, 0.95, 0.95]))
Outside the data: an error, never a guess¶
A grid that reaches beyond the series is refused with both ranges in the message (SPEC decision 9).
later = TimeGrid(
start=start + timedelta(hours=1), end=start + timedelta(hours=3), step=timedelta(minutes=15)
)
try:
load.resample(later)
except CoverageError as error:
print(error)
cannot resample to [2026-01-01T01:00:00+00:00, 2026-01-01T03:00:00+00:00): the series covers [2026-01-01T00:00:00+00:00, 2026-01-01T02:00:00+00:00)
Next: 03 — Load and PV profiles (with the next part of M1) turns Enedis shapes into kW series for a household and a solar array.