shepherd-core 2025.8.1__tar.gz → 2026.2.1__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.
Files changed (176) hide show
  1. shepherd_core-2026.2.1/LICENSE +21 -0
  2. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/PKG-INFO +6 -3
  3. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/eenv_generator.py +3 -3
  4. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/experiment_generic_var1.py +8 -7
  5. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/experiment_generic_var2.py +6 -5
  6. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/experiment_models.py +2 -1
  7. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/firmware_model.py +3 -2
  8. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/firmware_modification.py +2 -1
  9. shepherd_core-2025.8.1/examples/simulate_vharvester.py → shepherd_core-2026.2.1/examples/simulations/vharvester.py +20 -9
  10. shepherd_core-2025.8.1/examples/simulate_vsource.py → shepherd_core-2026.2.1/examples/simulations/vsource.py +19 -10
  11. shepherd_core-2026.2.1/examples/simulations/vstorage.py +241 -0
  12. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/vsource_debug_sim.py +7 -2
  13. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/pyproject.toml +4 -12
  14. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/config.py +1 -1
  15. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/__init__.py +8 -4
  16. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/base/cal_measurement.py +7 -2
  17. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/base/calibration.py +23 -12
  18. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/base/content.py +12 -2
  19. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/base/shepherd.py +13 -4
  20. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/base/wrapper.py +2 -0
  21. shepherd_core-2026.2.1/shepherd_core/data_models/content/__init__.py +24 -0
  22. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/content/_external_fixtures.yaml +104 -96
  23. shepherd_core-2026.2.1/shepherd_core/data_models/content/_metadata_eenvs_bonito.yaml +436 -0
  24. shepherd_core-2026.2.1/shepherd_core/data_models/content/_metadata_eenvs_synthetic_multivariate_random_walk.yaml +164 -0
  25. shepherd_core-2026.2.1/shepherd_core/data_models/content/_metadata_eenvs_synthetic_on_off_markov.yaml +3280 -0
  26. shepherd_core-2026.2.1/shepherd_core/data_models/content/_metadata_eenvs_synthetic_on_off_windows.yaml +3260 -0
  27. shepherd_core-2026.2.1/shepherd_core/data_models/content/_metadata_eenvs_synthetic_static.yaml +450 -0
  28. shepherd_core-2026.2.1/shepherd_core/data_models/content/energy_environment.py +370 -0
  29. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/content/energy_environment_fixture.yaml +21 -18
  30. shepherd_core-2026.2.1/shepherd_core/data_models/content/enum_datatypes.py +109 -0
  31. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/content/firmware.py +44 -16
  32. shepherd_core-2025.8.1/shepherd_core/data_models/content/virtual_harvester.py → shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_harvester_config.py +13 -96
  33. shepherd_core-2025.8.1/shepherd_core/data_models/content/virtual_source.py → shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_source_config.py +103 -60
  34. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/content/virtual_source_fixture.yaml +24 -24
  35. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_config.py +429 -0
  36. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_creator.py +267 -0
  37. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_ideal.yaml +637 -0
  38. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_lead.yaml +49 -0
  39. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_lipo.yaml +735 -0
  40. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_mlcc.yaml +200 -0
  41. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_param_experiments.py +151 -0
  42. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_super.yaml +150 -0
  43. shepherd_core-2026.2.1/shepherd_core/data_models/content/virtual_storage_fixture_tantal.yaml +550 -0
  44. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/experiment/experiment.py +38 -13
  45. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/experiment/observer_features.py +17 -4
  46. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/experiment/target_config.py +56 -8
  47. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/__init__.py +13 -2
  48. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/emulation.py +10 -6
  49. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/firmware_mod.py +3 -1
  50. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/harvest.py +3 -1
  51. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/helper_paths.py +2 -2
  52. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/observer_tasks.py +8 -6
  53. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/programming.py +4 -2
  54. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/task/testbed_tasks.py +8 -2
  55. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/cape.py +2 -0
  56. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/gpio.py +2 -0
  57. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/mcu.py +2 -0
  58. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/observer.py +2 -0
  59. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/target.py +7 -5
  60. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/target_fixture.old1 +1 -1
  61. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/target_fixture.yaml +1 -1
  62. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/testbed.py +17 -15
  63. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/decoder_waveform/uart.py +1 -1
  64. shepherd_core-2026.2.1/shepherd_core/exit_handler.py +22 -0
  65. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/fw_tools/converter.py +2 -2
  66. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/fw_tools/validation.py +1 -1
  67. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/inventory/__init__.py +23 -21
  68. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/inventory/system.py +3 -3
  69. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/logger.py +0 -1
  70. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/reader.py +32 -27
  71. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/testbed_client/cache_path.py +3 -3
  72. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/testbed_client/client_abc_fix.py +14 -3
  73. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/testbed_client/client_web.py +7 -5
  74. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/testbed_client/fixtures.py +7 -7
  75. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/version.py +1 -1
  76. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/vsource/__init__.py +4 -0
  77. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/vsource/virtual_converter_model.py +29 -28
  78. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/vsource/virtual_harvester_model.py +29 -21
  79. shepherd_core-2026.2.1/shepherd_core/vsource/virtual_harvester_simulation.py +71 -0
  80. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/vsource/virtual_source_model.py +18 -14
  81. shepherd_core-2026.2.1/shepherd_core/vsource/virtual_source_simulation.py +143 -0
  82. shepherd_core-2026.2.1/shepherd_core/vsource/virtual_storage_model.py +164 -0
  83. shepherd_core-2026.2.1/shepherd_core/vsource/virtual_storage_model_fixed_point_math.py +58 -0
  84. shepherd_core-2026.2.1/shepherd_core/vsource/virtual_storage_models_kibam.py +449 -0
  85. shepherd_core-2026.2.1/shepherd_core/vsource/virtual_storage_simulator.py +104 -0
  86. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/writer.py +16 -9
  87. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core.egg-info/PKG-INFO +6 -3
  88. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core.egg-info/SOURCES.txt +26 -6
  89. shepherd_core-2026.2.1/tests/data_models/conftest.py +40 -0
  90. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_config_emulator.yaml +2 -1
  91. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_config_virtsource.yaml +9 -8
  92. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_base_models.py +3 -2
  93. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_content_fixtures.py +6 -6
  94. shepherd_core-2026.2.1/tests/data_models/test_content_models.py +649 -0
  95. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_experiment_models.py +88 -8
  96. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_task_generation.py +6 -5
  97. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_task_models.py +2 -3
  98. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_testbed_models.py +0 -1
  99. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/decoder_waveform/test_decoder.py +0 -1
  100. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/inventory/test_inventory.py +0 -1
  101. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/test_cal_hw.py +0 -1
  102. shepherd_core-2026.2.1/tests/test_examples.py +53 -0
  103. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/vsource/test_converter.py +19 -22
  104. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/vsource/test_harvester.py +7 -7
  105. shepherd_core-2025.8.1/shepherd_core/data_models/content/__init__.py +0 -20
  106. shepherd_core-2025.8.1/shepherd_core/data_models/content/energy_environment.py +0 -52
  107. shepherd_core-2025.8.1/shepherd_core/data_models/content/firmware_datatype.py +0 -15
  108. shepherd_core-2025.8.1/shepherd_core/data_models/virtual_source_doc.txt +0 -207
  109. shepherd_core-2025.8.1/shepherd_core/vsource/virtual_harvester_simulation.py +0 -72
  110. shepherd_core-2025.8.1/shepherd_core/vsource/virtual_source_simulation.py +0 -145
  111. shepherd_core-2025.8.1/tests/data_models/conftest.py +0 -14
  112. shepherd_core-2025.8.1/tests/data_models/test_content_models.py +0 -282
  113. shepherd_core-2025.8.1/tests/test_examples.py +0 -42
  114. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/README.md +0 -0
  115. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/experiment_from_yaml.yaml +0 -0
  116. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/inventory.py +0 -0
  117. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/uart_decode_waveform.py +0 -0
  118. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/examples/uart_raw2.csv +0 -0
  119. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/setup.cfg +0 -0
  120. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/__init__.py +0 -0
  121. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/calibration_hw_def.py +0 -0
  122. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/commons.py +0 -0
  123. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/base/__init__.py +0 -0
  124. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/base/timezone.py +0 -0
  125. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
  126. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/experiment/__init__.py +0 -0
  127. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/readme.md +0 -0
  128. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/__init__.py +0 -0
  129. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
  130. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
  131. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
  132. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
  133. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
  134. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/decoder_waveform/__init__.py +0 -0
  135. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/fw_tools/__init__.py +0 -0
  136. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/fw_tools/converter_elf.py +0 -0
  137. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/fw_tools/patcher.py +0 -0
  138. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/inventory/python.py +0 -0
  139. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/inventory/target.py +0 -0
  140. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/testbed_client/__init__.py +0 -0
  141. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/testbed_client/user_model.py +0 -0
  142. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core/vsource/target_model.py +0 -0
  143. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core.egg-info/dependency_links.txt +0 -0
  144. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core.egg-info/requires.txt +0 -0
  145. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core.egg-info/top_level.txt +0 -0
  146. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/shepherd_core.egg-info/zip-safe +0 -0
  147. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/__init__.py +0 -0
  148. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/conftest.py +0 -0
  149. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/__init__.py +0 -0
  150. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_cal_data.yaml +0 -0
  151. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_cal_data_faulty.yaml +0 -0
  152. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_cal_meas.yaml +0 -0
  153. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
  154. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
  155. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_config_experiment.yaml +0 -0
  156. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
  157. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_config_harvester.yaml +0 -0
  158. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/example_config_testbed.yaml +0 -0
  159. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_examples.py +0 -0
  160. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/data_models/test_testbed_fixtures.py +0 -0
  161. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/decoder_waveform/__init__.py +0 -0
  162. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/fw_tools/__init__.py +0 -0
  163. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/fw_tools/build_msp.elf +0 -0
  164. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/fw_tools/build_nrf.elf +0 -0
  165. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/fw_tools/conftest.py +0 -0
  166. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/fw_tools/test_converter.py +0 -0
  167. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/fw_tools/test_patcher.py +0 -0
  168. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/fw_tools/test_validation.py +1 -1
  169. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/inventory/__init__.py +0 -0
  170. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/test_logger.py +0 -0
  171. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/test_reader.py +0 -0
  172. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/test_writer.py +4 -4
  173. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/testbed_client/__init__.py +0 -0
  174. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/vsource/__init__.py +0 -0
  175. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/vsource/conftest.py +0 -0
  176. {shepherd_core-2025.8.1 → shepherd_core-2026.2.1}/tests/vsource/test_z.py +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022-2025, Networked Embedded Systems Lab, TU Dresden, Ingmar Splitt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
