shepherd-core 2024.4.1__py3-none-any.whl → 2024.5.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 (76) hide show
  1. shepherd_core/__init__.py +3 -3
  2. shepherd_core/calibration_hw_def.py +9 -1
  3. shepherd_core/commons.py +2 -0
  4. shepherd_core/data_models/__init__.py +11 -0
  5. shepherd_core/data_models/base/__init__.py +4 -1
  6. shepherd_core/data_models/base/cal_measurement.py +18 -6
  7. shepherd_core/data_models/base/calibration.py +39 -15
  8. shepherd_core/data_models/base/content.py +10 -2
  9. shepherd_core/data_models/base/shepherd.py +21 -12
  10. shepherd_core/data_models/base/timezone.py +5 -0
  11. shepherd_core/data_models/base/wrapper.py +3 -3
  12. shepherd_core/data_models/content/__init__.py +5 -4
  13. shepherd_core/data_models/content/_external_fixtures.yaml +410 -0
  14. shepherd_core/data_models/content/energy_environment.py +7 -5
  15. shepherd_core/data_models/content/energy_environment_fixture.yaml +53 -0
  16. shepherd_core/data_models/content/firmware.py +12 -5
  17. shepherd_core/data_models/content/firmware_datatype.py +7 -0
  18. shepherd_core/data_models/content/virtual_harvester.py +24 -19
  19. shepherd_core/data_models/content/virtual_harvester_fixture.yaml +160 -0
  20. shepherd_core/data_models/content/virtual_source.py +22 -10
  21. shepherd_core/data_models/content/virtual_source_fixture.yaml +230 -0
  22. shepherd_core/data_models/experiment/__init__.py +5 -4
  23. shepherd_core/data_models/experiment/experiment.py +7 -6
  24. shepherd_core/data_models/experiment/observer_features.py +14 -7
  25. shepherd_core/data_models/experiment/target_config.py +11 -7
  26. shepherd_core/data_models/readme.md +88 -0
  27. shepherd_core/data_models/task/__init__.py +10 -3
  28. shepherd_core/data_models/task/emulation.py +10 -7
  29. shepherd_core/data_models/task/firmware_mod.py +4 -2
  30. shepherd_core/data_models/task/harvest.py +5 -4
  31. shepherd_core/data_models/task/observer_tasks.py +3 -1
  32. shepherd_core/data_models/task/programming.py +3 -1
  33. shepherd_core/data_models/task/testbed_tasks.py +3 -1
  34. shepherd_core/data_models/testbed/__init__.py +5 -2
  35. shepherd_core/data_models/testbed/cape.py +7 -5
  36. shepherd_core/data_models/testbed/cape_fixture.yaml +94 -0
  37. shepherd_core/data_models/testbed/gpio.py +10 -8
  38. shepherd_core/data_models/testbed/gpio_fixture.yaml +166 -0
  39. shepherd_core/data_models/testbed/mcu.py +9 -9
  40. shepherd_core/data_models/testbed/mcu_fixture.yaml +19 -0
  41. shepherd_core/data_models/testbed/observer.py +9 -4
  42. shepherd_core/data_models/testbed/observer_fixture.yaml +221 -0
  43. shepherd_core/data_models/testbed/target.py +4 -2
  44. shepherd_core/data_models/testbed/target_fixture.yaml +137 -0
  45. shepherd_core/data_models/testbed/testbed.py +5 -2
  46. shepherd_core/data_models/testbed/testbed_fixture.yaml +25 -0
  47. shepherd_core/decoder_waveform/__init__.py +2 -0
  48. shepherd_core/decoder_waveform/uart.py +43 -25
  49. shepherd_core/fw_tools/__init__.py +2 -0
  50. shepherd_core/fw_tools/converter.py +20 -9
  51. shepherd_core/fw_tools/converter_elf.py +3 -0
  52. shepherd_core/fw_tools/patcher.py +17 -5
  53. shepherd_core/fw_tools/validation.py +27 -6
  54. shepherd_core/inventory/__init__.py +15 -5
  55. shepherd_core/inventory/python.py +4 -0
  56. shepherd_core/inventory/system.py +6 -2
  57. shepherd_core/inventory/target.py +4 -0
  58. shepherd_core/logger.py +5 -0
  59. shepherd_core/reader.py +38 -23
  60. shepherd_core/testbed_client/__init__.py +2 -0
  61. shepherd_core/testbed_client/cache_path.py +2 -0
  62. shepherd_core/testbed_client/client.py +15 -8
  63. shepherd_core/testbed_client/fixtures.py +27 -11
  64. shepherd_core/testbed_client/user_model.py +8 -3
  65. shepherd_core/vsource/__init__.py +2 -0
  66. shepherd_core/vsource/virtual_converter_model.py +10 -3
  67. shepherd_core/vsource/virtual_harvester_model.py +7 -1
  68. shepherd_core/vsource/virtual_source_model.py +9 -5
  69. shepherd_core/writer.py +26 -21
  70. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/METADATA +2 -1
  71. shepherd_core-2024.5.1.dist-info/RECORD +75 -0
  72. shepherd_core-2024.4.1.dist-info/RECORD +0 -64
  73. /shepherd_core/data_models/{doc_virtual_source.py → virtual_source_doc.txt} +0 -0
  74. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/WHEEL +0 -0
  75. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/top_level.txt +0 -0
  76. {shepherd_core-2024.4.1.dist-info → shepherd_core-2024.5.1.dist-info}/zip-safe +0 -0
