shepherd-data 2025.4.1__tar.gz → 2025.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/PKG-INFO +3 -4
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/pyproject.toml +7 -4
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data/__init__.py +1 -1
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data/cli.py +5 -6
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data/ivonne.py +13 -13
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data/mppt.py +3 -3
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data/reader.py +63 -45
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/PKG-INFO +3 -4
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/requires.txt +1 -1
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_ivonne.py +3 -3
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/README.md +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/setup.cfg +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/SOURCES.txt +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/dependency_links.txt +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/entry_points.txt +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/top_level.txt +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/zip-safe +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_downsample.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_extract.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_extract_gpio.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_extract_meta.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_extract_uart.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_plot.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_validate.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_cli_version.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_examples.py +0 -0
- {shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/tests/test_reader.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_data
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.5.2
|
|
4
4
|
Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
|
|
5
5
|
Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
@@ -18,7 +18,6 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
18
18
|
Classifier: Intended Audience :: Developers
|
|
19
19
|
Classifier: Intended Audience :: Information Technology
|
|
20
20
|
Classifier: Intended Audience :: Science/Research
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -27,7 +26,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
27
26
|
Classifier: License :: OSI Approved :: MIT License
|
|
28
27
|
Classifier: Operating System :: OS Independent
|
|
29
28
|
Classifier: Natural Language :: English
|
|
30
|
-
Requires-Python: >=3.
|
|
29
|
+
Requires-Python: >=3.9
|
|
31
30
|
Description-Content-Type: text/markdown
|
|
32
31
|
Requires-Dist: click
|
|
33
32
|
Requires-Dist: h5py
|
|
@@ -36,7 +35,7 @@ Requires-Dist: numpy
|
|
|
36
35
|
Requires-Dist: pandas>=2.0.0
|
|
37
36
|
Requires-Dist: pyYAML
|
|
38
37
|
Requires-Dist: scipy
|
|
39
|
-
Requires-Dist: shepherd-core[inventory]>=2025.
|
|
38
|
+
Requires-Dist: shepherd-core[inventory]>=2025.05.2
|
|
40
39
|
Requires-Dist: tqdm
|
|
41
40
|
Provides-Extra: elf
|
|
42
41
|
Requires-Dist: shepherd-core[elf]; extra == "elf"
|
|
@@ -18,7 +18,6 @@ classifiers = [
|
|
|
18
18
|
"Intended Audience :: Developers",
|
|
19
19
|
"Intended Audience :: Information Technology",
|
|
20
20
|
"Intended Audience :: Science/Research",
|
|
21
|
-
"Programming Language :: Python :: 3.8",
|
|
22
21
|
"Programming Language :: Python :: 3.9",
|
|
23
22
|
"Programming Language :: Python :: 3.10",
|
|
24
23
|
"Programming Language :: Python :: 3.11",
|
|
@@ -29,7 +28,7 @@ classifiers = [
|
|
|
29
28
|
"Natural Language :: English",
|
|
30
29
|
]
|
|
31
30
|
|
|
32
|
-
requires-python = ">=3.
|
|
31
|
+
requires-python = ">=3.9"
|
|
33
32
|
dependencies = [
|
|
34
33
|
"click",
|
|
35
34
|
"h5py",
|
|
@@ -38,7 +37,7 @@ dependencies = [
|
|
|
38
37
|
"pandas>=2.0.0", # full-version, v2 is OK
|
|
39
38
|
"pyYAML",
|
|
40
39
|
"scipy", # full-version
|
|
41
|
-
"shepherd-core[inventory]>=2025.
|
|
40
|
+
"shepherd-core[inventory]>=2025.05.2", # libs are strongly coupled
|
|
42
41
|
"tqdm", # full-version
|
|
43
42
|
]
|
|
44
43
|
|
|
@@ -101,6 +100,10 @@ addopts = "-vvv --stepwise" # opts: verbose result for each tests
|
|
|
101
100
|
source = ["shepherd_data"]
|
|
102
101
|
|
|
103
102
|
[tool.mypy]
|
|
104
|
-
python_version = 3.
|
|
103
|
+
python_version = 3.9
|
|
105
104
|
ignore_missing_imports = true
|
|
106
105
|
disable_error_code = ["call-arg", ]
|
|
106
|
+
exclude = [
|
|
107
|
+
"build/",
|
|
108
|
+
".egg-info/",
|
|
109
|
+
]
|
|
@@ -5,7 +5,6 @@ import sys
|
|
|
5
5
|
from contextlib import suppress
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import List
|
|
9
8
|
from typing import Optional
|
|
10
9
|
|
|
11
10
|
import click
|
|
@@ -21,7 +20,7 @@ from .reader import Reader
|
|
|
21
20
|
logger = logging.getLogger("SHPData.cli")
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
def path_to_flist(data_path: Path, *, recurse: bool = False) ->
|
|
23
|
+
def path_to_flist(data_path: Path, *, recurse: bool = False) -> list[Path]:
|
|
25
24
|
"""Every path gets transformed to a list of paths.
|
|
26
25
|
|
|
27
26
|
Transformations:
|
|
@@ -93,7 +92,7 @@ def validate(in_data: Path, *, recurse: bool = False) -> None:
|
|
|
93
92
|
sys.exit(int(not valid_dir))
|
|
94
93
|
|
|
95
94
|
|
|
96
|
-
@cli.command(short_help="Extracts recorded
|
|
95
|
+
@cli.command(short_help="Extracts recorded IVTrace and stores it to csv")
|
|
97
96
|
@click.argument("in_data", type=click.Path(exists=True, resolve_path=True))
|
|
98
97
|
@click.option(
|
|
99
98
|
"--start",
|
|
@@ -144,7 +143,7 @@ def extract(
|
|
|
144
143
|
raw: bool = False,
|
|
145
144
|
recurse: bool = False,
|
|
146
145
|
) -> None:
|
|
147
|
-
"""Extract recorded
|
|
146
|
+
"""Extract recorded IVTrace and store them to csv."""
|
|
148
147
|
files = path_to_flist(in_data, recurse=recurse)
|
|
149
148
|
verbose_level = get_verbose_level()
|
|
150
149
|
if not isinstance(ds_factor, (float, int)) or ds_factor < 1:
|
|
@@ -190,12 +189,12 @@ def extract_meta(in_data: Path, separator: str, *, recurse: bool = False) -> Non
|
|
|
190
189
|
with Reader(file, verbose=verbose_level > 2) as shpr:
|
|
191
190
|
shpr.save_metadata()
|
|
192
191
|
csvs_depr = ["sysutil", "timesync"]
|
|
193
|
-
csvs = ["ptp", "sys_util", "pru_util"]
|
|
192
|
+
csvs = ["ptp", "phc2sys", "sys_util", "pru_util"]
|
|
194
193
|
for element in csvs + csvs_depr:
|
|
195
194
|
if element in shpr.h5file:
|
|
196
195
|
shpr.save_csv(shpr[element], separator)
|
|
197
196
|
logs_depr = ["shepherd-log", "dmesg", "exceptions"]
|
|
198
|
-
logs = ["sheep", "kernel", "
|
|
197
|
+
logs = ["sheep", "kernel", "ntp", "uart"]
|
|
199
198
|
for element in logs + logs_depr:
|
|
200
199
|
if element in shpr.h5file:
|
|
201
200
|
shpr.save_log(shpr[element])
|
|
@@ -17,14 +17,14 @@ import pickle
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from types import TracebackType
|
|
19
19
|
from typing import Optional
|
|
20
|
-
from typing import Type
|
|
21
20
|
|
|
22
21
|
import numpy as np
|
|
23
22
|
import pandas as pd
|
|
24
23
|
from tqdm import trange
|
|
25
24
|
from typing_extensions import Self
|
|
26
25
|
|
|
27
|
-
from . import Writer
|
|
26
|
+
from shepherd_core.writer import Writer as CoreWriter
|
|
27
|
+
|
|
28
28
|
from .mppt import MPPTracker
|
|
29
29
|
from .mppt import OptimalTracker
|
|
30
30
|
from .mppt import iv_model
|
|
@@ -88,7 +88,7 @@ class Reader:
|
|
|
88
88
|
|
|
89
89
|
def __exit__(
|
|
90
90
|
self,
|
|
91
|
-
typ: Optional[
|
|
91
|
+
typ: Optional[type[BaseException]] = None,
|
|
92
92
|
exc: Optional[BaseException] = None,
|
|
93
93
|
tb: Optional[TracebackType] = None,
|
|
94
94
|
extra_arg: int = 0,
|
|
@@ -102,7 +102,7 @@ class Reader:
|
|
|
102
102
|
self.file_size = self.file_path.stat().st_size
|
|
103
103
|
self.data_rate = self.file_size / self.runtime_s if self.runtime_s > 0 else 0
|
|
104
104
|
|
|
105
|
-
def
|
|
105
|
+
def convert_2_ivsurface(
|
|
106
106
|
self,
|
|
107
107
|
shp_output: Path,
|
|
108
108
|
v_max: float = 5.0,
|
|
@@ -132,12 +132,14 @@ class Reader:
|
|
|
132
132
|
|
|
133
133
|
v_proto = np.linspace(0, v_max, pts_per_curve)
|
|
134
134
|
|
|
135
|
-
with
|
|
135
|
+
with CoreWriter(shp_output, datatype="ivcurve", window_samples=pts_per_curve) as sfw:
|
|
136
136
|
sfw.store_hostname("IVonne")
|
|
137
137
|
curve_interval_us = round(sfw.sample_interval_ns * pts_per_curve / 1000)
|
|
138
138
|
up_factor = self.sample_interval_ns // sfw.sample_interval_ns
|
|
139
139
|
max_elements = math.ceil(sfw.max_elements // up_factor)
|
|
140
|
-
job_iter = trange(
|
|
140
|
+
job_iter = trange(
|
|
141
|
+
0, df_elements_n, max_elements, desc="generate ivsurface", leave=False
|
|
142
|
+
)
|
|
141
143
|
|
|
142
144
|
for idx in job_iter:
|
|
143
145
|
idx_top = min(idx + max_elements, df_elements_n)
|
|
@@ -164,14 +166,14 @@ class Reader:
|
|
|
164
166
|
# - time can be generated and set as a whole
|
|
165
167
|
# - v_proto is repetitive, can also be set as a whole
|
|
166
168
|
|
|
167
|
-
def
|
|
169
|
+
def convert_2_ivtrace(
|
|
168
170
|
self,
|
|
169
171
|
shp_output: Path,
|
|
170
172
|
v_max: float = 5.0,
|
|
171
173
|
duration_s: Optional[float] = None,
|
|
172
174
|
tracker: Optional[MPPTracker] = None,
|
|
173
175
|
) -> None:
|
|
174
|
-
"""Transform shepherd IV curves to shepherd IV
|
|
176
|
+
"""Transform shepherd IV surface / curves to shepherd IV trace / samples .
|
|
175
177
|
|
|
176
178
|
For the 'buck' and 'buck-boost' modes, shepherd takes voltage and current traces.
|
|
177
179
|
These can be recorded with shepherd or generated from existing IV curves by, for
|
|
@@ -207,14 +209,12 @@ class Reader:
|
|
|
207
209
|
v_max,
|
|
208
210
|
)
|
|
209
211
|
|
|
210
|
-
with
|
|
212
|
+
with CoreWriter(shp_output, datatype="ivsample") as sfw:
|
|
211
213
|
sfw.store_hostname("IVonne")
|
|
212
214
|
interval_us = round(sfw.sample_interval_ns / 1000)
|
|
213
215
|
up_factor = self.sample_interval_ns // sfw.sample_interval_ns
|
|
214
216
|
max_elements = math.ceil(sfw.max_elements // up_factor)
|
|
215
|
-
job_iter = trange(
|
|
216
|
-
0, df_elements_n, max_elements, desc="generate ivsamples", leave=False
|
|
217
|
-
)
|
|
217
|
+
job_iter = trange(0, df_elements_n, max_elements, desc="generate ivtrace", leave=False)
|
|
218
218
|
|
|
219
219
|
for idx in job_iter:
|
|
220
220
|
# select (max_elements + 1) elements, so upsampling is without gaps
|
|
@@ -260,7 +260,7 @@ class Reader:
|
|
|
260
260
|
self._logger.info("File already exists, will skip '%s'", shp_output.name)
|
|
261
261
|
return
|
|
262
262
|
|
|
263
|
-
with
|
|
263
|
+
with CoreWriter(shp_output, datatype="isc_voc") as sfw:
|
|
264
264
|
sfw.store_hostname("IVonne")
|
|
265
265
|
interval_us = round(sfw.sample_interval_ns / 1000)
|
|
266
266
|
up_factor = self.sample_interval_ns // sfw.sample_interval_ns
|
|
@@ -56,7 +56,7 @@ class MPPTracker(ABC):
|
|
|
56
56
|
"""Apply harvesting model to input data.
|
|
57
57
|
|
|
58
58
|
:param coeffs: ivonne coefficients
|
|
59
|
-
:return:
|
|
59
|
+
:return: ivtrace-data
|
|
60
60
|
"""
|
|
61
61
|
|
|
62
62
|
|
|
@@ -76,7 +76,7 @@ class OpenCircuitTracker(MPPTracker):
|
|
|
76
76
|
"""Apply harvesting model to input data.
|
|
77
77
|
|
|
78
78
|
:param coeffs: ivonne coefficients
|
|
79
|
-
:return:
|
|
79
|
+
:return: ivtrace-data
|
|
80
80
|
"""
|
|
81
81
|
coeffs["icurve"] = coeffs.apply(lambda x: iv_model(self.v_proto, x), axis=1)
|
|
82
82
|
if "voc" not in coeffs.columns:
|
|
@@ -106,7 +106,7 @@ class OptimalTracker(MPPTracker):
|
|
|
106
106
|
"""Apply harvesting model to input data.
|
|
107
107
|
|
|
108
108
|
:param coeffs: ivonne coefficients
|
|
109
|
-
:return:
|
|
109
|
+
:return: ivtrace-data
|
|
110
110
|
"""
|
|
111
111
|
coeffs["icurve"] = coeffs.apply(lambda x: iv_model(self.v_proto, x), axis=1)
|
|
112
112
|
coeffs["pcurve"] = coeffs.apply(lambda x: self.v_proto * x["icurve"], axis=1)
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
"""Reader-Baseclass for opening shepherds hdf5-files."""
|
|
2
2
|
|
|
3
3
|
import math
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from collections.abc import Sequence
|
|
4
6
|
from datetime import datetime
|
|
5
7
|
from pathlib import Path
|
|
6
|
-
from typing import Dict
|
|
7
|
-
from typing import List
|
|
8
|
-
from typing import Mapping
|
|
9
8
|
from typing import Optional
|
|
10
|
-
from typing import Sequence
|
|
11
9
|
from typing import Union
|
|
12
10
|
|
|
13
11
|
import h5py
|
|
@@ -18,6 +16,7 @@ from tqdm import trange
|
|
|
18
16
|
from shepherd_core import Reader as CoreReader
|
|
19
17
|
from shepherd_core import Writer as CoreWriter
|
|
20
18
|
from shepherd_core import local_tz
|
|
19
|
+
from shepherd_core.data_models import EnergyDType
|
|
21
20
|
from shepherd_core.logger import get_verbose_level
|
|
22
21
|
from shepherd_core.logger import logger
|
|
23
22
|
|
|
@@ -36,9 +35,9 @@ class Reader(CoreReader):
|
|
|
36
35
|
|
|
37
36
|
def __init__(
|
|
38
37
|
self,
|
|
39
|
-
file_path:
|
|
38
|
+
file_path: Path,
|
|
40
39
|
*,
|
|
41
|
-
verbose:
|
|
40
|
+
verbose: bool = True,
|
|
42
41
|
) -> None:
|
|
43
42
|
super().__init__(file_path, verbose=verbose)
|
|
44
43
|
|
|
@@ -59,13 +58,13 @@ class Reader(CoreReader):
|
|
|
59
58
|
if csv_path.exists():
|
|
60
59
|
self._logger.info("File already exists, will skip '%s'", csv_path.name)
|
|
61
60
|
return 0
|
|
62
|
-
datasets:
|
|
61
|
+
datasets: list[str] = [
|
|
63
62
|
str(key) for key in h5_group if isinstance(h5_group[key], h5py.Dataset)
|
|
64
63
|
]
|
|
65
64
|
datasets.remove("time")
|
|
66
65
|
datasets = ["time", *datasets]
|
|
67
66
|
separator = separator.strip().ljust(2)
|
|
68
|
-
header_elements:
|
|
67
|
+
header_elements: list[str] = [
|
|
69
68
|
str(h5_group[key].attrs["description"]).replace(", ", separator) for key in datasets
|
|
70
69
|
]
|
|
71
70
|
header: str = separator.join(header_elements)
|
|
@@ -74,10 +73,10 @@ class Reader(CoreReader):
|
|
|
74
73
|
csv_file.write(header + "\n")
|
|
75
74
|
ts_gain = h5_group["time"].attrs.get("gain", 1e-9)
|
|
76
75
|
# for converting data to si - if raw=false
|
|
77
|
-
gains:
|
|
76
|
+
gains: dict[str, float] = {
|
|
78
77
|
key: h5_group[key].attrs.get("gain", 1.0) for key in datasets[1:]
|
|
79
78
|
}
|
|
80
|
-
offsets:
|
|
79
|
+
offsets: dict[str, float] = {
|
|
81
80
|
key: h5_group[key].attrs.get("offset", 1.0) for key in datasets[1:]
|
|
82
81
|
}
|
|
83
82
|
for idx, time_ns in enumerate(h5_group["time"][:]):
|
|
@@ -94,7 +93,7 @@ class Reader(CoreReader):
|
|
|
94
93
|
return h5_group["time"][:].shape[0]
|
|
95
94
|
|
|
96
95
|
def save_log(self, h5_group: h5py.Group, *, add_timestamp: bool = True) -> int:
|
|
97
|
-
"""Save dataset from
|
|
96
|
+
"""Save dataset from groups as log, optimal for logged kernel- and console-output.
|
|
98
97
|
|
|
99
98
|
:param h5_group: can be external
|
|
100
99
|
:param add_timestamp: can be external
|
|
@@ -177,7 +176,8 @@ class Reader(CoreReader):
|
|
|
177
176
|
) -> Union[None, h5py.Dataset, np.ndarray]:
|
|
178
177
|
"""Sample down iv-data.
|
|
179
178
|
|
|
180
|
-
Warning: only valid for IV-Stream, not IV-Curves
|
|
179
|
+
Warning: only valid for IV-Stream, not IV-Curves,
|
|
180
|
+
TODO: globally rename to IVTrace, IVSurface
|
|
181
181
|
|
|
182
182
|
:param data_src: a h5-dataset to digest, can be external
|
|
183
183
|
:param data_dst: can be a dataset, numpy-array or None (will be created internally then)
|
|
@@ -189,8 +189,8 @@ class Reader(CoreReader):
|
|
|
189
189
|
"""
|
|
190
190
|
from scipy import signal # here due to massive delay
|
|
191
191
|
|
|
192
|
-
if self.get_datatype() ==
|
|
193
|
-
self._logger.warning("Downsampling-Function was not written for
|
|
192
|
+
if self.get_datatype() == EnergyDType.ivsurface:
|
|
193
|
+
self._logger.warning("Downsampling-Function was not written for IVSurfaces")
|
|
194
194
|
ds_factor = max(1, math.floor(ds_factor))
|
|
195
195
|
|
|
196
196
|
if isinstance(end_n, (int, float)):
|
|
@@ -203,9 +203,9 @@ class Reader(CoreReader):
|
|
|
203
203
|
if data_len == 0:
|
|
204
204
|
self._logger.warning("downsampling failed because of data_len = 0")
|
|
205
205
|
return data_dst
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
iterations = math.ceil(data_len /
|
|
206
|
+
chunk_size_inp = min(self.max_elements, data_len)
|
|
207
|
+
chunk_size_out = round(chunk_size_inp / ds_factor)
|
|
208
|
+
iterations = math.ceil(data_len / chunk_size_inp)
|
|
209
209
|
dest_len = math.floor(data_len / ds_factor)
|
|
210
210
|
if data_dst is None:
|
|
211
211
|
data_dst = np.empty((dest_len,))
|
|
@@ -224,8 +224,13 @@ class Reader(CoreReader):
|
|
|
224
224
|
)
|
|
225
225
|
# filter state - needed for sliced calculation
|
|
226
226
|
f_state = np.zeros((filter_.shape[0], 2))
|
|
227
|
+
# prime the state to avoid starting from 0
|
|
228
|
+
if not is_time and ds_factor > 1:
|
|
229
|
+
slice_ds = data_src[start_n : start_n + self.CHUNK_SAMPLES_N]
|
|
230
|
+
slice_ds[:] = slice_ds[:].mean()
|
|
231
|
+
slice_ds, f_state = signal.sosfilt(filter_, slice_ds, zi=f_state)
|
|
227
232
|
|
|
228
|
-
|
|
233
|
+
output_pos = 0
|
|
229
234
|
for _iter in trange(
|
|
230
235
|
0,
|
|
231
236
|
iterations,
|
|
@@ -233,16 +238,22 @@ class Reader(CoreReader):
|
|
|
233
238
|
leave=False,
|
|
234
239
|
disable=iterations < 8,
|
|
235
240
|
):
|
|
236
|
-
slice_ds = data_src[
|
|
241
|
+
slice_ds = data_src[
|
|
242
|
+
start_n + _iter * chunk_size_inp : start_n + (_iter + 1) * chunk_size_inp
|
|
243
|
+
]
|
|
237
244
|
if not is_time and ds_factor > 1:
|
|
238
245
|
slice_ds, f_state = signal.sosfilt(filter_, slice_ds, zi=f_state)
|
|
239
246
|
slice_ds = slice_ds[::ds_factor]
|
|
240
|
-
slice_len = min(dest_len - _iter *
|
|
241
|
-
data_dst[
|
|
247
|
+
slice_len = min(dest_len - _iter * chunk_size_out, chunk_size_out, len(slice_ds))
|
|
248
|
+
data_dst[output_pos : output_pos + slice_len] = slice_ds[:slice_len]
|
|
249
|
+
# workaround to allow processing last slice (often smaller than expected),
|
|
250
|
+
# wanted: [_iter * chunk_size_out : (_iter + 1) * chunk_size_out]
|
|
251
|
+
# this prevents future parallel processing!
|
|
252
|
+
output_pos += slice_len
|
|
242
253
|
if isinstance(data_dst, np.ndarray):
|
|
243
|
-
data_dst.resize((
|
|
254
|
+
data_dst.resize((output_pos,), refcheck=False)
|
|
244
255
|
else:
|
|
245
|
-
data_dst.resize((
|
|
256
|
+
data_dst.resize((output_pos,))
|
|
246
257
|
return data_dst
|
|
247
258
|
|
|
248
259
|
def cut_and_downsample_to_file(
|
|
@@ -271,24 +282,20 @@ class Reader(CoreReader):
|
|
|
271
282
|
|
|
272
283
|
# test input-parameters
|
|
273
284
|
if end_sample < start_sample:
|
|
274
|
-
|
|
275
|
-
"Cut & downsample for
|
|
276
|
-
"end-mark (
|
|
277
|
-
self.file_path.name,
|
|
278
|
-
end_s,
|
|
279
|
-
start_s,
|
|
285
|
+
msg = (
|
|
286
|
+
f"Cut & downsample for {self.file_path.name} failed because "
|
|
287
|
+
f"end-mark ({end_s:.3f}) is before start-mark ({start_s:.3f})."
|
|
280
288
|
)
|
|
289
|
+
raise ValueError(msg)
|
|
281
290
|
if ds_factor < 1:
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
self.file_path.name,
|
|
285
|
-
)
|
|
291
|
+
msg = f"Cut & downsample for {self.file_path.name} failed because factor < 1"
|
|
292
|
+
raise ValueError(msg)
|
|
286
293
|
if ((end_sample - start_sample) / ds_factor) < 1000:
|
|
287
|
-
|
|
288
|
-
"Cut & downsample for
|
|
289
|
-
|
|
294
|
+
msg = (
|
|
295
|
+
f"Cut & downsample for {self.file_path.name} failed because "
|
|
296
|
+
f"resulting sample-size is too small",
|
|
290
297
|
)
|
|
291
|
-
|
|
298
|
+
raise ValueError(msg)
|
|
292
299
|
# assemble file-name of output
|
|
293
300
|
if start_s != 0.0 or end_s != self.runtime_s:
|
|
294
301
|
start_str = f"{start_s:.3f}".replace(".", "s")
|
|
@@ -372,8 +379,8 @@ class Reader(CoreReader):
|
|
|
372
379
|
:return: resampled iv-data
|
|
373
380
|
"""
|
|
374
381
|
self._logger.error("Resampling is still under construction - do not use for now!")
|
|
375
|
-
if self.get_datatype() ==
|
|
376
|
-
self._logger.warning("Resampling-Function was not written for
|
|
382
|
+
if self.get_datatype() == EnergyDType.ivsurface:
|
|
383
|
+
self._logger.warning("Resampling-Function was not written for IVSurfaces")
|
|
377
384
|
return data_dst
|
|
378
385
|
if isinstance(end_n, (int, float)):
|
|
379
386
|
_end_n = min(data_src.shape[0], round(end_n))
|
|
@@ -460,7 +467,7 @@ class Reader(CoreReader):
|
|
|
460
467
|
end_s: Optional[float] = None,
|
|
461
468
|
*,
|
|
462
469
|
relative_timestamp: bool = True,
|
|
463
|
-
) -> Optional[
|
|
470
|
+
) -> Optional[dict]:
|
|
464
471
|
"""Provide down-sampled iv-data that can be fed into plot_to_file().
|
|
465
472
|
|
|
466
473
|
:param start_s: time in seconds, relative to start of recording
|
|
@@ -468,8 +475,8 @@ class Reader(CoreReader):
|
|
|
468
475
|
:param relative_timestamp: treat
|
|
469
476
|
:return: down-sampled size of ~ self.max_elements
|
|
470
477
|
"""
|
|
471
|
-
if self.get_datatype() ==
|
|
472
|
-
self._logger.warning("Plot-Function was not written for
|
|
478
|
+
if self.get_datatype() == EnergyDType.ivsurface:
|
|
479
|
+
self._logger.warning("Plot-Function was not written for IVSurfaces.")
|
|
473
480
|
if not isinstance(start_s, (float, int)):
|
|
474
481
|
start_s = 0
|
|
475
482
|
if not isinstance(end_s, (float, int)):
|
|
@@ -538,11 +545,20 @@ class Reader(CoreReader):
|
|
|
538
545
|
# last axis is set below
|
|
539
546
|
|
|
540
547
|
for date in data:
|
|
548
|
+
samples_n = min(len(date["time"]), len(date["voltage"]), len(date["current"]))
|
|
541
549
|
if not only_pwr:
|
|
542
|
-
axs[0].plot(
|
|
543
|
-
|
|
550
|
+
axs[0].plot(
|
|
551
|
+
date["time"][:samples_n], date["voltage"][:samples_n], label=date["name"]
|
|
552
|
+
)
|
|
553
|
+
axs[1].plot(
|
|
554
|
+
date["time"][:samples_n],
|
|
555
|
+
date["current"][:samples_n] * 10**3,
|
|
556
|
+
label=date["name"],
|
|
557
|
+
)
|
|
544
558
|
axs[-1].plot(
|
|
545
|
-
date["time"]
|
|
559
|
+
date["time"][:samples_n],
|
|
560
|
+
date["voltage"][:samples_n] * date["current"][:samples_n] * 10**3,
|
|
561
|
+
label=date["name"],
|
|
546
562
|
)
|
|
547
563
|
|
|
548
564
|
if len(data) > 1:
|
|
@@ -553,6 +569,8 @@ class Reader(CoreReader):
|
|
|
553
569
|
# deactivates offset-creation for ax-ticks
|
|
554
570
|
ax.get_yaxis().get_major_formatter().set_useOffset(False)
|
|
555
571
|
ax.get_xaxis().get_major_formatter().set_useOffset(False)
|
|
572
|
+
# add a thin and light gray grid, TODO: add option to switch off?
|
|
573
|
+
ax.grid(color="0.8", linewidth=0.5)
|
|
556
574
|
return fig
|
|
557
575
|
|
|
558
576
|
def plot_to_file(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_data
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.5.2
|
|
4
4
|
Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
|
|
5
5
|
Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
@@ -18,7 +18,6 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
18
18
|
Classifier: Intended Audience :: Developers
|
|
19
19
|
Classifier: Intended Audience :: Information Technology
|
|
20
20
|
Classifier: Intended Audience :: Science/Research
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -27,7 +26,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
27
26
|
Classifier: License :: OSI Approved :: MIT License
|
|
28
27
|
Classifier: Operating System :: OS Independent
|
|
29
28
|
Classifier: Natural Language :: English
|
|
30
|
-
Requires-Python: >=3.
|
|
29
|
+
Requires-Python: >=3.9
|
|
31
30
|
Description-Content-Type: text/markdown
|
|
32
31
|
Requires-Dist: click
|
|
33
32
|
Requires-Dist: h5py
|
|
@@ -36,7 +35,7 @@ Requires-Dist: numpy
|
|
|
36
35
|
Requires-Dist: pandas>=2.0.0
|
|
37
36
|
Requires-Dist: pyYAML
|
|
38
37
|
Requires-Dist: scipy
|
|
39
|
-
Requires-Dist: shepherd-core[inventory]>=2025.
|
|
38
|
+
Requires-Dist: shepherd-core[inventory]>=2025.05.2
|
|
40
39
|
Requires-Dist: tqdm
|
|
41
40
|
Provides-Extra: elf
|
|
42
41
|
Requires-Dist: shepherd-core[elf]; extra == "elf"
|
|
@@ -23,13 +23,13 @@ def test_convert_ivonne(tmp_path: Path, example_path: Path) -> None:
|
|
|
23
23
|
|
|
24
24
|
with ivonne.Reader(inp_path) as ifr:
|
|
25
25
|
ifr.upsample_2_isc_voc(isc_path, duration_s=20)
|
|
26
|
-
ifr.
|
|
26
|
+
ifr.convert_2_ivsurface(ivc_path, duration_s=20)
|
|
27
27
|
|
|
28
28
|
tr_voc = mppt.OpenCircuitTracker(ratio=0.76)
|
|
29
29
|
tr_opt = mppt.OptimalTracker()
|
|
30
30
|
|
|
31
|
-
ifr.
|
|
32
|
-
ifr.
|
|
31
|
+
ifr.convert_2_ivtrace(voc_path, tracker=tr_voc, duration_s=20)
|
|
32
|
+
ifr.convert_2_ivtrace(opt_path, tracker=tr_opt, duration_s=20)
|
|
33
33
|
|
|
34
34
|
energies = {}
|
|
35
35
|
for file_path in [isc_path, ivc_path, voc_path, opt_path]:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{shepherd_data-2025.4.1 → shepherd_data-2025.5.2}/shepherd_data.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|