- Name: shepherd_core
3
- Version: 2025.8.1
2
+ Name: shepherd-core
3
+ Version: 2026.2.1
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>
7
+ License-Expression: MIT
7
8
  Project-URL: Documentation, https://github.com/nes-lab/shepherd-tools/blob/main/README.md
8
9
  Project-URL: Issues, https://github.com/nes-lab/shepherd-tools/issues
9
10
  Project-URL: Source, https://pypi.org/project/shepherd-core/
@@ -22,11 +23,12 @@ Classifier: Programming Language :: Python :: 3.10
22
23
  Classifier: Programming Language :: Python :: 3.11
23
24
  Classifier: Programming Language :: Python :: 3.12
24
25
  Classifier: Programming Language :: Python :: 3.13
25
- Classifier: License :: OSI Approved :: MIT License
26
+ Classifier: Programming Language :: Python :: 3.14
26
27
  Classifier: Operating System :: OS Independent
27
28
  Classifier: Natural Language :: English
28
29
  Requires-Python: >=3.10
29
30
  Description-Content-Type: text/markdown
31
+ License-File: LICENSE
30
32
  Requires-Dist: h5py
31
33
  Requires-Dist: numpy
32
34
  Requires-Dist: pyYAML
@@ -49,6 +51,7 @@ Requires-Dist: pytest; extra == "test"
49
51
  Requires-Dist: coverage; extra == "test"