@@ -0,0 +1,160 @@
1
+ # info:
2
+ # - compendium of all parameters & description
3
+ # - look into the implementation to see which parameters are used
4
+ # - base for neutral fallback values if provided yml is sparse
5
+ # - -> it is encouraged to omit redundant parameters in your own implementation
6
+ - datatype: VirtualHarvesterConfig
7
+ parameters:
8
+ id: 1000
9
+ name: neutral
10
+ owner: Ingmar
11
+ group: NES Lab
12
+ visible2group: true
13
+ visible2all: true
14
+ created: 2022-12-12 12:12:12
15
+ updated_last: 2022-12-12 12:12:12
16
+
17
+ - datatype: VirtualHarvesterConfig
18
+ parameters:
19
+ id: 1010
20
+ name: ivcurve
21
+ description: Postpone harvesting by sampling ivcurves (voltage stepped as sawtooth-wave)
22
+ comment: ~200 Hz
23
+ inherit_from: neutral
24
+ algorithm: ivcurve
25
+ samples_n: 250
26
+ voltage_min_mV: 0
27
+ voltage_max_mV: 5000
28
+ wait_cycles: 1 # results in 200 Hz (= 100kHz /(2*250))
29
+ rising: false # downward sawtooth seems to have advantages for solar cells
30
+ # todo: also add switch for sawtooth- vs triangle-wave?
31
+ # todo: could also include a version with dynamic upper-boundary, varied if voc is reached very early
32
+
33
+ - datatype: VirtualHarvesterConfig
34
+ parameters:
35
+ id: 1011
36
+ name: ivcurves # synonym
37
+ inherit_from: ivcurve
38
+
39
+ - datatype: VirtualHarvesterConfig
40
+ parameters:
41
+ id: 1012
42
+ name: iv1000
43
+ comment: Name relates to curves per second
44
+ inherit_from: ivcurve
45
+ samples_n: 100
46
+ wait_cycles: 0
47
+
48
+ - datatype: VirtualHarvesterConfig
49
+ parameters:
50
+ id: 1013
51
+ name: iv110
52
+ comment: Between 50 & 60 Hz line-frequency to avoid standing waves
53
+ inherit_from: ivcurve
54
+ samples_n: 909
55
+ wait_cycles: 0
56
+
57
+ - datatype: VirtualHarvesterConfig
58
+ parameters:
59
+ id: 1020
60
+ name: isc_voc
61
+ description: Postpone harvesting by sampling short circuit current & open circuit voltage
62
+ inherit_from: neutral
63
+ algorithm: isc_voc
64
+ wait_cycles: 1 # results in 25 kHz (isc, wait, voc, wait)
65
+
66
+ - datatype: VirtualHarvesterConfig
67
+ parameters:
68
+ id: 1030
69
+ name: cv20
70
+ description: Harvesting with constant Voltage
71
+ inherit_from: neutral
72
+ algorithm: cv
73
+ voltage_mV: 2000
74
+
75
+ - datatype: VirtualHarvesterConfig
76
+ parameters:
77
+ id: 1031
78
+ name: cv24
79
+ inherit_from: cv20
80
+ voltage_mV: 2400
81
+
82
+ - datatype: VirtualHarvesterConfig
83
+ parameters:
84
+ id: 1032
85
+ name: cv33
86
+ inherit_from: cv20
87
+ voltage_mV: 3300
88
+
89
+ - datatype: VirtualHarvesterConfig
90
+ parameters:
91
+ id: 1032
92
+ name: cv10
93
+ inherit_from: cv20
94
+ voltage_mV: 1000
95
+
96
+ - datatype: VirtualHarvesterConfig
97
+ parameters:
98
+ id: 1040
99
+ name: mppt_voc
100
+ description: MPPT based on open circuit voltage for solar
101
+ inherit_from: neutral
102
+ algorithm: mppt_voc
103
+ setpoint_n: 0.76
104
+ interval_ms: 100 # between measurements
105
+ duration_ms: 1.2 # solar can overshoot when load is removed
106
+ current_limit_uA: 5 # boundary for detecting open circuit in emulated version (working on IV-Curves)
107
+
108
+ - datatype: VirtualHarvesterConfig
109
+ parameters:
110
+ id: 1041
111
+ name: mppt_bq
112
+ description: MPPT of TI BQ-Converters for solar
113
+ inherit_from: mppt_voc
114
+ setpoint_n: 0.76
115
+ interval_ms: 16000 # between measurements
116
+ duration_ms: 256 # of measurement
117
+
118
+ - datatype: VirtualHarvesterConfig
119
+ parameters:
120
+ id: 1042
121
+ name: mppt_bqt
122
+ description: MPPT of TI BQ-Converters for thermoelectric
123
+ inherit_from: mppt_voc
124
+ setpoint_n: 0.50
125
+ interval_ms: 16000 # between measurements
126
+ duration_ms: 256 # of measurement
127
+
128
+ - datatype: VirtualHarvesterConfig
129
+ parameters:
130
+ id: 1043
131
+ name: mppt_bq_solar # explicit naming
132
+ inherit_from: mppt_bq
133
+
134
+ - datatype: VirtualHarvesterConfig
135
+ parameters:
136
+ id: 1044
137
+ name: mppt_bq_thermoelectric # explicit naming
138
+ inherit_from: mppt_bqt
139
+
140
+ - datatype: VirtualHarvesterConfig
141
+ parameters:
142
+ id: 1045
143
+ name: mppt_po
144
+ description: MPPT based on perturb & observe algorithm
145
+ inherit_from: neutral
146
+ algorithm: mppt_po
147
+ voltage_min_mV: 0
148
+ voltage_max_mV: 5000
149
+ voltage_step_mV: 10
150
+ interval_ms: 18 # between steps
151
+
152
+ - datatype: VirtualHarvesterConfig
153
+ parameters:
154
+ id: 1046
155
+ name: mppt_opt
156
+ description: Power-Optimum with very fast PO-Variant (harvesting) or special max-pwr-picker (emulator / ivcurve)
157
+ inherit_from: mppt_po
158
+ algorithm: mppt_opt
159
+ voltage_step_mV: 1
160
+ interval_ms: 0.01
@@ -1,3 +1,5 @@
1
+ """Generalized virtual source data models."""
2
+
1
3
  from typing import List
