shepherd-core 2025.8.1__py3-none-any.whl → 2026.2.1__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.
Files changed (82) hide show
  1. shepherd_core/config.py +1 -1
  2. shepherd_core/data_models/__init__.py +8 -4
  3. shepherd_core/data_models/base/cal_measurement.py +7 -2
  4. shepherd_core/data_models/base/calibration.py +23 -12
  5. shepherd_core/data_models/base/content.py +12 -2
  6. shepherd_core/data_models/base/shepherd.py +13 -4
  7. shepherd_core/data_models/base/wrapper.py +2 -0
  8. shepherd_core/data_models/content/__init__.py +8 -4
  9. shepherd_core/data_models/content/_external_fixtures.yaml +104 -96
  10. shepherd_core/data_models/content/_metadata_eenvs_bonito.yaml +436 -0
  11. shepherd_core/data_models/content/_metadata_eenvs_synthetic_multivariate_random_walk.yaml +164 -0
  12. shepherd_core/data_models/content/_metadata_eenvs_synthetic_on_off_markov.yaml +3280 -0
  13. shepherd_core/data_models/content/_metadata_eenvs_synthetic_on_off_windows.yaml +3260 -0
  14. shepherd_core/data_models/content/_metadata_eenvs_synthetic_static.yaml +450 -0
  15. shepherd_core/data_models/content/energy_environment.py +341 -23
  16. shepherd_core/data_models/content/energy_environment_fixture.yaml +21 -18
  17. shepherd_core/data_models/content/enum_datatypes.py +109 -0
  18. shepherd_core/data_models/content/firmware.py +44 -16
  19. shepherd_core/data_models/content/{virtual_harvester.py → virtual_harvester_config.py} +13 -96
  20. shepherd_core/data_models/content/{virtual_source.py → virtual_source_config.py} +103 -60
  21. shepherd_core/data_models/content/virtual_source_fixture.yaml +24 -24
  22. shepherd_core/data_models/content/virtual_storage_config.py +429 -0
  23. shepherd_core/data_models/content/virtual_storage_fixture_creator.py +267 -0
  24. shepherd_core/data_models/content/virtual_storage_fixture_ideal.yaml +637 -0
  25. shepherd_core/data_models/content/virtual_storage_fixture_lead.yaml +49 -0
  26. shepherd_core/data_models/content/virtual_storage_fixture_lipo.yaml +735 -0
  27. shepherd_core/data_models/content/virtual_storage_fixture_mlcc.yaml +200 -0
  28. shepherd_core/data_models/content/virtual_storage_fixture_param_experiments.py +151 -0
  29. shepherd_core/data_models/content/virtual_storage_fixture_super.yaml +150 -0
  30. shepherd_core/data_models/content/virtual_storage_fixture_tantal.yaml +550 -0
  31. shepherd_core/data_models/experiment/experiment.py +38 -13
  32. shepherd_core/data_models/experiment/observer_features.py +17 -4
  33. shepherd_core/data_models/experiment/target_config.py +56 -8
  34. shepherd_core/data_models/task/__init__.py +13 -2
  35. shepherd_core/data_models/task/emulation.py +10 -6
  36. shepherd_core/data_models/task/firmware_mod.py +3 -1
  37. shepherd_core/data_models/task/harvest.py +3 -1
  38. shepherd_core/data_models/task/helper_paths.py +2 -2
  39. shepherd_core/data_models/task/observer_tasks.py +8 -6
  40. shepherd_core/data_models/task/programming.py +4 -2
  41. shepherd_core/data_models/task/testbed_tasks.py +8 -2
  42. shepherd_core/data_models/testbed/cape.py +2 -0
  43. shepherd_core/data_models/testbed/gpio.py +2 -0
  44. shepherd_core/data_models/testbed/mcu.py +2 -0
  45. shepherd_core/data_models/testbed/observer.py +2 -0
  46. shepherd_core/data_models/testbed/target.py +7 -5
  47. shepherd_core/data_models/testbed/target_fixture.old1 +1 -1
  48. shepherd_core/data_models/testbed/target_fixture.yaml +1 -1
  49. shepherd_core/data_models/testbed/testbed.py +17 -15
  50. shepherd_core/decoder_waveform/uart.py +1 -1
  51. shepherd_core/exit_handler.py +22 -0
  52. shepherd_core/fw_tools/converter.py +2 -2
  53. shepherd_core/fw_tools/validation.py +1 -1
  54. shepherd_core/inventory/__init__.py +23 -21
  55. shepherd_core/inventory/system.py +3 -3
  56. shepherd_core/logger.py +0 -1
  57. shepherd_core/reader.py +32 -27
  58. shepherd_core/testbed_client/cache_path.py +3 -3
  59. shepherd_core/testbed_client/client_abc_fix.py +14 -3
  60. shepherd_core/testbed_client/client_web.py +7 -5
  61. shepherd_core/testbed_client/fixtures.py +7 -7
  62. shepherd_core/version.py +1 -1
  63. shepherd_core/vsource/__init__.py +4 -0
  64. shepherd_core/vsource/virtual_converter_model.py +29 -28
  65. shepherd_core/vsource/virtual_harvester_model.py +29 -21
  66. shepherd_core/vsource/virtual_harvester_simulation.py +38 -39
  67. shepherd_core/vsource/virtual_source_model.py +18 -14
  68. shepherd_core/vsource/virtual_source_simulation.py +71 -73
  69. shepherd_core/vsource/virtual_storage_model.py +164 -0
  70. shepherd_core/vsource/virtual_storage_model_fixed_point_math.py +58 -0
  71. shepherd_core/vsource/virtual_storage_models_kibam.py +449 -0
  72. shepherd_core/vsource/virtual_storage_simulator.py +104 -0
  73. shepherd_core/writer.py +16 -9
  74. {shepherd_core-2025.8.1.dist-info → shepherd_core-2026.2.1.dist-info}/METADATA +6 -3
  75. shepherd_core-2026.2.1.dist-info/RECORD +102 -0
  76. {shepherd_core-2025.8.1.dist-info → shepherd_core-2026.2.1.dist-info}/WHEEL +1 -1
  77. shepherd_core-2026.2.1.dist-info/licenses/LICENSE +21 -0
  78. shepherd_core/data_models/content/firmware_datatype.py +0 -15
  79. shepherd_core/data_models/virtual_source_doc.txt +0 -207
  80. shepherd_core-2025.8.1.dist-info/RECORD +0 -83
  81. {shepherd_core-2025.8.1.dist-info → shepherd_core-2026.2.1.dist-info}/top_level.txt +0 -0
  82. {shepherd_core-2025.8.1.dist-info → shepherd_core-2026.2.1.dist-info}/zip-safe +0 -0