50
52
  Provides-Extra: all
51
53
  Requires-Dist: shepherd-core[dev,elf,inventory,test]; extra == "all"
54
+ Dynamic: license-file
52
55
 
53
56
  # Core Library
54
57
 
@@ -1,14 +1,14 @@
1
- """Create a set of static artificial energy environments."""
1
+ """Create a set of static synthetic energy environments."""
2
2
 
3
3
  from itertools import product
4
4
  from pathlib import Path
5
5
 
6
6
  import numpy as np
7
+ from shepherd_core.logger import log
7
8
  from tqdm import trange
8
9
 
9
10
  from shepherd_core import Reader as ShpReader
10
11
  from shepherd_core import Writer as ShpWriter
11
- from shepherd_core.logger import log
12
12
 
13
13
  # Config
14
14
  voltages_V = [4.0, 2.0]
@@ -29,7 +29,7 @@ for _v, _c in product(voltages_V, currents_A):
29
29
  log.info("File exists, will skip: %s", file_path.name)
30
30
  else:
31
31
  with ShpWriter(file_path) as file:
32
- file.store_hostname("artificial")
32
+ file.store_hostname("synthetic")
33
33
  # values in SI units
34
34
  timestamp_vector = np.arange(0.0, duration_s, file.sample_interval_ns / 1e9)
35
35
  voltage_vector = np.linspace(_v, _v, int(file.samplerate_sps * duration_s))
@@ -16,10 +16,11 @@ What the code does:
16
16
  from pathlib import Path
17
17
 
18
18
  import shepherd_core.data_models as sm
19
- from shepherd_core import WebClient
20
19
  from shepherd_core.data_models.task import TestbedTasks
21
20
  from shepherd_core.data_models.testbed import MCU
22
21
 
22
+ from shepherd_core import WebClient
23
+
23
24
  # For online-queries the lib can be connected to the testbed-server.
24
25
  # NOTE: there are 3 states:
25
26
  # - unconnected -> demo-fixtures are queried (locally)
@@ -29,20 +30,20 @@ do_connect = False
29
30
  if do_connect:
30
31
  WebClient()
31
32
 