2
4
 
3
5
  from pydantic import Field
@@ -8,8 +10,8 @@ from typing_extensions import Self
8
10
  from ...commons import samplerate_sps_default
9
11
  from ...logger import logger
10
12
  from ...testbed_client import tb_client
11
- from .. import ShpModel
12
13
  from ..base.content import ContentModel
14
+ from ..base.shepherd import ShpModel
13
15
  from .virtual_harvester import HarvesterPRUConfig
14
16
  from .virtual_harvester import VirtualHarvesterConfig
15
17
 
@@ -21,9 +23,11 @@ LUT2D = Annotated[List[LUT1D], Field(min_length=LUT_SIZE, max_length=LUT_SIZE)]
21
23
 
22
24
 
23
25
  class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
24
- """The virtual Source uses the energy environment (file)
25
- for supplying the Target Node during the experiment.
26
- If not already done, the energy will be harvested and then converted.
26
+ """The vSrc uses the energy environment (file) for supplying the Target Node.
27
+
28
+ If not already done, the energy will be harvested and
29
+ then converted during the experiment.
30
+
27
31
  The converter-stage is software defined and offers:
28
32
  - buck-boost-combinations,
29
33
  - a simple diode + resistor and
@@ -117,9 +121,15 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
117
121
  return self
118
122
 
119
123
  def calc_internal_states(self) -> dict:
120
- """Compensate for (hard to detect) current-surge of real capacitors
121
- when converter gets turned on -> this can be const value, because
122
- the converter always turns on with "V_storage_enable_threshold_uV"
124
+ """Update the model-states for the capacitor and other elements.
125
+
126
+ This also compensates for current-surge of real capacitors
127
+ when the converter gets turned on:
128
+
129
+ - surges are hard to detect & record
130
+ - this can be const value, because
131
+ - the converter always turns on with "V_storage_enable_threshold_uV".
132
+
123
133
  TODO: currently neglecting delay after disabling converter, boost
124
134
  only has simpler formula, second enabling when V_Cap >= V_out
125
135
 
@@ -189,7 +199,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
189
199
  return values
190
200
 
191
201
  def calc_converter_mode(self, *, log_intermediate_node: bool) -> int:
192
- """Assembles bitmask from discrete values
202
+ """Assembles bitmask from discrete values.
193
203
 
194
204
  log_intermediate_node: record / log virtual intermediate (cap-)voltage and
