shepherd-data 2025.4.2__py3-none-any.whl → 2025.5.2__py3-none-any.whl

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/__init__.py CHANGED
@@ -11,7 +11,7 @@ from shepherd_core import Writer
11
11
 
12
12
  from .reader import Reader
13
13
 
14
- __version__ = "2025.04.2"
14
+ __version__ = "2025.05.2"
15
15
 
16
16
  __all__ = [
17
17
  "Reader",
shepherd_data/cli.py CHANGED
@@ -92,7 +92,7 @@ def validate(in_data: Path, *, recurse: bool = False) -> None:
92
92
  sys.exit(int(not valid_dir))
93
93
 
94
94
 
95
- @cli.command(short_help="Extracts recorded IVSamples and stores it to csv")
95
+ @cli.command(short_help="Extracts recorded IVTrace and stores it to csv")
96
96
  @click.argument("in_data", type=click.Path(exists=True, resolve_path=True))
97
97
  @click.option(
98
98
  "--start",
@@ -143,7 +143,7 @@ def extract(
143
143
  raw: bool = False,
144
144
  recurse: bool = False,
145
145
  ) -> None:
146
- """Extract recorded IVSamples and store them to csv."""
146
+ """Extract recorded IVTrace and store them to csv."""
147
147
  files = path_to_flist(in_data, recurse=recurse)
148
148
  verbose_level = get_verbose_level()
149
149
  if not isinstance(ds_factor, (float, int)) or ds_factor < 1:
@@ -189,12 +189,12 @@ def extract_meta(in_data: Path, separator: str, *, recurse: bool = False) -> Non
189
189
  with Reader(file, verbose=verbose_level > 2) as shpr:
190
190
  shpr.save_metadata()
191
191
  csvs_depr = ["sysutil", "timesync"]
192
- csvs = ["ptp", "sys_util", "pru_util"]
192
+ csvs = ["ptp", "phc2sys", "sys_util", "pru_util"]
193
193
  for element in csvs + csvs_depr:
194
194
  if element in shpr.h5file:
195
195
  shpr.save_csv(shpr[element], separator)
196
196
  logs_depr = ["shepherd-log", "dmesg", "exceptions"]
197
- logs = ["sheep", "kernel", "phc2sys", "uart"]
197
+ logs = ["sheep", "kernel", "ntp", "uart"]
198
198
  for element in logs + logs_depr:
199
199
  if element in shpr.h5file:
200
200
  shpr.save_log(shpr[element])
shepherd_data/ivonne.py CHANGED
@@ -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 convert_2_ivcurves(
105
+ def convert_2_ivsurface(
106
106
  self,
107
107
  shp_output: Path,
108
108
  v_max: float = 5.0,
@@ -137,7 +137,9 @@ class Reader:
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(0, df_elements_n, max_elements, desc="generate ivcurves", leave=False)
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 convert_2_ivsamples(
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 samples / traces.
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
@@ -212,9 +214,7 @@ class Reader:
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
shepherd_data/mppt.py CHANGED
@@ -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: ivsample-data
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: ivsample-data
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: ivsample-data
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)
shepherd_data/reader.py CHANGED
@@ -16,6 +16,7 @@ from tqdm import trange
16
16
  from shepherd_core import Reader as CoreReader
17
17
  from shepherd_core import Writer as CoreWriter
18
18
  from shepherd_core import local_tz
19
+ from shepherd_core.data_models import EnergyDType
19
20
  from shepherd_core.logger import get_verbose_level
20
21
  from shepherd_core.logger import logger
21
22
 
@@ -92,7 +93,7 @@ class Reader(CoreReader):
92
93
  return h5_group["time"][:].shape[0]
93
94
 
94
95
  def save_log(self, h5_group: h5py.Group, *, add_timestamp: bool = True) -> int:
95
- """Save dataset from group as log, optimal for logged 'dmesg' and console-output.
96
+ """Save dataset from groups as log, optimal for logged kernel- and console-output.
96
97
 
97
98
  :param h5_group: can be external
98
99
  :param add_timestamp: can be external
@@ -175,7 +176,8 @@ class Reader(CoreReader):
175
176
  ) -> Union[None, h5py.Dataset, np.ndarray]:
176
177
  """Sample down iv-data.
177
178
 
178
- 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
179
181
 
180
182
  :param data_src: a h5-dataset to digest, can be external
181
183
  :param data_dst: can be a dataset, numpy-array or None (will be created internally then)
@@ -187,8 +189,8 @@ class Reader(CoreReader):
187
189
  """
188
190
  from scipy import signal # here due to massive delay
189
191
 
190
- if self.get_datatype() == "ivcurve":
191
- self._logger.warning("Downsampling-Function was not written for IVCurves")
192
+ if self.get_datatype() == EnergyDType.ivsurface:
193
+ self._logger.warning("Downsampling-Function was not written for IVSurfaces")
192
194
  ds_factor = max(1, math.floor(ds_factor))
193
195
 
194
196
  if isinstance(end_n, (int, float)):
@@ -201,9 +203,9 @@ class Reader(CoreReader):
201
203
  if data_len == 0:
202
204
  self._logger.warning("downsampling failed because of data_len = 0")
203
205
  return data_dst
204
- iblock_len = min(self.max_elements, data_len)
205
- oblock_len = round(iblock_len / ds_factor)
206
- iterations = math.ceil(data_len / iblock_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)
207
209
  dest_len = math.floor(data_len / ds_factor)
208
210
  if data_dst is None:
209
211
  data_dst = np.empty((dest_len,))
@@ -222,8 +224,13 @@ class Reader(CoreReader):
222
224
  )
223
225
  # filter state - needed for sliced calculation
224
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)
225
232
 
226
- slice_len = 0
233
+ output_pos = 0
227
234
  for _iter in trange(
228
235
  0,
229
236
  iterations,
@@ -231,16 +238,22 @@ class Reader(CoreReader):
231
238
  leave=False,
232
239
  disable=iterations < 8,
233
240
  ):
234
- slice_ds = data_src[start_n + _iter * iblock_len : start_n + (_iter + 1) * iblock_len]
241
+ slice_ds = data_src[
242
+ start_n + _iter * chunk_size_inp : start_n + (_iter + 1) * chunk_size_inp
243
+ ]
235
244
  if not is_time and ds_factor > 1:
236
245
  slice_ds, f_state = signal.sosfilt(filter_, slice_ds, zi=f_state)
237
246
  slice_ds = slice_ds[::ds_factor]
238
- slice_len = min(dest_len - _iter * oblock_len, oblock_len)
239
- data_dst[_iter * oblock_len : (_iter + 1) * oblock_len] = slice_ds[:slice_len]
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
240
253
  if isinstance(data_dst, np.ndarray):
241
- data_dst.resize((oblock_len * (iterations - 1) + slice_len,), refcheck=False)
254
+ data_dst.resize((output_pos,), refcheck=False)
242
255
  else:
243
- data_dst.resize((oblock_len * (iterations - 1) + slice_len,))
256
+ data_dst.resize((output_pos,))
244
257
  return data_dst
245
258
 
246
259
  def cut_and_downsample_to_file(
@@ -269,24 +282,20 @@ class Reader(CoreReader):
269
282
 
270
283
  # test input-parameters
271
284
  if end_sample < start_sample:
272
- raise ValueError(
273
- "Cut & downsample for %s failed because "
274
- "end-mark (%.3f) is before start-mark (%.3f).",
275
- self.file_path.name,
276
- end_s,
277
- 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})."
278
288
  )
