-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtime_utils.py
More file actions
62 lines (50 loc) · 2.5 KB
/
time_utils.py
File metadata and controls
62 lines (50 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
"""Time conversion and formatting for reports and plots."""
import datetime
from typing import Tuple, Optional
import numpy as np
def timestamp_str() -> str:
"""Return current local time as 'YYYY-MM-DD HH:MM:SS' for reports and logs."""
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def seconds_to_datetime(seconds: float) -> datetime.datetime:
"""Elapsed seconds since epoch -> timezone-naive datetime (for Plotly/pandas)."""
return datetime.datetime.fromtimestamp(0) + datetime.timedelta(seconds=seconds)
# ─────────────────────────────────────────────────────────────────────────────
# Standardized dense time raster (dt=0.05s)
# ─────────────────────────────────────────────────────────────────────────────
STANDARD_DT_SEC = 0.05
def dense_time_grid(duration_sec: float, dt_sec: float = STANDARD_DT_SEC) -> np.ndarray:
"""Return a dense time grid [0, duration] with step dt_sec."""
dur = float(duration_sec)
dt = float(dt_sec)
if not np.isfinite(dur) or dur <= 0:
return np.asarray([], dtype=np.float64)
if not np.isfinite(dt) or dt <= 0:
dt = STANDARD_DT_SEC
return np.arange(0.0, dur + 1e-12, dt, dtype=np.float64)
def rasterize_timeseries_linear(
t_data: np.ndarray,
y_data: np.ndarray,
t_grid: np.ndarray,
*,
fallback: Optional[float] = None,
) -> np.ndarray:
"""
Linear interpolation of irregular samples onto a dense grid with constant edge extrapolation.
If fallback is provided, non-finite outputs are replaced with it.
"""
t_data = np.asarray(t_data, dtype=np.float64)
y_data = np.asarray(y_data, dtype=np.float64)
t_grid = np.asarray(t_grid, dtype=np.float64)
if len(t_grid) == 0:
return np.asarray([], dtype=np.float64)
if len(t_data) < 2 or len(t_data) != len(y_data):
if fallback is None:
return np.full_like(t_grid, np.nan, dtype=np.float64)
return np.full_like(t_grid, float(fallback), dtype=np.float64)
order = np.argsort(t_data)
t = t_data[order]
y = y_data[order]
out = np.interp(t_grid, t, y, left=float(y[0]), right=float(y[-1])).astype(np.float64)
if fallback is not None:
out[~np.isfinite(out)] = float(fallback)
return out