195
205
  -current (out) instead of output-voltage and -current
@@ -204,7 +214,8 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
204
214
  )
205
215
 
206
216
  def calc_cap_constant_us_per_nF_n28(self) -> int:
207
- """Calc constant to convert capacitor-current to Voltage-delta
217
+ """Calc constant to convert capacitor-current to Voltage-delta.
218
+
208
219
  dV[uV] = constant[us/nF] * current[nA] = constant[us*V/nAs] * current[nA]
209
220
  """
210
221
  C_cap_uF = max(self.C_intermediate_uF, 0.001)
@@ -224,7 +235,8 @@ lut_o = Annotated[List[u32], Field(min_length=LUT_SIZE, max_length=LUT_SIZE)]
224
235
 
225
236
 
226
237
  class ConverterPRUConfig(ShpModel):
227
- """Map settings-list to internal state-vars struct ConverterConfig
238
+ """Map settings-list to internal state-vars struct ConverterConfig.
239
+
228
240
  NOTE:
229
241
  - yaml is based on si-units like nA, mV, ms, uF
230
242
  - c-code and py-copy is using nA, uV, ns, nF, fW, raw
@@ -0,0 +1,230 @@
1
+ # info:
2
+ # - compendium of all parameters & description
3
+ # - base for neutral fallback values if provided yml is sparse
4
+ # - -> it is encouraged to omit redundant parameters
5
+ ---
6
+ - datatype: VirtualSourceConfig
7
+ parameters:
8
+ id: 1000
9
+ name: neutral
10
+ description: Direct feed-through of energy environment with no converter (allows on-off-patters)
11
+ # General Config
12
+ enable_boost: false # if false -> v_intermediate = v_input, output-switch-hysteresis is still usable
13
+ enable_buck: false # if false -> v_output = v_intermediate
14
+
15
+ interval_startup_delay_drain_ms: 0
16
+
17
+ harvester:
18
+ name: mppt_opt # harvester only active if input is "ivcurves"
19
+
20
+ V_input_max_mV: 10000
21
+ I_input_max_mA: 4200
22
+ V_input_drop_mV: 0.0 # simulate input-diode
23
+ R_input_mOhm: 0.0 # resistance only active with disabled boost, range [1 mOhm; 1MOhm]
24
+
25
+ C_intermediate_uF: 0.0 # primary storage-Cap
26
+ V_intermediate_init_mV: 3000 # allow a proper / fast startup
27
+ I_intermediate_leak_nA: 0.0
28
+
29
+ V_intermediate_enable_threshold_mV: 1 # -> target gets connected (hysteresis-combo with next value)
30
+ V_intermediate_disable_threshold_mV: 0 # -> target gets disconnected
31
+ interval_check_thresholds_ms: 0.0 # some BQs check every 64 ms if output should be disconnected
32
+
33
+ V_pwr_good_enable_threshold_mV: 2800 # target is informed by pwr-good on output-pin (hysteresis) -> for intermediate voltage
34
+ V_pwr_good_disable_threshold_mV: 2200
35
+ immediate_pwr_good_signal: true # 1: activate instant schmitt-trigger, 0: stay in interval for checking thresholds
36
+
37
+ C_output_uF: 1.0 # final (always last) stage to compensate undetectable current spikes when enabling power for target
38
+
39
+ # Extra
40
+ V_output_log_gpio_threshold_mV: 1400 # min voltage needed to enable recording changes in gpio-bank
41
+
42
+ # Boost Converter
43
+ V_input_boost_threshold_mV: 0.0 # min input-voltage for the boost converter to work
44
+ V_intermediate_max_mV: 10000 # -> boost converter shuts off
45
+
46
+ LUT_input_efficiency: [
47
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ], # rows are current -> here a[V=0][:]
48
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
49
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
50
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
51
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
52
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
53
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
54
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
55
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
56
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
57
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
58
+ [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ],
59
+ ] # input-array[12][12] depending on array[inp_voltage][log(inp_current)], influence of cap-voltage is not implemented
60
+ LUT_input_V_min_log2_uV: 0 # 2^7 = 128 uV -> array[0] is for inputs < 128 uV
61
+ LUT_input_I_min_log2_nA: 0 # 2^8 = 256 nA -> array[0] is for inputs < 256 nA
62
+
63
+ # Buck-converter
64
+ V_output_mV: 2400
65
+ V_buck_drop_mV: 0.0 # simulate LDO min voltage differential or output-diode
66
+
67
+ LUT_output_efficiency: [ 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ] # array[12] depending on output_current
68
+ LUT_output_I_min_log2_nA: 0 # 2^8 = 256 nA -> array[0] is for inputs < 256 nA, see notes on LUT_input for explanation
69
+
70
+ owner: Ingmar
71
+ group: NES Lab
72
+ visible2group: true
73
+ visible2all: true
74
+ created: 2022-12-12 12:12:12
75
+ updated_last: 2022-12-12 12:12:12
76
+
77
+ - datatype: VirtualSourceConfig
78
+ parameters:
79
+ id: 1010
80
+ name: direct
81
+ inherit_from: neutral
82
+ # Note: current input has no influence
83
+
84
+ - datatype: VirtualSourceConfig
85
+ parameters:
86
+ id: 1011
87
+ name: diode+capacitor
88
+ description: Simple Converter based on diode and buffer capacitor
89
+ inherit_from: neutral
90
+ V_input_drop_mV: 300 # simulate input-diode
91
+ C_intermediate_uF: 10 # primary storage-Cap
92
+
93
+ - datatype: VirtualSourceConfig
94
+ parameters:
95
+ id: 1012
96
+ name: dio_cap # simpler naming
97
+ inherit_from: diode+capacitor
98
+
99
+ - datatype: VirtualSourceConfig
100
+ parameters:
101
+ id: 1013
102
+ name: diode+resistor+capacitor
103
+ description: Simple Converter based on diode, current limiting resistor and buffer capacitor
104
+ inherit_from: diode+capacitor
105
+ R_input_mOhm: 10000
106
+
107
+ - datatype: VirtualSourceConfig
108
+ parameters:
109
+ id: 1014
110
+ name: dio_res_cap # simpler naming
111
+ inherit_from: diode+resistor+capacitor
112
+
113
+ - datatype: VirtualSourceConfig
114
+ parameters:
115
+ id: 1020
116
+ name: BQ25504
117
+ description: TI BQ25504 with integrated boost-converter
118
+ inherit_from: neutral # to complete undefined vars
119
+ enable_boost: true # if false -> v_intermediate = v_input, output-switch-hysteresis is still usable
120
+
121
+ harvester:
122
+ name: mppt_bq_solar # harvester only active if input is "ivcurves"
123
+
124
+ V_input_max_mV: 3000
125
+ I_input_max_mA: 100
126
+
127
+ C_intermediate_uF: 22.0 # primary storage-Cap
128
+ V_intermediate_init_mV: 3000 # allow a proper / fast startup
129
+ I_intermediate_leak_nA: 330
130
+
131
+ V_intermediate_enable_threshold_mV: 2600 # -> target gets connected (hysteresis-combo with next value)
132
+ V_intermediate_disable_threshold_mV: 2300 # -> target gets disconnected
133
+ interval_check_thresholds_ms: 64.0 # some BQs check every 64 ms if output should be disconnected
134
+
135
+ V_pwr_good_enable_threshold_mV: 2800 # target is informed by pwr-good on output-pin (hysteresis) -> for intermediate voltage
136
+ V_pwr_good_disable_threshold_mV: 2400
137
+ immediate_pwr_good_signal: false # 1: activate instant schmitt-trigger, 0: stay in interval for checking thresholds
138
+
139
+ # Boost Converter
140
+ V_input_boost_threshold_mV: 130 # min input-voltage for the boost converter to work
141
+ V_intermediate_max_mV: 3600 # -> boost converter shuts off
142
+
143
+ LUT_input_efficiency: [
144
+ # <8uA 8uA 16uA 32uA 64uA 128uA 256uA 512uA 1mA 2mA 4mA >8mA
145
+ [ 0.01, 0.01, 0.02, 0.05, 0.10, 0.15, 0.15, 0.20, 0.25, 0.30, 0.30, 0.35 ], # < 128 mV
146
+ [ 0.10, 0.20, 0.30, 0.40, 0.50, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61 ], # > 128 mV, ~200
147
+ [ 0.20, 0.40, 0.50, 0.60, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72 ], # > 256 mV, ~320
148
+ [ 0.35, 0.55, 0.65, 0.71, 0.73, 0.74, 0.75, 0.75, 0.76, 0.77, 0.77, 0.78 ], # > 384 mV, ~450
149
+ [ 0.45, 0.65, 0.70, 0.73, 0.75, 0.77, 0.78, 0.79, 0.80, 0.81, 0.81, 0.82 ], # > 512 mV, ~570
150
+ [ 0.50, 0.70, 0.74, 0.76, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.83, 0.84 ], # > 640 mV
151
+ [ 0.52, 0.73, 0.76, 0.78, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.85, 0.86 ], # > 768 mV
152
+ [ 0.53, 0.75, 0.77, 0.79, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.86, 0.87 ], # > 896 mV
153
+ [ 0.55, 0.77, 0.78, 0.80, 0.82, 0.83, 0.85, 0.86, 0.87, 0.87, 0.87, 0.88 ], # > 1024 mV
154
+ [ 0.56, 0.78, 0.79, 0.81, 0.83, 0.85, 0.87, 0.88, 0.88, 0.88, 0.88, 0.89 ], # > 1152 mV
155
+ [ 0.58, 0.79, 0.80, 0.82, 0.84, 0.86, 0.88, 0.89, 0.89, 0.89, 0.89, 0.90 ], # > 1280 mV
156
+ [ 0.60, 0.80, 0.81, 0.83, 0.85, 0.87, 0.89, 0.90, 0.90, 0.90, 0.90, 0.90 ], # > 1408 mV
157
+ ] # input-array[12][12] depending on array[inp_voltage][log(inp_current)], influence of cap-voltage is not implemented
158
+ LUT_input_V_min_log2_uV: 17 # example: 2^7 = 128 uV -> array[0] is for inputs < 128 uV
159
+ LUT_input_I_min_log2_nA: 13 # example: 2^8 = 256 nA -> array[0] is for inputs < 256 nA
160
+
161
+ - datatype: VirtualSourceConfig
162
+ parameters:
163
+ id: 1021
164
+ name: BQ25504s # Version with Schmitt-Trigger
165
+ description: TI BQ25504 with Schmitt-Trigger for a faster power-good-signal
166
+ inherit_from: BQ25504
167
+ immediate_pwr_good_signal: true
168
+
169
+ - datatype: VirtualSourceConfig
170
+ parameters:
171
+ id: 1022
172
+ name: BQ25504-Schmitt
173
+ inherit_from: BQ25504s
174
+
175
+ - datatype: VirtualSourceConfig
176
+ parameters:
177
+ id: 1030
178
+ name: BQ25570
179
+ description: TI BQ25570 with integrated boost- & buck-converter
180
+ inherit_from: BQ25504 # inherit Input-LUT that is similar enough
181
+ enable_boost: true # if false -> v_intermediate = v_input, output-switch-hysteresis is still usable
182
+ enable_buck: true # if false -> v_output = v_intermediate
183
+
184
+ V_input_max_mV: 5100
185
+ I_input_max_mA: 100
186
+
187
+ C_intermediate_uF: 33.0 # primary storage-Cap
188
+ V_intermediate_init_mV: 3400 # allow a proper / fast startup
189
+ I_intermediate_leak_nA: 0.0
190
+
191
+ V_intermediate_enable_threshold_mV: 3000 # -> target gets connected (hysteresis-combo with next value)
192
+ V_intermediate_disable_threshold_mV: 2400 # -> target gets disconnected
193
+ interval_check_thresholds_ms: 64.0 # some BQs check every 64 ms if output should be disconnected
194
+
195
+ V_pwr_good_enable_threshold_mV: 3000 # target is informed by pwr-good on output-pin (hysteresis) -> for intermediate voltage
196
+ V_pwr_good_disable_threshold_mV: 2500
197
+ immediate_pwr_good_signal: false # 1: activate instant schmitt-trigger, 0: stay in interval for checking thresholds
198
+
199
+ C_output_uF: 1.0 # final (always last) stage to compensate undetectable current spikes when enabling power for target
200
+
201
+ # Boost Converter
202
+ V_input_boost_threshold_mV: 100.0 # min input-voltage for the boost converter to work
203
+ V_intermediate_max_mV: 5500 # -> boost converter shuts off
204
+
205
+ # Buck Converter
206
+ V_output_mV: 2200
207
+ V_buck_drop_mV: 200.0 # simulate LDO min voltage differential or output-diode
208
+
209
+ # <1u 1u 2u 4u 8u 16u 32u 64u 128u 256u 512u >1m
210
+ LUT_output_efficiency: [ 0.40, 0.50, 0.60, 0.73, 0.82, 0.86, 0.88, 0.90, 0.91, 0.92, 0.93, 0.92] # array[12] depending on output_current
211
+ LUT_output_I_min_log2_nA: 10 # example: 2^8 = 256 nA -> array[0] is for inputs < 256 nA, see notes on LUT_input for explanation
212
+
213
+ - datatype: VirtualSourceConfig
214
+ parameters:
215
+ id: 1031
216
+ name: BQ25570s
217
+ description: TI BQ25570 with Schmitt-Trigger for a faster power-good-signal
218
+ inherit_from: BQ25570
219
+ immediate_pwr_good_signal: true
220
+
221
+ - datatype: VirtualSourceConfig
222
+ parameters:
223
+ id: 1032
224
+ name: BQ25570-Schmitt
225
+ inherit_from: BQ25570s
226
+ - datatype: VirtualSourceConfig
227
+ parameters:
228
+ id: 1033
229
+ name: default
230
+ inherit_from: BQ25570s
@@ -1,4 +1,8 @@
1
- from ..testbed.cape import TargetPort
1
+ """Module for experiment related data-models.
2
+
3
+ These models import externally from: /base, /content, /testbed.
4
+ """
5
+
2
6
  from .experiment import Experiment
3
7
  from .observer_features import GpioActuation
4
8
  from .observer_features import GpioEvent
@@ -8,8 +12,6 @@ from .observer_features import PowerTracing
8
12
  from .observer_features import SystemLogging
9
13
  from .target_config import TargetConfig
10
14
 
11
- # these models import externally from: /base, /content, /testbed
12
-
13
15
  __all__ = [
14
16
  "Experiment",
15
17
  "TargetConfig",
@@ -21,5 +23,4 @@ __all__ = [
21
23
  "SystemLogging",
22
24
  # Enums
23
25
  "GpioLevel",
24
- "TargetPort",
25
26
  ]
@@ -1,3 +1,5 @@
1
+ """Config for testbed experiments."""
2
+
1
3
  from datetime import datetime
2
4
  from datetime import timedelta
3
5
  from typing import List
@@ -22,12 +24,10 @@ from .target_config import TargetConfig
22
24
 
23
25
 
24
26
  class Experiment(ShpModel, title="Config of an Experiment"):
25
- """Configuration for Experiments on the Shepherd-Testbed
26
- emulating Energy Environments for Target Nodes
27
- """
27
+ """Config for experiments on the testbed emulating energy environments for target nodes."""
28
28
 
29
29
  # General Properties
30
- # id: UUID4 ... # TODO db-migration - temp fix for documentation
30
+ # id: UUID4 ... # TODO: db-migration - temp fix for documentation
31
31
  id: Union[UUID4, int] = Field(default_factory=uuid4)
32
32
  # ⤷ TODO: automatic ID is problematic for identification by hash
33
33
 
@@ -90,7 +90,7 @@ class Experiment(ShpModel, title="Config of an Experiment"):
90
90
  obs_ids = [testbed.get_observer(_id).id for _id in target_ids]
91
91
  if len(target_ids) > len(set(obs_ids)):
92
92
  raise ValueError(
93
- "Observer used more than once in Experiment -> only 1 target per observer!"
93
+ "Observer is used more than once in Experiment -> only 1 target per observer!"
94
94
  )
95
95
 
96
96
  def get_target_ids(self) -> list:
@@ -101,4 +101,5 @@ class Experiment(ShpModel, title="Config of an Experiment"):
101
101
  if target_id in _config.target_IDs:
102
102
  return _config
103
103
  # gets already caught in target_config - but keep:
104
- raise ValueError(f"Target-ID {target_id} was not found in Experiment '{self.name}'")
104
+ msg = f"Target-ID {target_id} was not found in Experiment '{self.name}'"
105
+ raise ValueError(msg)
@@ -1,3 +1,5 @@
1
+ """Configs for observer features like gpio- & power-tracing."""
2
+
1
3
  from datetime import timedelta
2
4
  from enum import Enum
3
5
  from typing import List
@@ -15,7 +17,8 @@ from ..testbed.gpio import GPIO
15
17
 
16
18
 
17
19
  class PowerTracing(ShpModel, title="Config for Power-Tracing"):
18
- """Configuration for recording the Power-Consumption of the Target Nodes
20
+ """Configuration for recording the Power-Consumption of the Target Nodes.
21
+
19
22
  TODO: postprocessing not implemented ATM
20
23
  """