289
+ raise ValueError(msg)
279
290
  if ds_factor < 1:
280
- raise ValueError(
281
- "Cut & downsample for %s failed because factor < 1",
282
- self.file_path.name,
283
- )
291
+ msg = f"Cut & downsample for {self.file_path.name} failed because factor < 1"
292
+ raise ValueError(msg)
284
293
  if ((end_sample - start_sample) / ds_factor) < 1000:
285
- raise ValueError(
286
- "Cut & downsample for %s failed because resulting sample-size is too small",
287
- self.file_path.name,
294
+ msg = (
295
+ f"Cut & downsample for {self.file_path.name} failed because "
296
+ f"resulting sample-size is too small",
288
297
  )
289
-
298
+ raise ValueError(msg)
290
299
  # assemble file-name of output
291
300
  if start_s != 0.0 or end_s != self.runtime_s:
292
301
  start_str = f"{start_s:.3f}".replace(".", "s")
@@ -370,8 +379,8 @@ class Reader(CoreReader):
370
379
  :return: resampled iv-data
371
380
  """
372
381
  self._logger.error("Resampling is still under construction - do not use for now!")
373
- if self.get_datatype() == "ivcurve":
374
- self._logger.warning("Resampling-Function was not written for IVCurves")
382
+ if self.get_datatype() == EnergyDType.ivsurface:
383
+ self._logger.warning("Resampling-Function was not written for IVSurfaces")
375
384
  return data_dst
376
385
  if isinstance(end_n, (int, float)):
377
386
  _end_n = min(data_src.shape[0], round(end_n))
@@ -466,8 +475,8 @@ class Reader(CoreReader):
466
475
  :param relative_timestamp: treat
467
476
  :return: down-sampled size of ~ self.max_elements
468
477
  """
469
- if self.get_datatype() == "ivcurve":
470
- self._logger.warning("Plot-Function was not written for IVCurves.")
478
+ if self.get_datatype() == EnergyDType.ivsurface:
479
+ self._logger.warning("Plot-Function was not written for IVSurfaces.")
471
480
  if not isinstance(start_s, (float, int)):
472
481
  start_s = 0
473
482
  if not isinstance(end_s, (float, int)):
@@ -536,11 +545,20 @@ class Reader(CoreReader):
536
545
  # last axis is set below
537
546
 
538
547
  for date in data:
548
+ samples_n = min(len(date["time"]), len(date["voltage"]), len(date["current"]))
539
549
  if not only_pwr:
540
- axs[0].plot(date["time"], date["voltage"], label=date["name"])
541
- axs[1].plot(date["time"], date["current"] * 10**3, label=date["name"])
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
+ )
542
558
  axs[-1].plot(
543
- date["time"], date["voltage"] * date["current"] * 10**3, label=date["name"]
559
+ date["time"][:samples_n],
560
+ date["voltage"][:samples_n] * date["current"][:samples_n] * 10**3,
561
+ label=date["name"],
544
562
  )