32
- xp = sm.Experiment(
33
+ exp = sm.Experiment(
33
34
  name="meaningful_TestName",
34
35
  # time_start could be "2033-03-13 14:15:16" or "datetime.now() + timedelta(minutes=30)"
35
- duration=30,
36
+ duration=30, # ty: ignore[invalid-argument-type]
36
37
  target_configs=[
37
38
  sm.TargetConfig(
38
39
  target_IDs=range(7, 12),
39
40
  custom_IDs=range(1, 100), # note: longer list is OK
40
- energy_env=sm.EnergyEnvironment(name="eenv_static_3000mV_50mA_3600s"),
41
+ energy_env=sm.EnergyEnvironment(name="synthetic_static_3000mV_50mA"),
41
42
  firmware1=sm.Firmware(
42
43
  name="FW_TestXYZ",
43
44
  data=Path("/var/shepherd/content/fw/nes_lab/nrf52_demo_rf/build.elf"),
44
45
  data_type=sm.FirmwareDType.path_elf,
45
- data_local=False,
46
+ data_2_copy=False,
46
47
  mcu=MCU(name="nRF52"),
47
48
  ),
48
49
  power_tracing=None,
@@ -51,10 +52,10 @@ xp = sm.Experiment(
51
52
  ),
52
53
  ],
53
54
  )
54
- xp.to_file("experiment_generic_var1.yaml")
55
+ exp.to_file("experiment_generic_var1.yaml")
55
56
 
56
57
  # Create a tasks-list for the testbed
57
- tb_tasks = TestbedTasks.from_xp(xp)
58
+ tb_tasks = TestbedTasks.from_xp(exp)
58
59
  tb_tasks.to_file("experiment_generic_var1_tbt.yaml")
59
60
 
60
61
  # next steps:
@@ -15,9 +15,10 @@
15
15
  from pathlib import Path
16
16
 
17
17
  import shepherd_core.data_models as sm
18
- from shepherd_core import WebClient
19
18
  from shepherd_core.data_models.task import TestbedTasks
20
19
 
20
+ from shepherd_core import WebClient
21
+
21
22
  # For online-queries the lib can be connected to the testbed-server.
22
23
  # NOTE: there are 3 states:
23
24
  # - unconnected -> demo-fixtures are queried (locally)
@@ -27,7 +28,7 @@ do_connect = False
27
28
  if do_connect:
28
29
  WebClient()
29
30
 
30
- xp = sm.Experiment(
31
+ exp = sm.Experiment(
31
32
  name="meaningful_TestName",
32
33
  # time_start could be "2033-03-13 14:15:16" or "datetime.now() + timedelta(minutes=30)"
33
34
  duration=30,
@@ -35,7 +36,7 @@ xp = sm.Experiment(
35
36
  sm.TargetConfig(
36
37
  target_IDs=range(7, 12),
37
38
  custom_IDs=range(1, 100), # note: longer list is OK
38
- energy_env=sm.EnergyEnvironment(name="eenv_static_3000mV_50mA_3600s"),
39
+ energy_env=sm.EnergyEnvironment(name="synthetic_static_3000mV_50mA"),
39
40
  firmware1=sm.Firmware.from_firmware(
40
41
  file=Path("./firmware_nrf.elf").absolute(),
41
42
  ),
@@ -44,10 +45,10 @@ xp = sm.Experiment(
44
45
  ),
45
46
  ],
46
47
  )
47
- xp.to_file("experiment_generic_var2.yaml")
48
+ exp.to_file("experiment_generic_var2.yaml")
48
49
 
49
50
  # Create a tasks-list for the testbed
50
- tb_tasks = TestbedTasks.from_xp(xp)
51
+ tb_tasks = TestbedTasks.from_xp(exp)
51
52
  tb_tasks.to_file("experiment_generic_var2_tbt.yaml")
52
53
 
53
54
  # next steps:
@@ -19,9 +19,10 @@ How to define an experiment:
19
19
  """
20
20
 
21
21
  import shepherd_core.data_models as sm
22
- from shepherd_core import WebClient
23
22
  from shepherd_core.data_models.task import TestbedTasks
24
23
 
24
+ from shepherd_core import WebClient
25
+
25
26
  # generate description for all parameters -> base for web-forms
26
27
  sm.Experiment.schema_to_file("experiment_schema.yaml")
27
28
 
@@ -6,11 +6,12 @@ or shepherd-core[elf].
6
6
 
7
7
  from pathlib import Path
8
8
 
9
- from shepherd_core import WebClient
10
- from shepherd_core import fw_tools
11
9
  from shepherd_core.data_models import Firmware
12
10
  from shepherd_core.data_models import FirmwareDType
13
11
 
12
+ from shepherd_core import WebClient
13
+ from shepherd_core import fw_tools
14
+
14
15
  path_elf = Path(__file__).parent.parent / "tests/fw_tools/build_msp.elf"
15
16
 
16
17
  # Option 1 - fully manual
@@ -8,10 +8,11 @@ Note: make sure to have installed
8
8
  import shutil
9
9
  from pathlib import Path
10
10
 
11
- from shepherd_core import fw_tools
12
11
  from shepherd_core.data_models import Firmware
13
12
  from shepherd_core.data_models import FirmwareDType
14
13
 
14
+ from shepherd_core import fw_tools
15
+
15
16
  path_src = Path(__file__).parent.parent / "tests/fw_tools/build_msp.elf"
16
17
  path_elf = Path(__file__).with_name("firmware_msp.elf")
17
18
 
@@ -6,26 +6,37 @@
6
6
 
7
7
  Output:
8
8
  E_out = 0.000 mWs -> cv20
9
- E_out = 17.165 mWs -> cv10
10
- E_out = 17.427 mWs -> mppt_voc
11
- E_out = 17.242 mWs -> mppt_bq_solar
12
- E_out = 13.998 mWs -> mppt_bq_thermoelectric
13
- E_out = 15.202 mWs -> mppt_po
9
+ E_out = 17.143 mWs -> cv10
10
+ E_out = 17.384 mWs -> mppt_voc
11
+ E_out = 17.249 mWs -> mppt_bq_solar
12
+ E_out = 13.954 mWs -> mppt_bq_thermoelectric
13
+ E_out = 15.001 mWs -> mppt_po
14
14
  E_out = 17.811 mWs -> mppt_opt
15
+
15
16
  """
16
17
 
18
+ import os
19
+ import sys
17
20
  from pathlib import Path
18
21
 
19
- from shepherd_core import Reader
20
22
  from shepherd_core.data_models import VirtualHarvesterConfig
21
23
  from shepherd_core.vsource import simulate_harvester
24
+
25
+ from shepherd_core import Reader
22
26
  from shepherd_data import ivonne
23
27
 
28
+ DURATION_MAX = 1 if "PYTEST_CURRENT_TEST" in os.environ else sys.float_info.max
29
+ # ⤷ limits runtime for pytest
30
+
24
31
  # config simulation
25
- sim_duration = 32
26
- file_ivonne = Path(__file__).parent.parent.parent / "shepherd_data/examples/jogging_10m.iv"
32
+ sim_duration = min(32, DURATION_MAX)
33
+ # limits runtime for pytest
34
+ file_ivonne = Path(__file__).parents[3] / "shepherd_data/examples/jogging_10m.iv"
27
35
  file_ivcurve = Path(__file__).parent / "jogging_ivcurve.h5"
28
36
 
37
+ if not file_ivonne.exists():
38
+ raise FileNotFoundError("Input-File not found - check path")
39
+
29
40
  hrv_list = [
30
41
  "cv20",
31
42
  # ⤷ fails due to lower solar voltage
@@ -39,7 +50,7 @@ hrv_list = [
39
50
  "mppt_opt",
40
51
  ]
41
52
 
42
- save_files: bool = False
53
+ save_files: bool = True
43
54
 
44
55
  # convert IVonne to IVCurve
45
56
  if not file_ivcurve.exists():
@@ -10,20 +10,22 @@ The output file can be analyzed and plotted with shepherds tool suite.
10
10
 
11
11
  Output:
12
12
  E_out = 220.001 mWs -> direct (no current-limit)
13
- E_out = 13.142 mWs -> diode+capacitor
14
- E_out = 13.066 mWs -> diode+resistor+capacitor
15
- E_out = 15.045 mWs -> BQ25504
16
- E_out = 14.962 mWs -> BQ25504s
17
- E_out = 14.397 mWs -> BQ25570
18
- E_out = 14.232 mWs -> BQ25570s
13
+ E_out = 14.670 mWs -> diode+capacitor
14
+ E_out = 14.563 mWs -> diode+resistor+capacitor
15
+ E_out = 16.718 mWs -> BQ25504
16
+ E_out = 16.805 mWs -> BQ25504s
17
+ E_out = 16.369 mWs -> BQ25570
18
+ E_out = 16.387 mWs -> BQ25570s
19
19
 
20
20
  """
21
21
 
22
22
  from pathlib import Path
23
23
 
24
24
  from shepherd_core.data_models import VirtualSourceConfig
25
+ from shepherd_core.data_models import VirtualStorageConfig
25
26
  from shepherd_core.vsource import ResistiveTarget
26
27
  from shepherd_core.vsource import simulate_source
28
+
27
29
  from shepherd_data import Reader
28
30
 
29
31
  # config simulation
@@ -41,6 +43,11 @@ src_list = [
41
43
  tgt = ResistiveTarget(R_Ohm=1_000, controlled=True)
42
44
  save_files = True
43
45
 
46
+ if not file_input.exists():
47
+ raise FileNotFoundError(
48
+ "Input-File not found - please run harvester-simulation first to create it."
49
+ )
50
+
44
51
  for src_name in src_list:
45
52
  file_output = file_input.with_stem(file_input.stem + "_emu_" + src_name) if save_files else None
46
53
 
@@ -48,10 +55,12 @@ for src_name in src_list:
48
55
  config=VirtualSourceConfig(
49
56
  name=src_name,
50
57
  C_output_uF=0,
51
- V_intermediate_enable_threshold_mV=1,
52
- V_intermediate_disable_threshold_mV=0,
53
- # jogging-dataset has max VOC of ~1.6 V -> lower set-point for non-boost
54
- C_intermediate_uF=100 if "direct" not in src_name else 0,
58
+ V_intermediate_enable_output_threshold_mV=1,
59
+ V_intermediate_disable_output_threshold_mV=0,
60
+ # jogging-dataset has maximum VOC of ~1.6 V -> lower set-point for non-boost
61
+ storage=VirtualStorageConfig.capacitor(C_uF=100, V_rated=10.0)
62
+ if "direct" not in src_name
63
+ else None,
55
64
  V_pwr_good_enable_threshold_mV=1300 if "dio" in src_name else 2800,
56
65
  V_pwr_good_disable_threshold_mV=1000 if "dio" in src_name else 2400,
57
66
  V_input_drop_mV=150 if "dio" in src_name else 0,
@@ -0,0 +1,241 @@
1
+ """A set of experiments to validate and qualify the virtual storage algorithms.
2
+
3
+ Some general Notes:
4
+
5
+ - ShpCap is also displayed when emulating Lipo and lead-acid, but it can't and won't behave similar
6
+ - during charging the model KiBaM-Plus will deviate from normal KiBaM and KiBaM-Simple,
7
+ as it supports the rate capacity effect and transients (during charging)
8
+
9
+ """
10
+
11
+ import multiprocessing
12
+ import os
13
+ import sys
14
+ from datetime import timedelta
15
+ from pathlib import Path
16
+
17
+ from pydantic import PositiveFloat
18
+ from pydantic import validate_call
19
+ from shepherd_core.data_models.content.virtual_storage_config import VirtualStorageConfig
20
+ from shepherd_core.data_models.content.virtual_storage_config import soc_t
21
+ from shepherd_core.vsource.virtual_storage_model import ModelStorage
22
+ from shepherd_core.vsource.virtual_storage_model import VirtualStorageModel
23
+ from shepherd_core.vsource.virtual_storage_models_kibam import ModelKiBaM
24
+ from shepherd_core.vsource.virtual_storage_models_kibam import ModelKiBaMPlus
25
+ from shepherd_core.vsource.virtual_storage_models_kibam import ModelKiBaMSimple
26
+ from shepherd_core.vsource.virtual_storage_models_kibam import ModelShpCap
27
+ from shepherd_core.vsource.virtual_storage_simulator import StorageSimulator
28
+
29
+ from shepherd_core import log
30
+
31
+ path_here = Path(__file__).parent
32
+
33
+ DURATION_MAX = 1 if "PYTEST_CURRENT_TEST" in os.environ else sys.float_info.max
34
+ # ⤷ limits runtime for pytest
35
+
36
+
37
+ @validate_call
38
+ def get_models(
39
+ SoC_init: soc_t, config: VirtualStorageConfig, dt_s: PositiveFloat
40
+ ) -> list[ModelStorage]:
41
+ """Models to include in experiments."""
42
+ return [
43
+ ModelKiBaM(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
44
+ ModelKiBaMPlus(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
45
+ ModelKiBaMSimple(SoC_init=SoC_init, cfg=config, dt_s=dt_s, optimize_clamp=True),
46
+ ModelKiBaMSimple(SoC_init=SoC_init, cfg=config, dt_s=dt_s, interpolate=True),
47
+ VirtualStorageModel(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
48
+ ModelShpCap(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
49
+ ][1:5]
50
+
51
+
52
+ class CurrentPulsed:
53
+ """A simple constant current source that is pulsed until a target SoC is reached."""
54
+
55
+ @validate_call
56
+ def __init__(
57
+ self,
58
+ I_pulse: float,
59
+ period_pulse: PositiveFloat,
60
+ duration_pulse: PositiveFloat,
61
+ SoC_target: soc_t,
62
+ ) -> None:
63
+ self.I_pulse = I_pulse
64
+ self.period_pulse = period_pulse
65
+ self.duration_pulse = duration_pulse
66
+ self.SoC_target = SoC_target
67
+
68
+ def step(self, t_s: float, SoC: float, _v: float) -> float:
69
+ if (self.I_pulse < 0 and SoC <= self.SoC_target) or (
70
+ self.I_pulse > 0 and SoC >= self.SoC_target
71
+ ):
72
+ return 0
73
+ return self.I_pulse if t_s % self.period_pulse < self.duration_pulse else 0
74
+
75
+
76
+ class ResistiveChargePulsed:
77
+ """A pulsed charger that is 'current limited' by a resistor."""
78
+
79
+ @validate_call
80
+ def __init__(
81
+ self,
82
+ V_target: PositiveFloat,
83
+ R_Ohm: PositiveFloat,
84
+ period_pulse: PositiveFloat,
85
+ duration_pulse: PositiveFloat,
86
+ ) -> None:
87
+ self.R_Ohm = R_Ohm
88
+ self.V_target = V_target
89
+ self.period_pulse = period_pulse
90
+ self.duration_pulse = duration_pulse
91
+
92
+ def step(self, t_s: float, _s: float, V: float) -> float:
93
+ I_A = (self.V_target - V) / self.R_Ohm
94
+ return I_A if t_s % self.period_pulse < self.duration_pulse else 0
95
+
96
+
97
+ def experiment_current_ramp_pos(config: VirtualStorageConfig) -> None:
98
+ """Charge virtual storage with a positive current ramp (increasing power)."""
99
+ dt_s = 0.1
100
+ SoC_start = 0.5
101
+ duration_s = min(200, DURATION_MAX)
102
+ sim = StorageSimulator(
103
+ models=get_models(SoC_start, config, dt_s),
104
+ dt_s=dt_s,
105
+ )
106
+
107
+ def current_trace(t_s: float, _s: float, _v: float) -> float:
108
+ return 0.1 + 0.15 * t_s / duration_s # pru-model can handle +- 268 mA
109
+
110
+ sim.run(fn=current_trace, duration_s=duration_s)
111
+ sim.plot(path_here, f"Experiment {config.name}, current charge ramp (positive)")
112
+
113
+
114
+ def experiment_current_ramp_neg(config: VirtualStorageConfig) -> None:
115
+ """Discharge virtual storage with a negative current ramp (increasing power)."""
116
+ dt_s = 0.1
117
+ SoC_start = 0.5
118
+ duration_s = min(200, DURATION_MAX)
119
+ sim = StorageSimulator(
120
+ models=get_models(SoC_start, config, dt_s),
121
+ dt_s=dt_s,
122
+ )
123
+
124
+ def current_trace(t_s: float, _s: float, _v: float) -> float:
125
+ return -(0.1 + 0.14 * t_s / duration_s) # pru-model can handle +- 268 mA
126
+
127
+ sim.run(fn=current_trace, duration_s=duration_s)
128
+ sim.plot(path_here, f"Experiment {config.name}, current discharge ramp (negative)")
129
+
130
+
131
+ def experiment_pulsed_discharge(config: VirtualStorageConfig) -> None:
132
+ """Discharge virtual storage with a pulsed constant current."""
133
+ dt_s = 0.2
134
+ SoC_start = 1.0
135
+ SoC_target = 0.0
136
+ i_pulse = CurrentPulsed(
137
+ I_pulse=-0.1, period_pulse=200, duration_pulse=100, SoC_target=SoC_target
138
+ ) # pru-model can handle +- 268 mA
139
+ sim = StorageSimulator(
140
+ models=get_models(SoC_start, config, dt_s),
141
+ dt_s=dt_s,
142
+ )
143
+ sim.run(fn=i_pulse.step, duration_s=min(1_000, DURATION_MAX))
144
+ sim.plot(path_here, f"Experiment {config.name}, pulsed discharge .1A, 1000 s (figure_9a)")
145
+
146
+
147
+ def experiment_pulsed_charge(config: VirtualStorageConfig) -> None:
148
+ """Charge virtual storage with a pulsed constant current."""
149
+ dt_s = 0.2
150
+ SoC_start = 0.0
151
+ SoC_target = 1.0
152
+ i_pulse = CurrentPulsed(
153
+ I_pulse=0.1, period_pulse=200, duration_pulse=100, SoC_target=SoC_target
154
+ ) # pru-model can handle +- 268 mA
155
+ sim = StorageSimulator(
156
+ models=get_models(SoC_start, config, dt_s),
157
+ dt_s=dt_s,
158
+ )
159
+ sim.run(fn=i_pulse.step, duration_s=min(1_000, DURATION_MAX))
160
+ sim.plot(path_here, f"Experiment {config.name}, pulsed charge .1A, 1000 s (figure_9b)")
161
+
162
+
163
+ def experiment_pulsed_resistive_charge(config: VirtualStorageConfig) -> None:
164
+ """Charge virtual storage with a resistive constant voltage."""
165
+ dt_s = 0.5
166
+ SoC_start = 0.0
167
+ i_pulse = ResistiveChargePulsed(R_Ohm=20, V_target=4.2, period_pulse=200, duration_pulse=100)
168
+ sim = StorageSimulator(
169
+ models=get_models(SoC_start, config, dt_s),
170
+ dt_s=dt_s,
171
+ )
172
+ sim.run(fn=i_pulse.step, duration_s=min(3_000, DURATION_MAX))
173
+ sim.plot(
174
+ path_here, f"Experiment {config.name}, pulsed resistive charge 20 Ohm to 4.2 V, 3000 s"
175
+ )
176
+
177
+
178
+ def experiment_resistive_load(config: VirtualStorageConfig) -> None:
179
+ """Charge virtual storage with a resistive constant voltage."""
180
+ dt_s = 0.5
181
+ SoC_start = 1.0
182
+
183
+ def i_charge(_t_s: float, _s: float, V: float) -> float:
184
+ return -V / 20
185
+
186
+ sim = StorageSimulator(
187
+ models=get_models(SoC_start, config, dt_s),
188
+ dt_s=dt_s,
189
+ )
190
+ sim.run(fn=i_charge, duration_s=min(1_000, DURATION_MAX))
191
+ sim.plot(path_here, f"Experiment {config.name}, resistive load 20 Ohm from 4.2 V, 1000 s")
192
+
193
+
194
+ def experiment_self_discharge() -> None:
195
+ """Observe self-discharge behavior of virtual storage models."""
196
+ dt_s = 0.2
197
+ SoC_start = 1.0
198
+ SoC_target = 0.9
199
+ duration = timedelta(minutes=25)
200
+ store = VirtualStorageConfig.capacitor(C_uF=100, V_rated=6.3)
201
+ R_leak = store.calc_R_leak_capacitor(duration=duration, SoC_final=SoC_target, SoC_0=SoC_start)
202
+ log.info("R_leak = %.2f Ohm", R_leak)
203
+ config = VirtualStorageConfig.capacitor(C_uF=100, V_rated=6.3, R_leak_Ohm=R_leak)
204
+ sim = StorageSimulator(
205
+ models=get_models(SoC_start, config, dt_s),
206
+ dt_s=dt_s,
207
+ )
208
+
209
+ def step(_t: float, _s: float, _v: float) -> float:
210
+ return 0
211
+
212
+ sim.run(fn=step, duration_s=min(duration.total_seconds(), DURATION_MAX))
213
+ sim.plot(
214
+ path_here,
215
+ f"Experiment {config.name}, self-discharge, "
216
+ f"SoC {SoC_start} to {SoC_target} in {duration.total_seconds()} s",
217
+ )
218
+
219
+
220
+ if __name__ == "__main__":
221
+ with multiprocessing.Pool() as pool:
222
+ pool.apply_async(experiment_self_discharge)
223
+
224
+ configs = [
225
+ VirtualStorageConfig.capacitor(C_uF=10e6, V_rated=4.2), # match charge with batteries
226
+ VirtualStorageConfig.lipo(q_mAh=10),
227
+ VirtualStorageConfig.lead_acid(q_mAh=10),
228
+ ]
229
+
230
+ for cfg in configs:
231
+ pool.apply_async(experiment_pulsed_charge, args=(cfg,))
232
+ pool.apply_async(experiment_pulsed_discharge, args=(cfg,))
233
+ pool.apply_async(experiment_current_ramp_pos, args=(cfg,))
234
+ pool.apply_async(experiment_current_ramp_neg, args=(cfg,))
235
+
236
+ for cfg in configs[0:2]:
237
+ pool.apply_async(experiment_pulsed_resistive_charge, args=(cfg,))
238
+ pool.apply_async(experiment_resistive_load, args=(cfg,))
239
+
240
+ pool.close()
241
+ pool.join()
@@ -10,15 +10,16 @@
10
10
 
11
11
  """
12
12
 
13
+ import os
13
14
  from itertools import product
14
15
 
15
16
  import matplotlib.pyplot as plt
16
17
  import numpy as np
18
+ from shepherd_core.data_models import VirtualSourceConfig
19
+ from shepherd_core.vsource import VirtualSourceModel
17
20
 
18
21
  from shepherd_core import CalibrationEmulator
19
22
  from shepherd_core import WebClient
20
- from shepherd_core.data_models import VirtualSourceConfig
21
- from shepherd_core.vsource import VirtualSourceModel
22
23
 
23
24
  # config simulation
24
25
  sample_dur_list = [50_000, 500_000]
@@ -38,6 +39,10 @@ src_list = [
38
39
  I_mcu_sleep_A = 200e-9
39
40
  I_mcu_active_A = 1e-3
40
41
 
42
+ # limit runtime for pytest
43
+ if "PYTEST_CURRENT_TEST" in os.environ:
44
+ sample_dur_list = [10_000]
45
+
41
46
  # For online-queries the lib can be connected to the testbed-server.
42
47
  # NOTE: there are 3 states:
43
48
  # - unconnected -> demo-fixtures are queried (locally)
@@ -1,12 +1,13 @@
1
1
  [project]
2
- name = "shepherd_core"
2
+ name = "shepherd-core"
3
3
  description = "Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed"
4
4
  keywords = ["testbed", "beaglebone", "pru", "batteryless", "energyharvesting", "solar"]
5
5
 
6
6
  authors = [{name = "Ingmar Splitt", email = "ingmar.splitt@tu-dresden.de"},]
7
7
  maintainers = [{name = "Ingmar Splitt", email = "ingmar.splitt@tu-dresden.de"},]
8
8
 
9
- license = {file = "LICENSE"}
9
+ license = "MIT"
10
+ license-files = ["LICENSE"] # can't be in parent dir
10
11
  dynamic = ["version"]
11
12
 
12
13
  classifiers = [
@@ -18,7 +19,7 @@ classifiers = [
18
19
  "Programming Language :: Python :: 3.11",
19
20
  "Programming Language :: Python :: 3.12",
20
21
  "Programming Language :: Python :: 3.13",
21
- "License :: OSI Approved :: MIT License",
22
+ "Programming Language :: Python :: 3.14",
22
23
  "Operating System :: OS Independent",
23
24
  "Natural Language :: English",
24
25
  ]
@@ -103,12 +104,3 @@ addopts = "-vvv --stepwise" # opts: verbose result for each tests
103
104
  [tool.coverage.run]
104
105
  source = ["shepherd_core"]
105
106
  omit = ["*/shepherd_data/*"]
106
-
107
- [tool.mypy]
108
- python_version = 3.10
109
- ignore_missing_imports = true
110
- disable_error_code = ["call-arg", ]
111
- exclude = [
112
- "build/",
113
- ".egg-info/",
114
- ]
@@ -27,7 +27,7 @@ class ConfigDefault(BaseModel):
27
27
  UID_SIZE: int = 2
28
28
  """Variable size in Byte"""
29
29
 
30
- TESTBED_SERVER: HttpUrl = "https://shepherd.cfaed.tu-dresden.de:8000/"
30
+ TESTBED_SERVER: HttpUrl = HttpUrl("https://shepherd.cfaed.tu-dresden.de:8000/")
31
31
  """Server that holds up to date testbed fixtures"""
32
32
 
33
33