21
24
 
@@ -45,12 +48,13 @@ class PowerTracing(ShpModel, title="Config for Power-Tracing"):
45
48
  if not self.calculate_power and discard_all:
46
49
  raise ValueError("Error in config -> tracing enabled, but output gets discarded")
47
50
  if self.calculate_power:
48
- raise ValueError("postprocessing not implemented ATM")
51
+ raise NotImplementedError("postprocessing not implemented ATM")
49
52
  return self
50
53
 
51
54
 
52
55
  class GpioTracing(ShpModel, title="Config for GPIO-Tracing"):
53
- """Configuration for recording the GPIO-Output of the Target Nodes
56
+ """Configuration for recording the GPIO-Output of the Target Nodes.
57
+
54
58
  TODO: postprocessing not implemented ATM
55
59
  """
56
60
 
@@ -84,13 +88,15 @@ class GpioTracing(ShpModel, title="Config for GPIO-Tracing"):
84
88
 
85
89
 
86
90
  class GpioLevel(str, Enum):
91
+ """Options for setting the gpio-level or state."""
92
+
87
93
  low = "L"
88
94
  high = "H"
89
95
  toggle = "X" # TODO: not the smartest decision for writing a converter
90
96
 
91
97
 
92
98
  class GpioEvent(ShpModel, title="Config for a GPIO-Event"):
93
- """Configuration for a single GPIO-Event (Actuation)"""
99
+ """Configuration for a single GPIO-Event (Actuation)."""
94
100
 
95
101
  delay: PositiveFloat
96
102
  # ⤷ from start_time
@@ -104,7 +110,8 @@ class GpioEvent(ShpModel, title="Config for a GPIO-Event"):
104
110
  @model_validator(mode="after")
105
111
  def post_validation(self) -> Self:
106
112
  if not self.gpio.user_controllable():
107
- raise ValueError(f"GPIO '{self.gpio.name}' in actuation-event not controllable by user")
113
+ msg = f"GPIO '{self.gpio.name}' in actuation-event not controllable by user"
114
+ raise ValueError(msg)
108
115
  return self
109
116
 
110
117
  def get_events(self) -> np.ndarray:
@@ -113,7 +120,7 @@ class GpioEvent(ShpModel, title="Config for a GPIO-Event"):
113
120
 
114
121
 
115
122
  class GpioActuation(ShpModel, title="Config for GPIO-Actuation"):
116
- """Configuration for a GPIO-Actuation-Sequence"""
123
+ """Configuration for a GPIO-Actuation-Sequence."""
117
124
 
118
125
  # TODO: not implemented ATM - decide if pru control sys-gpio or
119
126
  # TODO: not implemented ATM - reverses pru-gpio (preferred if possible)
@@ -125,7 +132,7 @@ class GpioActuation(ShpModel, title="Config for GPIO-Actuation"):
125
132
 
126
133
 
127
134
  class SystemLogging(ShpModel, title="Config for System-Logging"):
128
- """Configuration for recording Debug-Output of the Observers System-Services"""
135
+ """Configuration for recording Debug-Output of the Observers System-Services."""
129
136
 
130
137
  dmesg: bool = True
131
138
  ptp: bool = True
@@ -1,3 +1,5 @@
1
+ """Configuration related to Target Nodes (DuT)."""
2
+
1
3
  from typing import List
2
4
  from typing import Optional
3
5
 
@@ -19,7 +21,7 @@ from .observer_features import PowerTracing
19
21
 
20
22
 
21
23
  class TargetConfig(ShpModel, title="Target Config"):
22
- """Configuration for Target Nodes (DuT)"""
24
+ """Configuration related to Target Nodes (DuT)."""
23
25
 
24
26
  target_IDs: Annotated[List[IdInt], Field(min_length=1, max_length=128)]
25
27
  custom_IDs: Optional[Annotated[List[IdInt16], Field(min_length=1, max_length=128)]] = None
@@ -44,7 +46,8 @@ class TargetConfig(ShpModel, title="Target Config"):
44
46
  @model_validator(mode="after")
45
47
  def post_validation(self) -> Self:
46
48
  if not self.energy_env.valid:
47
- raise ValueError(f"EnergyEnv '{self.energy_env.name}' for target must be valid")
49
+ msg = f"EnergyEnv '{self.energy_env.name}' for target must be valid"
50
+ raise ValueError(msg)
48
51
  for _id in self.target_IDs:
49
52
  target = Target(id=_id)
50
53
  for mcu_num in [1, 2]:
@@ -56,24 +59,25 @@ class TargetConfig(ShpModel, title="Target Config"):
56
59
  fw_def = Firmware(name=tgt_mcu.fw_name_default)
57
60
  # ⤷ this will raise if default is faulty
58
61
  if tgt_mcu.id != fw_def.mcu.id:
59
- raise ValueError(
62
+ msg = (
60
63
  f"Default-Firmware for MCU{mcu_num} of Target-ID '{target.id}' "
61
64
  f"(={fw_def.mcu.name}) "
62
65
  f"is incompatible (={tgt_mcu.name})"
63
66
  )
67
+ raise ValueError(msg)
64
68
  if has_fw and has_mcu and val_fw.mcu.id != tgt_mcu.id:
65
- raise ValueError(
69
+ msg = (
66
70
  f"Firmware{mcu_num} for MCU of Target-ID '{target.id}' "
67
71
  f"(={val_fw.mcu.name}) "
68
72
  f"is incompatible (={tgt_mcu.name})"
69
73
  )
74
+ raise ValueError(msg)
70
75
 
71
76
  c_ids = self.custom_IDs
72
77
  t_ids = self.target_IDs
73
78
  if c_ids is not None and (len(set(c_ids)) < len(set(t_ids))):
74
- raise ValueError(
75
- f"Provided custom IDs {c_ids} not enough to cover target range {t_ids}"
76
- )
79
+ msg = f"Provided custom IDs {c_ids} not enough to cover target range {t_ids}"
80
+ raise ValueError(msg)
77
81
  # TODO: if custom ids present, firmware must be ELF
78
82
  return self
79
83