shepherd-core 2024.7.4__tar.gz → 2024.8.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/PKG-INFO +1 -1
- shepherd_core-2024.8.2/examples/eenv_generator.py +43 -0
- shepherd_core-2024.7.4/examples/vharvester_simulation.py → shepherd_core-2024.8.2/examples/simulate_vharvester.py +23 -22
- shepherd_core-2024.8.2/examples/simulate_vsource.py +55 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/calibration.py +20 -22
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/virtual_harvester.py +18 -11
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +10 -13
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/virtual_source.py +6 -4
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/virtual_source_fixture.yaml +11 -9
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/reader.py +9 -4
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/version.py +1 -1
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/vsource/__init__.py +10 -0
- shepherd_core-2024.8.2/shepherd_core/vsource/target_model.py +62 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/vsource/virtual_converter_model.py +21 -6
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/vsource/virtual_harvester_model.py +18 -8
- shepherd_core-2024.8.2/shepherd_core/vsource/virtual_harvester_simulation.py +71 -0
- shepherd_core-2024.8.2/shepherd_core/vsource/virtual_source_simulation.py +78 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/writer.py +13 -3
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core.egg-info/PKG-INFO +1 -1
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core.egg-info/SOURCES.txt +7 -2
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/test_examples.py +3 -2
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/vsource/test_converter.py +10 -4
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/README.md +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/experiment_from_yaml.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/experiment_generic_var1.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/experiment_generic_var2.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/experiment_models.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/firmware_model.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/firmware_modification.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/inventory.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/uart_decode_waveform.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/examples/uart_raw2.csv +0 -0
- /shepherd_core-2024.7.4/examples/vsource_simulation.py → /shepherd_core-2024.8.2/examples/vsource_debug_sim.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/pyproject.toml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/setup.cfg +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/calibration_hw_def.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/commons.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/cal_measurement.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/content.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/shepherd.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/timezone.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/wrapper.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/_external_fixtures.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/energy_environment.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/firmware.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/experiment/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/experiment/experiment.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/experiment/observer_features.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/experiment/target_config.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/readme.md +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/task/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/task/emulation.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/task/firmware_mod.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/task/harvest.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/task/observer_tasks.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/task/programming.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/task/testbed_tasks.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/cape.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/gpio.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/mcu.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/observer.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/target.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/target_fixture.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/testbed.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/virtual_source_doc.txt +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/decoder_waveform/uart.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/fw_tools/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/fw_tools/converter.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/fw_tools/converter_elf.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/fw_tools/patcher.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/fw_tools/validation.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/inventory/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/inventory/python.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/inventory/system.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/inventory/target.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/logger.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/testbed_client/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/testbed_client/cache_path.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/testbed_client/client_abc_fix.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/testbed_client/client_web.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/testbed_client/fixtures.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/testbed_client/user_model.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/vsource/virtual_source_model.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core.egg-info/dependency_links.txt +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core.egg-info/requires.txt +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core.egg-info/top_level.txt +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core.egg-info/zip-safe +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/conftest.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/conftest.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_cal_data.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_cal_data_faulty.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_cal_meas.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_config_emulator.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_config_experiment.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_config_harvester.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_config_testbed.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/example_config_virtsource.yaml +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_base_models.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_content_fixtures.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_content_models.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_examples.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_experiment_models.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_task_generation.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_task_models.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_testbed_fixtures.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/data_models/test_testbed_models.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/decoder_waveform/test_decoder.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/fw_tools/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/fw_tools/build_msp.elf +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/fw_tools/build_nrf.elf +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/fw_tools/conftest.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/fw_tools/test_converter.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/fw_tools/test_patcher.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/fw_tools/test_validation.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/inventory/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/inventory/test_inventory.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/test_cal_hw.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/test_logger.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/test_reader.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/test_writer.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/testbed_client/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/vsource/__init__.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/vsource/conftest.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/vsource/test_harvester.py +0 -0
- {shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/tests/vsource/test_z.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: shepherd_core
|
|
3
|
-
Version: 2024.
|
|
3
|
+
Version: 2024.8.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>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Create a set of static artificial energy environments."""
|
|
2
|
+
|
|
3
|
+
from itertools import product
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from tqdm import trange
|
|
8
|
+
|
|
9
|
+
from shepherd_core import Reader as ShpReader
|
|
10
|
+
from shepherd_core import Writer as ShpWriter
|
|
11
|
+
from shepherd_core import logger
|
|
12
|
+
|
|
13
|
+
# Config
|
|
14
|
+
voltages_V = [4.0, 2.0]
|
|
15
|
+
currents_A = [2e-3, 1e-3]
|
|
16
|
+
duration_s = 10
|
|
17
|
+
repetitions = 1
|
|
18
|
+
|
|
19
|
+
path_here = Path(__file__).parent.absolute()
|
|
20
|
+
|
|
21
|
+
for _v, _c in product(voltages_V, currents_A):
|
|
22
|
+
v_str = f"{round(_v * 1000)}mV"
|
|
23
|
+
c_str = f"{round(_c * 1000)}mA"
|
|
24
|
+
t_str = f"{round(duration_s * repetitions)}s"
|
|
25
|
+
name = f"eenv_static_{v_str}_{c_str}_{t_str}"
|
|
26
|
+
file_path = path_here / f"{name}.h5"
|
|
27
|
+
|
|
28
|
+
if file_path.exists():
|
|
29
|
+
logger.info("File exists, will skip: %s", file_path.name)
|
|
30
|
+
else:
|
|
31
|
+
with ShpWriter(file_path) as file:
|
|
32
|
+
file.store_hostname("artificial")
|
|
33
|
+
# values in SI units
|
|
34
|
+
timestamp_vector = np.arange(0.0, duration_s, file.sample_interval_ns / 1e9)
|
|
35
|
+
voltage_vector = np.linspace(_v, _v, int(file.samplerate_sps * duration_s))
|
|
36
|
+
current_vector = np.linspace(_c, _c, int(file.samplerate_sps * duration_s))
|
|
37
|
+
|
|
38
|
+
for idx in trange(repetitions, desc="generate", leave=False):
|
|
39
|
+
timestamps = idx * duration_s + timestamp_vector
|
|
40
|
+
file.append_iv_data_si(timestamps, voltage_vector, current_vector)
|
|
41
|
+
|
|
42
|
+
with ShpReader(file_path) as file:
|
|
43
|
+
file.save_metadata()
|
|
@@ -4,14 +4,21 @@
|
|
|
4
4
|
- harvesting is done by various algorithms and preconfigured virtual harvesters
|
|
5
5
|
- results are printed on console (harvested energy)
|
|
6
6
|
|
|
7
|
+
Output:
|
|
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
|
|
14
|
+
E_out = 17.811 mWs -> mppt_opt
|
|
7
15
|
"""
|
|
8
16
|
|
|
9
17
|
from pathlib import Path
|
|
10
18
|
|
|
11
19
|
from shepherd_core import Reader
|
|
12
20
|
from shepherd_core.data_models import VirtualHarvesterConfig
|
|
13
|
-
from shepherd_core.
|
|
14
|
-
from shepherd_core.vsource import VirtualHarvesterModel
|
|
21
|
+
from shepherd_core.vsource import simulate_harvester
|
|
15
22
|
from shepherd_data import ivonne
|
|
16
23
|
|
|
17
24
|
# config simulation
|
|
@@ -32,6 +39,8 @@ hrv_list = [
|
|
|
32
39
|
"mppt_opt",
|
|
33
40
|
]
|
|
34
41
|
|
|
42
|
+
save_files: bool = False
|
|
43
|
+
|
|
35
44
|
# convert IVonne to IVCurve
|
|
36
45
|
if not file_ivcurve.exists():
|
|
37
46
|
with ivonne.Reader(file_ivonne) as db:
|
|
@@ -45,29 +54,21 @@ with Reader(file_ivcurve, verbose=False) as file:
|
|
|
45
54
|
I_in_max = max(I_in_max, _i.max())
|
|
46
55
|
print(
|
|
47
56
|
f"Input-file: \n"
|
|
48
|
-
f"\tE_in = {file.energy() * 1e3:.3f} mWs\n"
|
|
57
|
+
f"\tE_in = {file.energy() * 1e3:.3f} mWs (not representative)\n"
|
|
49
58
|
f"\tI_in_max = {I_in_max * 1e3:.3f} mA\n"
|
|
50
59
|
f"\twindow_size = {window_size} n\n",
|
|
51
60
|
)
|
|
52
61
|
|
|
53
62
|
# Simulation
|
|
54
63
|
for hrv_name in hrv_list:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
length = max(_v.size, _i.size)
|
|
67
|
-
for _n in range(length):
|
|
68
|
-
_v[_n], _i[_n] = hrv.ivcurve_sample(
|
|
69
|
-
_voltage_uV=_v[_n] * 10**6, _current_nA=_i[_n] * 10**9
|
|
70
|
-
)
|
|
71
|
-
E_out_Ws += (_v * _i).sum() * 1e-15 * file.sample_interval_s
|
|
72
|
-
|
|
73
|
-
print(f"E_out = {E_out_Ws * 1e3:.3f} mWs -> {hrv_name}")
|
|
64
|
+
file_output = (
|
|
65
|
+
file_ivcurve.with_name(file_ivcurve.stem + "_" + hrv_name + file_ivcurve.suffix)
|
|
66
|
+
if save_files
|
|
67
|
+
else None
|
|
68
|
+
)
|
|
69
|
+
E_out_Ws = simulate_harvester(
|
|
70
|
+
config=VirtualHarvesterConfig(name=hrv_name),
|
|
71
|
+
path_input=file_ivcurve,
|
|
72
|
+
path_output=file_output,
|
|
73
|
+
)
|
|
74
|
+
print(f"E_out = {E_out_Ws * 1e3:.3f} mWs -> {hrv_name}")
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Demonstrate behavior of Virtual Source Algorithms.
|
|
2
|
+
|
|
3
|
+
The emulation recreates an observer-cape, the virtual Source and a virtual target
|
|
4
|
+
- input = hdf5-file with a harvest-recording
|
|
5
|
+
- output = hdf5-file
|
|
6
|
+
- config is currently hardcoded, but it could be an emulation-task
|
|
7
|
+
- target is currently a simple resistor
|
|
8
|
+
|
|
9
|
+
The output file can be analyzed and plotted with shepherds tool suite.
|
|
10
|
+
|
|
11
|
+
Output:
|
|
12
|
+
E_out = 0.007 mWs -> direct
|
|
13
|
+
E_out = 0.033 mWs -> diode+capacitor
|
|
14
|
+
E_out = 0.033 mWs -> diode+resistor+capacitor
|
|
15
|
+
E_out = 14.964 mWs -> BQ25504
|
|
16
|
+
E_out = 15.042 mWs -> BQ25504s
|
|
17
|
+
E_out = 13.909 mWs -> BQ25570
|
|
18
|
+
E_out = 14.073 mWs -> BQ25570s
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from shepherd_core.data_models import VirtualSourceConfig
|
|
24
|
+
from shepherd_core.vsource import ConstantCurrentTarget
|
|
25
|
+
from shepherd_core.vsource import simulate_source
|
|
26
|
+
|
|
27
|
+
# config simulation
|
|
28
|
+
file_input = Path(__file__).parent / "jogging_ivcurve.h5"
|
|
29
|
+
|
|
30
|
+
src_list = [
|
|
31
|
+
"direct",
|
|
32
|
+
"diode+capacitor",
|
|
33
|
+
"diode+resistor+capacitor",
|
|
34
|
+
"BQ25504",
|
|
35
|
+
"BQ25504s",
|
|
36
|
+
"BQ25570",
|
|
37
|
+
"BQ25570s",
|
|
38
|
+
]
|
|
39
|
+
tgt = ConstantCurrentTarget(i_active_A=1e-3, i_sleep_A=200e-9)
|
|
40
|
+
save_files = False
|
|
41
|
+
|
|
42
|
+
for src_name in src_list:
|
|
43
|
+
file_output = (
|
|
44
|
+
file_input.with_name(file_input.stem + "_emu_" + src_name + file_input.suffix)
|
|
45
|
+
if save_files
|
|
46
|
+
else None
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
e_out_Ws = simulate_source(
|
|
50
|
+
config=VirtualSourceConfig(name=src_name),
|
|
51
|
+
target=tgt,
|
|
52
|
+
path_input=file_input,
|
|
53
|
+
path_output=file_output,
|
|
54
|
+
)
|
|
55
|
+
print(f"E_out = {e_out_Ws * 1e3:.3f} mWs -> {src_name}")
|
{shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/data_models/base/calibration.py
RENAMED
|
@@ -51,7 +51,7 @@ class CalibrationPair(ShpModel):
|
|
|
51
51
|
|
|
52
52
|
gain: PositiveFloat
|
|
53
53
|
offset: float = 0
|
|
54
|
-
# TODO: add
|
|
54
|
+
unit: Optional[str] = None # TODO: add units when used
|
|
55
55
|
|
|
56
56
|
def raw_to_si(self, values_raw: Calc_t, *, allow_negative: bool = True) -> Calc_t:
|
|
57
57
|
"""Convert between physical units and raw unsigned integers."""
|
|
@@ -78,14 +78,11 @@ class CalibrationPair(ShpModel):
|
|
|
78
78
|
return values_raw
|
|
79
79
|
|
|
80
80
|
@classmethod
|
|
81
|
-
def from_fn(cls, fn: Callable) -> Self:
|
|
81
|
+
def from_fn(cls, fn: Callable, unit: Optional[str] = None) -> Self:
|
|
82
82
|
"""Probe linear function to determine scaling values."""
|
|
83
83
|
offset = fn(0, limited=False)
|
|
84
84
|
gain_inv = fn(1.0, limited=False) - offset
|
|
85
|
-
return cls(
|
|
86
|
-
gain=1.0 / float(gain_inv),
|
|
87
|
-
offset=-float(offset) / gain_inv,
|
|
88
|
-
)
|
|
85
|
+
return cls(gain=1.0 / float(gain_inv), offset=-float(offset) / gain_inv, unit=unit)
|
|
89
86
|
|
|
90
87
|
|
|
91
88
|
cal_hrv_legacy = { # legacy translator
|
|
@@ -99,10 +96,10 @@ cal_hrv_legacy = { # legacy translator
|
|
|
99
96
|
class CalibrationHarvester(ShpModel):
|
|
100
97
|
"""Container for all calibration-pairs for that device."""
|
|
101
98
|
|
|
102
|
-
dac_V_Hrv: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw)
|
|
103
|
-
dac_V_Sim: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw)
|
|
104
|
-
adc_V_Sense: CalibrationPair = CalibrationPair.from_fn(adc_voltage_to_raw)
|
|
105
|
-
adc_C_Hrv: CalibrationPair = CalibrationPair.from_fn(adc_current_to_raw)
|
|
99
|
+
dac_V_Hrv: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw, unit="V")
|
|
100
|
+
dac_V_Sim: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw, unit="V")
|
|
101
|
+
adc_V_Sense: CalibrationPair = CalibrationPair.from_fn(adc_voltage_to_raw, unit="V")
|
|
102
|
+
adc_C_Hrv: CalibrationPair = CalibrationPair.from_fn(adc_current_to_raw, unit="A")
|
|
106
103
|
|
|
107
104
|
def export_for_sysfs(self) -> dict:
|
|
108
105
|
"""Convert and write the essential data.
|
|
@@ -143,10 +140,10 @@ class CalibrationEmulator(ShpModel):
|
|
|
143
140
|
Differentiates between both target-ports A/B.
|
|
144
141
|
"""
|
|
145
142
|
|
|
146
|
-
dac_V_A: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw)
|
|
147
|
-
dac_V_B: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw)
|
|
148
|
-
adc_C_A: CalibrationPair = CalibrationPair.from_fn(adc_current_to_raw)
|
|
149
|
-
adc_C_B: CalibrationPair = CalibrationPair.from_fn(adc_current_to_raw)
|
|
143
|
+
dac_V_A: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw, unit="V")
|
|
144
|
+
dac_V_B: CalibrationPair = CalibrationPair.from_fn(dac_voltage_to_raw, unit="V")
|
|
145
|
+
adc_C_A: CalibrationPair = CalibrationPair.from_fn(adc_current_to_raw, unit="A")
|
|
146
|
+
adc_C_B: CalibrationPair = CalibrationPair.from_fn(adc_current_to_raw, unit="A")
|
|
150
147
|
|
|
151
148
|
def export_for_sysfs(self) -> dict:
|
|
152
149
|
"""Convert and write the essential data.
|
|
@@ -233,10 +230,11 @@ class CalibrationCape(ShpModel):
|
|
|
233
230
|
|
|
234
231
|
"""
|
|
235
232
|
dv = cls().model_dump(include={"harvester", "emulator"})
|
|
236
|
-
|
|
237
|
-
|
|
233
|
+
lw1 = list(dict_generator(dv))
|
|
234
|
+
lw2 = [elem for elem in lw1 if isinstance(elem[-1], float)]
|
|
235
|
+
values = struct.unpack(">" + len(lw2) * "d", data)
|
|
238
236
|
# ⤷ X => double float, big endian
|
|
239
|
-
for _i, walk in enumerate(
|
|
237
|
+
for _i, walk in enumerate(lw2):
|
|
240
238
|
# hardcoded fixed depth ... bad but easy
|
|
241
239
|
dv[walk[0]][walk[1]][walk[2]] = float(values[_i])
|
|
242
240
|
dv["cape"] = cape
|
|
@@ -252,18 +250,18 @@ class CalibrationCape(ShpModel):
|
|
|
252
250
|
|
|
253
251
|
"""
|
|
254
252
|
lw = list(dict_generator(self.model_dump(include={"harvester", "emulator"})))
|
|
255
|
-
values = [walk[-1] for walk in lw]
|
|
256
|
-
return struct.pack(">" + len(
|
|
253
|
+
values = [walk[-1] for walk in lw if isinstance(walk[-1], float)]
|
|
254
|
+
return struct.pack(">" + len(values) * "d", *values)
|
|
257
255
|
|
|
258
256
|
|
|
259
257
|
class CalibrationSeries(ShpModel):
|
|
260
258
|
"""Cal-Data for a typical recording of a testbed experiment."""
|
|
261
259
|
|
|
262
|
-
voltage: CalibrationPair = CalibrationPair(gain=3 * 1e-9)
|
|
260
|
+
voltage: CalibrationPair = CalibrationPair(gain=3 * 1e-9, unit="V")
|
|
263
261
|
# ⤷ default allows 0 - 12 V in 3 nV-Steps
|
|
264
|
-
current: CalibrationPair = CalibrationPair(gain=250 * 1e-12)
|
|
262
|
+
current: CalibrationPair = CalibrationPair(gain=250 * 1e-12, unit="A")
|
|
265
263
|
# ⤷ default allows 0 - 1 A in 250 pA - Steps
|
|
266
|
-
time: CalibrationPair = CalibrationPair(gain=1e-9)
|
|
264
|
+
time: CalibrationPair = CalibrationPair(gain=1e-9, unit="s")
|
|
267
265
|
# ⤷ default = nanoseconds
|
|
268
266
|
|
|
269
267
|
@classmethod
|
|
@@ -149,20 +149,27 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
|
|
|
149
149
|
|
|
150
150
|
def calc_window_size(
|
|
151
151
|
self,
|
|
152
|
-
dtype_in: Optional[EnergyDType] =
|
|
152
|
+
dtype_in: Optional[EnergyDType] = None,
|
|
153
153
|
*,
|
|
154
154
|
for_emu: bool,
|
|
155
155
|
) -> int:
|
|
156
|
-
if for_emu:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
raise NotImplementedError
|
|
156
|
+
if not for_emu:
|
|
157
|
+
# TODO: should be named 'for_ivcurve_recording'
|
|
158
|
+
# TODO: add extra variable to distinguish step_count
|
|
159
|
+
# and window_size (currently mixed together)
|
|
160
|
+
# only used by ivcurve algo (in ADC-Mode)
|
|
161
|
+
return self.samples_n
|
|
163
162
|
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
if dtype_in is None:
|
|
164
|
+
dtype_in = self.get_datatype()
|
|
165
|
+
|
|
166
|
+
if dtype_in == EnergyDType.ivcurve:
|
|
167
|
+
return self.samples_n * (1 + self.wait_cycles)
|
|
168
|
+
if dtype_in == EnergyDType.ivsample:
|
|
169
|
+
return 0
|
|
170
|
+
if dtype_in == EnergyDType.isc_voc:
|
|
171
|
+
return 2 * (1 + self.wait_cycles)
|
|
172
|
+
raise NotImplementedError
|
|
166
173
|
|
|
167
174
|
|
|
168
175
|
u32 = Annotated[int, Field(ge=0, lt=2**32)]
|
|
@@ -234,7 +241,7 @@ class HarvesterPRUConfig(ShpModel):
|
|
|
234
241
|
dtype_in = EnergyDType[dtype_in]
|
|
235
242
|
if for_emu and dtype_in not in {EnergyDType.ivsample, EnergyDType.ivcurve}:
|
|
236
243
|
raise NotImplementedError
|
|
237
|
-
|
|
244
|
+
|
|
238
245
|
interval_ms, duration_ms = data.calc_timings_ms(for_emu=for_emu)
|
|
239
246
|
return cls(
|
|
240
247
|
algorithm=data.calc_algorithm_num(for_emu=for_emu),
|
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
id: 1010
|
|
20
20
|
name: ivcurve
|
|
21
21
|
description: Postpone harvesting by sampling ivcurves (voltage stepped as sawtooth-wave)
|
|
22
|
-
comment: ~
|
|
22
|
+
comment: ~110 Hz, Between 50 & 60 Hz line-frequency to avoid standing waves
|
|
23
23
|
inherit_from: neutral
|
|
24
24
|
algorithm: ivcurve
|
|
25
|
-
samples_n:
|
|
25
|
+
samples_n: 909
|
|
26
26
|
voltage_min_mV: 0
|
|
27
27
|
voltage_max_mV: 5000
|
|
28
|
-
wait_cycles:
|
|
28
|
+
wait_cycles: 0
|
|
29
29
|
rising: false # downward sawtooth seems to have advantages for solar cells
|
|
30
30
|
# todo: also add switch for sawtooth- vs triangle-wave?
|
|
31
31
|
# todo: could also include a version with dynamic upper-boundary, varied if voc is reached very early
|
|
@@ -38,20 +38,17 @@
|
|
|
38
38
|
|
|
39
39
|
- datatype: VirtualHarvesterConfig
|
|
40
40
|
parameters:
|
|
41
|
-
id:
|
|
42
|
-
name:
|
|
43
|
-
comment: Name relates to curves per second
|
|
41
|
+
id: 1013
|
|
42
|
+
name: iv110 # synonym
|
|
44
43
|
inherit_from: ivcurve
|
|
45
|
-
samples_n: 100
|
|
46
|
-
wait_cycles: 0
|
|
47
44
|
|
|
48
45
|
- datatype: VirtualHarvesterConfig
|
|
49
46
|
parameters:
|
|
50
|
-
id:
|
|
51
|
-
name:
|
|
52
|
-
comment:
|
|
47
|
+
id: 1012
|
|
48
|
+
name: iv1000
|
|
49
|
+
comment: Name relates to curves per second
|
|
53
50
|
inherit_from: ivcurve
|
|
54
|
-
samples_n:
|
|
51
|
+
samples_n: 100
|
|
55
52
|
wait_cycles: 0
|
|
56
53
|
|
|
57
54
|
- datatype: VirtualHarvesterConfig
|
|
@@ -61,7 +58,7 @@
|
|
|
61
58
|
description: Postpone harvesting by sampling short circuit current & open circuit voltage
|
|
62
59
|
inherit_from: neutral
|
|
63
60
|
algorithm: isc_voc
|
|
64
|
-
wait_cycles:
|
|
61
|
+
wait_cycles: 4 # results in 10 kHz (isc, wait, voc, wait)
|
|
65
62
|
|
|
66
63
|
- datatype: VirtualHarvesterConfig
|
|
67
64
|
parameters:
|
|
@@ -76,6 +76,8 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
76
76
|
# final (always last) stage to compensate undetectable current spikes
|
|
77
77
|
# when enabling power for target
|
|
78
78
|
C_output_uF: Annotated[float, Field(ge=0, le=4.29e6)] = 1.0
|
|
79
|
+
# TODO: C_output is handled internally as delta-V, but should be a I_transient
|
|
80
|
+
# that makes it visible in simulation as additional i_out_drain
|
|
79
81
|
|
|
80
82
|
# Extra
|
|
81
83
|
V_output_log_gpio_threshold_mV: Annotated[float, Field(ge=0, le=4.29e6)] = 1_400
|
|
@@ -93,7 +95,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
93
95
|
# influence of cap-voltage is not implemented
|
|
94
96
|
LUT_input_V_min_log2_uV: Annotated[int, Field(ge=0, le=20)] = 0
|
|
95
97
|
# ⤷ 2^7 = 128 uV -> LUT[0][:] is for inputs < 128 uV
|
|
96
|
-
LUT_input_I_min_log2_nA: Annotated[int, Field(ge=
|
|
98
|
+
LUT_input_I_min_log2_nA: Annotated[int, Field(ge=1, le=20)] = 1
|
|
97
99
|
# ⤷ 2^8 = 256 nA -> LUT[:][0] is for inputs < 256 nA
|
|
98
100
|
|
|
99
101
|
# Buck Converter
|
|
@@ -103,7 +105,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
103
105
|
|
|
104
106
|
LUT_output_efficiency: LUT1D = 12 * [1.00]
|
|
105
107
|
# ⤷ array[12] depending on output_current
|
|
106
|
-
LUT_output_I_min_log2_nA: Annotated[int, Field(ge=
|
|
108
|
+
LUT_output_I_min_log2_nA: Annotated[int, Field(ge=1, le=20)] = 1
|
|
107
109
|
# ⤷ 2^8 = 256 nA -> LUT[0] is for inputs < 256 nA, see notes on LUT_input for explanation
|
|
108
110
|
|
|
109
111
|
@model_validator(mode="before")
|
|
@@ -318,8 +320,8 @@ class ConverterPRUConfig(ShpModel):
|
|
|
318
320
|
V_buck_drop_uV=round(data.V_buck_drop_mV * 1e3),
|
|
319
321
|
# LUTs
|
|
320
322
|
LUT_input_V_min_log2_uV=data.LUT_input_V_min_log2_uV,
|
|
321
|
-
LUT_input_I_min_log2_nA=data.LUT_input_I_min_log2_nA,
|
|
322
|
-
LUT_output_I_min_log2_nA=data.LUT_output_I_min_log2_nA,
|
|
323
|
+
LUT_input_I_min_log2_nA=data.LUT_input_I_min_log2_nA - 1, # sub-1 due to later log2-op
|
|
324
|
+
LUT_output_I_min_log2_nA=data.LUT_output_I_min_log2_nA - 1, # sub-1 due to later log2
|
|
323
325
|
LUT_inp_efficiency_n8=[
|
|
324
326
|
[min(255, round(256 * ival)) for ival in il] for il in data.LUT_input_efficiency
|
|
325
327
|
],
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
interval_startup_delay_drain_ms: 0
|
|
16
16
|
|
|
17
17
|
harvester:
|
|
18
|
-
name: mppt_opt # harvester only active if input is "
|
|
18
|
+
name: mppt_opt # harvester only active if input is "ivcurve"
|
|
19
19
|
|
|
20
20
|
V_input_max_mV: 10000
|
|
21
21
|
I_input_max_mA: 4200
|
|
@@ -56,16 +56,18 @@
|
|
|
56
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
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
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
|
-
]
|
|
59
|
+
]
|
|
60
|
+
# input-array[12][12] depending on array[inp_voltage][log(inp_current)],
|
|
61
|
+
# influence of cap-voltage is not implemented
|
|
60
62
|
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:
|
|
63
|
+
LUT_input_I_min_log2_nA: 1 # 2^8 = 256 nA -> array[0] is for inputs < 256 nA
|
|
62
64
|
|
|
63
65
|
# Buck-converter
|
|
64
66
|
V_output_mV: 2400
|
|
65
67
|
V_buck_drop_mV: 0.0 # simulate LDO min voltage differential or output-diode
|
|
66
68
|
|
|
67
69
|
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:
|
|
70
|
+
LUT_output_I_min_log2_nA: 1 # 2^8 = 256 nA -> array[0] is for inputs < 256 nA, see notes on LUT_input for explanation
|
|
69
71
|
|
|
70
72
|
owner: Ingmar
|
|
71
73
|
group: NES Lab
|
|
@@ -114,7 +116,7 @@
|
|
|
114
116
|
parameters:
|
|
115
117
|
id: 1020
|
|
116
118
|
name: BQ25504
|
|
117
|
-
description: TI BQ25504 with integrated boost-converter
|
|
119
|
+
description: TI BQ25504 with integrated boost-converter. Values are taken from the DK-Board.
|
|
118
120
|
inherit_from: neutral # to complete undefined vars
|
|
119
121
|
enable_boost: true # if false -> v_intermediate = v_input, output-switch-hysteresis is still usable
|
|
120
122
|
|
|
@@ -124,16 +126,16 @@
|
|
|
124
126
|
V_input_max_mV: 3000
|
|
125
127
|
I_input_max_mA: 100
|
|
126
128
|
|
|
127
|
-
C_intermediate_uF:
|
|
129
|
+
C_intermediate_uF: 100.0 # primary storage-Cap
|
|
128
130
|
V_intermediate_init_mV: 3000 # allow a proper / fast startup
|
|
129
131
|
I_intermediate_leak_nA: 330
|
|
130
132
|
|
|
131
|
-
V_intermediate_enable_threshold_mV:
|
|
132
|
-
V_intermediate_disable_threshold_mV:
|
|
133
|
+
V_intermediate_enable_threshold_mV: 1000 # -> target gets connected (hysteresis-combo with next value)
|
|
134
|
+
V_intermediate_disable_threshold_mV: 0 # -> target gets disconnected
|
|
133
135
|
interval_check_thresholds_ms: 64.0 # some BQs check every 64 ms if output should be disconnected
|
|
134
136
|
|
|
135
137
|
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:
|
|
138
|
+
V_pwr_good_disable_threshold_mV: 2340
|
|
137
139
|
immediate_pwr_good_signal: false # 1: activate instant schmitt-trigger, 0: stay in interval for checking thresholds
|
|
138
140
|
|
|
139
141
|
# Boost Converter
|
|
@@ -84,6 +84,7 @@ class Reader:
|
|
|
84
84
|
|
|
85
85
|
# init stats
|
|
86
86
|
self.runtime_s: float = 0
|
|
87
|
+
self.buffers_n: int = 0
|
|
87
88
|
self.file_size: int = 0
|
|
88
89
|
self.data_rate: float = 0
|
|
89
90
|
|
|
@@ -170,12 +171,16 @@ class Reader:
|
|
|
170
171
|
def _refresh_file_stats(self) -> None:
|
|
171
172
|
"""Update internal states, helpful after resampling or other changes in data-group."""
|
|
172
173
|
self.h5file.flush()
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
sample_count = self.ds_time.shape[0]
|
|
175
|
+
duration_raw = self.ds_time[sample_count - 1] - self.ds_time[0] if sample_count > 0 else 0
|
|
176
|
+
if (sample_count > 0) and (duration_raw > 0):
|
|
177
|
+
# this assumes iso-chronous sampling
|
|
178
|
+
duration_s = self._cal.time.raw_to_si(duration_raw)
|
|
179
|
+
self.sample_interval_s = duration_s / sample_count
|
|
176
180
|
self.sample_interval_ns = int(10**9 * self.sample_interval_s)
|
|
177
|
-
self.samplerate_sps = max(int(
|
|
181
|
+
self.samplerate_sps = max(int((sample_count - 1) / duration_s), 1)
|
|
178
182
|
self.runtime_s = round(self.ds_voltage.shape[0] / self.samplerate_sps, 1)
|
|
183
|
+
self.buffers_n = int(self.ds_voltage.shape[0] // self.samples_per_buffer)
|
|
179
184
|
if isinstance(self.file_path, Path):
|
|
180
185
|
self.file_size = self.file_path.stat().st_size
|
|
181
186
|
else:
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
"""Simulation model of the virtual source."""
|
|
2
2
|
|
|
3
|
+
from .target_model import ConstantCurrentTarget
|
|
4
|
+
from .target_model import ConstantPowerTarget
|
|
5
|
+
from .target_model import ResistiveTarget
|
|
3
6
|
from .virtual_converter_model import PruCalibration
|
|
4
7
|
from .virtual_converter_model import VirtualConverterModel
|
|
5
8
|
from .virtual_harvester_model import VirtualHarvesterModel
|
|
9
|
+
from .virtual_harvester_simulation import simulate_harvester
|
|
6
10
|
from .virtual_source_model import VirtualSourceModel
|
|
11
|
+
from .virtual_source_simulation import simulate_source
|
|
7
12
|
|
|
8
13
|
__all__ = [
|
|
9
14
|
"PruCalibration",
|
|
10
15
|
"VirtualConverterModel",
|
|
11
16
|
"VirtualHarvesterModel",
|
|
12
17
|
"VirtualSourceModel",
|
|
18
|
+
"simulate_harvester",
|
|
19
|
+
"simulate_source",
|
|
20
|
+
"ResistiveTarget",
|
|
21
|
+
"ConstantCurrentTarget",
|
|
22
|
+
"ConstantPowerTarget",
|
|
13
23
|
]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Virtual targets with different characteristics.
|
|
2
|
+
|
|
3
|
+
TODO: add more targets
|
|
4
|
+
- diode
|
|
5
|
+
- constant power
|
|
6
|
+
- constant current
|
|
7
|
+
- msp430 (const I)
|
|
8
|
+
- nRF (constant power due to regulator)
|
|
9
|
+
- riotee
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from abc import ABC
|
|
13
|
+
from abc import abstractmethod
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TargetABC(ABC):
|
|
17
|
+
"""Abstract base class for all targets."""
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def step(self, voltage_uV: int, *, pwr_good: bool) -> float:
|
|
21
|
+
"""Calculate one time step and return drawn current in nA."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ResistiveTarget(TargetABC):
|
|
25
|
+
"""Predictable target for matching the real world."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, resistance_Ohm: float, *, controlled: bool = False) -> None:
|
|
28
|
+
if resistance_Ohm <= 1e-3:
|
|
29
|
+
raise ValueError("Resistance must be greater than 1 mOhm.")
|
|
30
|
+
self.r_kOhm = 1e-3 * resistance_Ohm
|
|
31
|
+
self.ctrl = controlled
|
|
32
|
+
|
|
33
|
+
def step(self, voltage_uV: int, *, pwr_good: bool) -> float:
|
|
34
|
+
if pwr_good or not self.ctrl:
|
|
35
|
+
return voltage_uV / self.r_kOhm # = nA
|
|
36
|
+
return 0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ConstantCurrentTarget(TargetABC):
|
|
40
|
+
"""Recreate simple MCU without integrated regulator."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, i_active_A: float, i_sleep_A: float = 0) -> None:
|
|
43
|
+
if i_active_A <= 0 or i_sleep_A <= 0:
|
|
44
|
+
raise ValueError("Current must be greater than 0.")
|
|
45
|
+
self.i_active_nA = 1e9 * i_active_A
|
|
46
|
+
self.i_sleep_nA = 1e9 * i_sleep_A
|
|
47
|
+
|
|
48
|
+
def step(self, voltage_uV: int, *, pwr_good: bool) -> float: # noqa: ARG002
|
|
49
|
+
return self.i_active_nA if pwr_good else self.i_sleep_nA
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ConstantPowerTarget(TargetABC):
|
|
53
|
+
"""Recreate MCU with integrated regulator."""
|
|
54
|
+
|
|
55
|
+
def __init__(self, p_active_W: float, p_sleep_W: float = 0) -> None:
|
|
56
|
+
if p_active_W <= 0 or p_sleep_W <= 0:
|
|
57
|
+
raise ValueError("Power must be greater than 0.")
|
|
58
|
+
self.p_active_fW = 1e15 * p_active_W
|
|
59
|
+
self.p_sleep_fW = 1e15 * p_sleep_W
|
|
60
|
+
|
|
61
|
+
def step(self, voltage_uV: int, *, pwr_good: bool) -> float:
|
|
62
|
+
return (self.p_active_fW if pwr_good else self.p_sleep_fW) / voltage_uV # = nA
|
{shepherd_core-2024.7.4 → shepherd_core-2024.8.2}/shepherd_core/vsource/virtual_converter_model.py
RENAMED
|
@@ -25,12 +25,28 @@ from ..data_models.content.virtual_source import ConverterPRUConfig
|
|
|
25
25
|
class PruCalibration:
|
|
26
26
|
"""part of calibration.h."""
|
|
27
27
|
|
|
28
|
+
# negative residue compensation - compensate for noise around 0
|
|
29
|
+
# -> current uint-design cuts away negative part and leads to biased mean()
|
|
30
|
+
NOISE_ESTIMATE_nA: int = 2000
|
|
31
|
+
RESIDUE_SIZE_FACTOR: int = 30
|
|
32
|
+
RESIDUE_MAX_nA: int = NOISE_ESTIMATE_nA * RESIDUE_SIZE_FACTOR
|
|
33
|
+
negative_residue_nA = 0
|
|
34
|
+
|
|
28
35
|
def __init__(self, cal_emu: Optional[CalibrationEmulator] = None) -> None:
|
|
29
36
|
self.cal = cal_emu if cal_emu else CalibrationEmulator()
|
|
30
37
|
|
|
31
38
|
def conv_adc_raw_to_nA(self, current_raw: int) -> float:
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
I_nA = self.cal.adc_C_A.raw_to_si(current_raw) * (10**9)
|
|
40
|
+
if self.cal.adc_C_A.offset < 0:
|
|
41
|
+
if I_nA > self.negative_residue_nA:
|
|
42
|
+
I_nA -= self.negative_residue_nA
|
|
43
|
+
self.negative_residue_nA = 0
|
|
44
|
+
else:
|
|
45
|
+
self.negative_residue_nA = self.negative_residue_nA - I_nA
|
|
46
|
+
if self.negative_residue_nA > self.RESIDUE_MAX_nA:
|
|
47
|
+
self.negative_residue_nA = self.RESIDUE_MAX_nA
|
|
48
|
+
I_nA = 0
|
|
49
|
+
return I_nA
|
|
34
50
|
|
|
35
51
|
@staticmethod
|
|
36
52
|
def conv_adc_raw_to_uV(voltage_raw: int) -> float:
|
|
@@ -88,10 +104,11 @@ class VirtualConverterModel:
|
|
|
88
104
|
self.vsource_skip_gpio_logging: bool = False
|
|
89
105
|
|
|
90
106
|
def calc_inp_power(self, input_voltage_uV: float, input_current_nA: float) -> int:
|
|
91
|
-
# Next 2 lines are Python-specific
|
|
107
|
+
# Next 2 lines are Python-specific (model unsigned int)
|
|
92
108
|
input_voltage_uV = max(0.0, input_voltage_uV)
|
|
93
109
|
input_current_nA = max(0.0, input_current_nA)
|
|
94
110
|
|
|
111
|
+
# Input diode
|
|
95
112
|
if input_voltage_uV > self._cfg.V_input_drop_uV:
|
|
96
113
|
input_voltage_uV -= self._cfg.V_input_drop_uV
|
|
97
114
|
else:
|
|
@@ -108,8 +125,6 @@ class VirtualConverterModel:
|
|
|
108
125
|
if self.enable_boost:
|
|
109
126
|
if input_voltage_uV < self._cfg.V_input_boost_threshold_uV:
|
|
110
127
|
input_voltage_uV = 0.0
|
|
111
|
-
if input_voltage_uV > self.V_mid_uV:
|
|
112
|
-
input_voltage_uV = self.V_mid_uV
|
|
113
128
|
elif not self.enable_storage:
|
|
114
129
|
# direct connection
|
|
115
130
|
self.V_mid_uV = input_voltage_uV
|
|
@@ -134,7 +149,7 @@ class VirtualConverterModel:
|
|
|
134
149
|
return round(self.P_inp_fW) # Python-specific, added for easier testing
|
|
135
150
|
|
|
136
151
|
def calc_out_power(self, current_adc_raw: int) -> int:
|
|
137
|
-
# Next 2 lines are Python-specific
|
|
152
|
+
# Next 2 lines are Python-specific (model unsigned int)
|
|
138
153
|
current_adc_raw = max(0, current_adc_raw)
|
|
139
154
|
current_adc_raw = min((2**18) - 1, current_adc_raw)
|
|
140
155
|
|