@@ -0,0 +1,267 @@
1
+ """Script for generating YAML-fixture for virtual storage."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ import yaml
7
+ from virtual_storage_config import VirtualStorageConfig
8
+
9
+ from shepherd_core import local_now
10
+ from shepherd_core.data_models import Wrapper
11
+ from shepherd_core.logger import log
12
+
13
+ dsc_ideal = "Model of an ideal Capacitor (true to spec, no losses)"
14
+ dsc_tantal = "Tantal-Capacitor similar to ideal Model, but with R_leak & R_series"
15
+ dsc_mlcc = "MLCC-Capacitor with R_leak & R_series and planned DC-Bias-Effect"
16
+ dsc_super = "SuperCapacitor with typically 1000 hours / 500 k cycles (not modeled)"
17
+
18
+ # Ideal Capacitor, E6 row 10 to 1000 uF
19
+ # typical voltage-ratings: 2.5, 4.0, 6.3, 10, 16, 20 V
20
+ E6: list[int] = [10, 15, 22, 33, 47, 68, 100, 150, 220, 330, 470, 680, 1000]
21
+ fixture_ideal: list[VirtualStorageConfig] = [
22
+ VirtualStorageConfig.capacitor(C_uF=v_, V_rated=10.0, description=dsc_ideal) for v_ in E6
23
+ ]
24
+
25
+ # Tantal Capacitors, E6 row
26
+ # ⤷ verified with AVX TAJB107M006RNJ
27
+ # - Tantal, 100 uF, 6V3, 20%, 1411 package -> 100 uF measured
28
+ # - R_series taken from Datasheet
29
+ # - R_leak = 1 MOhm in datasheet (6.3V/6.3uA), but ~2 MOhm in experiment
30
+ # see https://github.com/orgua/bq_characteristics/tree/main/eval_kit_behavior_var1#capacitor
31
+ fixture_tantal: list[VirtualStorageConfig] = [
32
+ VirtualStorageConfig.capacitor(
33
+ C_uF=10,
34
+ V_rated=6.3,
35
+ R_leak_Ohm=196e6 / 10,
36
+ R_series_Ohm=3.0,
37
+ name="AVX TAJB106x006", # Note: small x is * in datasheet
38
+ description=dsc_tantal,
39
+ ),
40
+ VirtualStorageConfig.capacitor(
41
+ C_uF=15,
42
+ V_rated=6.3,
43
+ R_leak_Ohm=196e6 / 15,
44
+ R_series_Ohm=2.0,
45
+ name="AVX TAJB156x006",
46
+ description=dsc_tantal,
47
+ ),
48
+ VirtualStorageConfig.capacitor(
49
+ C_uF=22,
50
+ V_rated=6.3,
51
+ R_leak_Ohm=196e6 / 22,
52
+ R_series_Ohm=2.5,
53
+ name="AVX TAJB226x006",
54
+ description=dsc_tantal,
55
+ ),
56
+ VirtualStorageConfig.capacitor(
57
+ C_uF=33,
58
+ V_rated=6.3,
59
+ R_leak_Ohm=196e6 / 33,
60
+ R_series_Ohm=2.2,
61
+ name="AVX TAJB336x006",
62
+ description=dsc_tantal,
63
+ ),
64
+ VirtualStorageConfig.capacitor(
65
+ C_uF=47,
66
+ V_rated=6.3,
67
+ R_leak_Ohm=196e6 / 47,
68
+ R_series_Ohm=2,
69
+ name="AVX TAJB476x006",
70
+ description=dsc_tantal,
71
+ ),
72
+ VirtualStorageConfig.capacitor(
73
+ C_uF=68,
74
+ V_rated=6.3,
75
+ R_leak_Ohm=196e6 / 68,
76
+ R_series_Ohm=0.9,
77
+ name="AVX TAJB686x006",
78
+ description=dsc_tantal,
79
+ ),
80
+ VirtualStorageConfig.capacitor(
81
+ C_uF=100,
82
+ V_rated=6.3,
83
+ R_leak_Ohm=196e6 / 100,
84
+ R_series_Ohm=1.7,
85
+ name="AVX TAJB107x006",
86
+ description=dsc_tantal,
87
+ ),
88
+ VirtualStorageConfig.capacitor(
89
+ C_uF=150,
90
+ V_rated=6.3,
91
+ R_leak_Ohm=196e6 / 150,
92
+ R_series_Ohm=1.3,
93
+ name="AVX TAJC157x006",
94
+ description=dsc_tantal,
95
+ ),
96
+ VirtualStorageConfig.capacitor(
97
+ C_uF=220,
98
+ V_rated=6.3,
99
+ R_leak_Ohm=196e6 / 220,
100
+ R_series_Ohm=1.2,
101
+ name="AVX TAJC227x006",
102
+ description=dsc_tantal,
103
+ ),
104
+ VirtualStorageConfig.capacitor(
105
+ C_uF=330,
106
+ V_rated=6.3,
107
+ R_leak_Ohm=196e6 / 330,
108
+ R_series_Ohm=0.5,
109
+ name="AVX TAJC337x006",
110
+ description=dsc_tantal,
111
+ ),
112
+ VirtualStorageConfig.capacitor(
113
+ C_uF=470,
114
+ V_rated=6.3,
115
+ R_leak_Ohm=196e6 / 470,
116
+ R_series_Ohm=0.4,
117
+ name="AVX TAJD477x006",
118
+ description=dsc_tantal,
119
+ ),
120
+ ]
121
+
122
+ # MLCC
123
+ # ⤷ verified with Taiyo Yuden JMK316ABJ107ML-T
124
+ # - MLCC, 100uF, 6V3, 20%, X5R, 1206 package -> 74 uF measured
125
+ # - Insulation Resistance (min) 100 MΩ·μF (datasheet), 97.8 MΩ measured
126
+ # https://github.com/orgua/bq_characteristics/tree/main/eval_kit_behavior_var1/data_capacitor
127
+ # BQ25570EVM uses Murata GRM43SR60J107ME20L
128
+ # - MLCC, 100uF, 6V3, 20%, X5R, 1812 package -> 79 uF measured
129
+ # - murata-DB does not know this part, but direct substitute is GRM31CR60J107MEA8
130
+ # https://pim.murata.com/en-global/pim/details/?partNum=GRM31CR60J107MEA8%23
131
+ # TODO: add DC-Bias
132
+ fixture_mlcc: list[VirtualStorageConfig] = [
133
+ VirtualStorageConfig.capacitor(
134
+ C_uF=10, V_rated=6.3, R_leak_Ohm=97.8e6 / 10, description=dsc_mlcc
135
+ ),
136
+ VirtualStorageConfig.capacitor(
137
+ C_uF=33, V_rated=6.3, R_leak_Ohm=97.8e6 / 33, description=dsc_mlcc
138
+ ),
139
+ VirtualStorageConfig.capacitor(
140
+ C_uF=47, V_rated=6.3, R_leak_Ohm=97.8e6 / 47, description=dsc_mlcc
141
+ ),
142
+ VirtualStorageConfig.capacitor(
143
+ C_uF=100, V_rated=6.3, R_leak_Ohm=97.8e6 / 100, description=dsc_mlcc
144
+ ),
145
+ ]
146
+
147
+ # SuperCap
148
+ fixture_super: list[VirtualStorageConfig] = [
149
+ VirtualStorageConfig.capacitor(
150
+ C_uF=25e6,
151
+ V_rated=3.0,
152
+ R_leak_Ohm=3 / 55e-6,
153
+ R_series_Ohm=17e-3,
154
+ name="Maxwell BCAP0025 P300 X11",
155
+ description=dsc_super,
156
+ ),
157
+ VirtualStorageConfig.capacitor(
158
+ C_uF=12e6,
159
+ V_rated=6.0,
160
+ R_leak_Ohm=6 / 80e-6,
161
+ R_series_Ohm=90e-3,
162
+ name="Abracon ADCM-S06R0SA126RB",
163
+ description=dsc_super,
164
+ ),
165
+ VirtualStorageConfig.capacitor(
166
+ C_uF=7.5e6,
167
+ V_rated=5.5,
168
+ R_leak_Ohm=6 / 78e-6,
169
+ R_series_Ohm=90e-3,
170
+ name="AVX SCMT32F755SRBA0 ",
171
+ description=dsc_super,
172
+ ),
173
+ ]
174
+
175
+ fixture_lipo: list[VirtualStorageConfig] = [
176
+ # LiPo-Coin-cells 5.4mm, https://www.lipobatteries.net/3-8v-rechargeable-mini-button-lipo-coin-cell-battery/
177
+ VirtualStorageConfig.lipo(
178
+ q_mAh=80, name="LPM1254", description="LiPo-Coin-Cell 80mAh, 1 cell, w=12mm, d=5.4mm"
179
+ ),
180
+ VirtualStorageConfig.lipo(
181
+ q_mAh=65, name="LPM1154", description="LiPo-Coin-Cell 65mAh, 1 cell, w=11mm, d=5.4mm"
182
+ ),
183
+ VirtualStorageConfig.lipo(
184
+ q_mAh=50, name="LPM1054", description="LiPo-Coin-Cell 50mAh, 1 cell, w=10mm, d=5.4mm"
185
+ ),
186
+ VirtualStorageConfig.lipo(
187
+ q_mAh=40, name="LPM0954", description="LiPo-Coin-Cell 40mAh, 1 cell, w=9mm, d=5.4mm"
188
+ ),
189
+ VirtualStorageConfig.lipo(
190
+ q_mAh=35, name="LPM0854", description="LiPo-Coin-Cell 35mAh, 1 cell, w=8mm, d=5.4mm"
191
+ ),
192
+ # LiPo-Coin-cells 4.0mm, https://www.lipobatteries.net/3-8v-rechargeable-mini-button-lipo-coin-cell-battery/
193
+ VirtualStorageConfig.lipo(
194
+ q_mAh=55, name="LPM1240", description="LiPo-Coin-Cell 55mAh, 1 cell, w=12mm, d=4.0mm"
195
+ ),
196
+ VirtualStorageConfig.lipo(
197
+ q_mAh=45, name="LPM1140", description="LiPo-Coin-Cell 45mAh, 1 cell, w=11mm, d=4.0mm"
198
+ ),
199
+ VirtualStorageConfig.lipo(
200
+ q_mAh=35, name="LPM1040", description="LiPo-Coin-Cell 35mAh, 1 cell, w=10mm, d=4.0mm"
201
+ ),
202
+ VirtualStorageConfig.lipo(
203
+ q_mAh=30, name="LPM0940", description="LiPo-Coin-Cell 30mAh, 1 cell, w=9mm, d=4.0mm"
204
+ ),
205
+ VirtualStorageConfig.lipo(
206
+ q_mAh=18, name="LPM0840", description="LiPo-Coin-Cell 18mAh, 1 cell, w=8mm, d=4.0mm"
207
+ ),
208
+ # small LiPos, https://www.lipobatteries.net/lipo-batteries-within-100mah/
209
+ VirtualStorageConfig.lipo(
210
+ q_mAh=12, name="LP151020", description="LiPo-Pouch 12mAh, 1 cell, 20x10x1.5mm"
211
+ ),
212
+ VirtualStorageConfig.lipo(
213
+ q_mAh=15, name="LP251212", description="LiPo-Pouch 15mAh, 1 cell, 12x12x2.5mm"
214
+ ),
215
+ VirtualStorageConfig.lipo(
216
+ q_mAh=22, name="LP500522", description="LiPo-Pouch 20mAh, 1 cell, 22x05x5.0mm"
217
+ ),
218
+ VirtualStorageConfig.lipo(
219
+ q_mAh=22, name="LP271015", description="LiPo-Pouch 22mAh, 1 cell, 15x10x2.7mm"
220
+ ),
221
+ # Example from the paper
222
+ VirtualStorageConfig.lipo(q_mAh=860, name="PL-383562"),
223
+ ]
224
+
225
+ fixture_lead: list[VirtualStorageConfig] = [
226
+ # Example from the paper
227
+ VirtualStorageConfig.lead_acid(q_mAh=1200, name="LEOCH_LP12-1.2AH"),
228
+ ]
229
+
230
+
231
+ if __name__ == "__main__":
232
+ path_here = Path(__file__).parent.absolute()
233
+ path_db = path_here # .parent / "shepherd_core/shepherd_core/data_models/content"
234
+
235
+ if not path_db.exists() or not path_db.is_dir():
236
+ log.error("Path to db must exist and be a directory!")
237
+ sys.exit(1)
238
+
239
+ fixtures: dict[str, list[VirtualStorageConfig]] = {
240
+ "ideal": fixture_ideal,
241
+ "tantal": fixture_tantal,
242
+ "mlcc": fixture_mlcc,
243
+ "super": fixture_super,
244
+ "lipo": fixture_lipo,
245
+ "lead": fixture_lead,
246
+ }
247
+
248
+ for name, fixture in fixtures.items():
249
+ file_path = path_db / f"virtual_storage_fixture_{name}.yaml"
250
+ if file_path.exists():
251
+ log.warning("File %s already exists! -> will skip", file_path.name)
252
+ models_wrap = []
253
+ for model in fixture:
254
+ model_dict = (
255
+ model.model_dump()
256
+ ) # exclude_unset=True, exclude_defaults=True, include={"id",})
257
+ model_wrap = Wrapper(
258
+ datatype=type(model).__name__,
259
+ created=local_now(),
260
+ comment=f"created by script '{Path(__file__).name}'",
261
+ parameters=model_dict,
262
+ )
263
+ models_wrap.append(model_wrap.model_dump(exclude_unset=True, exclude_defaults=True))
264
+
265
+ models_yaml = yaml.safe_dump(models_wrap, default_flow_style=False, sort_keys=False)
266
+ with file_path.open("w") as f:
267
+ f.write(models_yaml)