545
563
 
546
564
  if len(data) > 1:
@@ -551,6 +569,8 @@ class Reader(CoreReader):
551
569
  # deactivates offset-creation for ax-ticks
552
570
  ax.get_yaxis().get_major_formatter().set_useOffset(False)
553
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)
554
574
  return fig
555
575
 
556
576
  def plot_to_file(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shepherd_data
3
- Version: 2025.4.2
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>
@@ -35,7 +35,7 @@ Requires-Dist: numpy
35
35
  Requires-Dist: pandas>=2.0.0
36
36
  Requires-Dist: pyYAML
37
37
  Requires-Dist: scipy
38
- Requires-Dist: shepherd-core[inventory]>=2025.04.2
38
+ Requires-Dist: shepherd-core[inventory]>=2025.05.2
39
39
  Requires-Dist: tqdm
40
40
  Provides-Extra: elf
41
41
  Requires-Dist: shepherd-core[elf]; extra == "elf"
@@ -0,0 +1,11 @@
1
+ shepherd_data/__init__.py,sha256=smoL-HtpycktcveBdkayEDG7aGF2n08SccXwK7yhYow,353
2
+ shepherd_data/cli.py,sha256=wunO1ZQktJ_-uTGVIfq-E-sD9nGJPYSAfw7Gw6dgXco,14740
3
+ shepherd_data/ivonne.py,sha256=sH7c2aj9i5ygkpw6xQbjRwrbl9wtU_Toj_ZFyJVywG8,11930
4
+ shepherd_data/mppt.py,sha256=y9gVIhMs-ZG3ScL9UQTc5n8T146B13Q5dA5sfqqfjg0,3999
5
+ shepherd_data/reader.py,sha256=LMHaLM8SKu8g8_CZOjZlQsOcOXkweP4cLPRf0dnJlhY,25735
6
+ shepherd_data-2025.5.2.dist-info/METADATA,sha256=ddL643nRP5_PT1qOe-p_Ir56XLM8CcG8YHe-13t_O2Q,3380
7
+ shepherd_data-2025.5.2.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
8
+ shepherd_data-2025.5.2.dist-info/entry_points.txt,sha256=6PBfY36A1xNOdzLiz-Qoukya_UzFZAwOapwmRNnPeZ8,56
9
+ shepherd_data-2025.5.2.dist-info/top_level.txt,sha256=7-SCTY-TG1mLY72OVKCaqte1hy-X8woxknIUAD3OIxs,14
10
+ shepherd_data-2025.5.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
+ shepherd_data-2025.5.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.1)
2
+ Generator: setuptools (80.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,11 +0,0 @@
1
- shepherd_data/__init__.py,sha256=y1kOe2aqvWM7s5JHNJemMxTbZn4k_X7XPCOvdFWJIsI,353
2
- shepherd_data/cli.py,sha256=ZrCFtWGXmfREux5a7XcdTEzmm7w4P0HMlURvVr_dkAw,14737
3
- shepherd_data/ivonne.py,sha256=TG0ATldv2nSFXAaHtfTZixH43pjSlIcohfXneZ9hOCU,11922
4
- shepherd_data/mppt.py,sha256=lBzcRttbqlsJLTHqofdx9vM6Yp8I_xNCEj9Ipsc-xY8,4002
5
- shepherd_data/reader.py,sha256=i7mGpqmaMfHVZ5n_GcUrEL-Z-aWKjAW0SLH05buSGjo,24610
6
- shepherd_data-2025.4.2.dist-info/METADATA,sha256=F-dwas6BCK7qXqBZhbFQGJLeS_xdp_9eVj7GCmIjiLg,3380
7
- shepherd_data-2025.4.2.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
8
- shepherd_data-2025.4.2.dist-info/entry_points.txt,sha256=6PBfY36A1xNOdzLiz-Qoukya_UzFZAwOapwmRNnPeZ8,56
9
- shepherd_data-2025.4.2.dist-info/top_level.txt,sha256=7-SCTY-TG1mLY72OVKCaqte1hy-X8woxknIUAD3OIxs,14
10
- shepherd_data-2025.4.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
- shepherd_data-2025.4.2.dist-info/RECORD,,