shepherd-core 2025.6.4__py3-none-any.whl → 2025.10.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.
- shepherd_core/data_models/__init__.py +4 -2
- shepherd_core/data_models/base/content.py +2 -0
- shepherd_core/data_models/content/__init__.py +4 -2
- shepherd_core/data_models/content/{virtual_harvester.py → virtual_harvester_config.py} +3 -3
- shepherd_core/data_models/content/{virtual_source.py → virtual_source_config.py} +82 -58
- shepherd_core/data_models/content/virtual_source_fixture.yaml +24 -24
- shepherd_core/data_models/content/virtual_storage_config.py +426 -0
- shepherd_core/data_models/content/virtual_storage_fixture_creator.py +267 -0
- shepherd_core/data_models/content/virtual_storage_fixture_ideal.yaml +637 -0
- shepherd_core/data_models/content/virtual_storage_fixture_lead.yaml +49 -0
- shepherd_core/data_models/content/virtual_storage_fixture_lipo.yaml +735 -0
- shepherd_core/data_models/content/virtual_storage_fixture_mlcc.yaml +200 -0
- shepherd_core/data_models/content/virtual_storage_fixture_param_experiments.py +151 -0
- shepherd_core/data_models/content/virtual_storage_fixture_super.yaml +150 -0
- shepherd_core/data_models/content/virtual_storage_fixture_tantal.yaml +550 -0
- shepherd_core/data_models/experiment/observer_features.py +8 -2
- shepherd_core/data_models/experiment/target_config.py +1 -1
- shepherd_core/data_models/task/emulation.py +9 -6
- shepherd_core/data_models/task/firmware_mod.py +1 -0
- shepherd_core/data_models/task/harvest.py +4 -4
- shepherd_core/data_models/task/observer_tasks.py +5 -2
- shepherd_core/data_models/task/programming.py +1 -0
- shepherd_core/data_models/task/testbed_tasks.py +6 -1
- shepherd_core/decoder_waveform/uart.py +2 -1
- shepherd_core/fw_tools/patcher.py +60 -34
- shepherd_core/fw_tools/validation.py +7 -1
- shepherd_core/inventory/system.py +1 -1
- shepherd_core/reader.py +4 -3
- shepherd_core/version.py +1 -1
- shepherd_core/vsource/__init__.py +4 -0
- shepherd_core/vsource/virtual_converter_model.py +27 -26
- shepherd_core/vsource/virtual_harvester_model.py +27 -19
- shepherd_core/vsource/virtual_harvester_simulation.py +38 -39
- shepherd_core/vsource/virtual_source_model.py +17 -13
- shepherd_core/vsource/virtual_source_simulation.py +71 -73
- shepherd_core/vsource/virtual_storage_model.py +164 -0
- shepherd_core/vsource/virtual_storage_model_fixed_point_math.py +58 -0
- shepherd_core/vsource/virtual_storage_models_kibam.py +449 -0
- shepherd_core/vsource/virtual_storage_simulator.py +104 -0
- {shepherd_core-2025.6.4.dist-info → shepherd_core-2025.10.1.dist-info}/METADATA +4 -6
- {shepherd_core-2025.6.4.dist-info → shepherd_core-2025.10.1.dist-info}/RECORD +44 -32
- shepherd_core/data_models/virtual_source_doc.txt +0 -207
- {shepherd_core-2025.6.4.dist-info → shepherd_core-2025.10.1.dist-info}/WHEEL +0 -0
- {shepherd_core-2025.6.4.dist-info → shepherd_core-2025.10.1.dist-info}/top_level.txt +0 -0
- {shepherd_core-2025.6.4.dist-info → shepherd_core-2025.10.1.dist-info}/zip-safe +0 -0
|
@@ -14,7 +14,7 @@ import numpy as np
|
|
|
14
14
|
from tqdm import tqdm
|
|
15
15
|
|
|
16
16
|
from shepherd_core.data_models.base.calibration import CalibrationEmulator
|
|
17
|
-
from shepherd_core.data_models.content.
|
|
17
|
+
from shepherd_core.data_models.content.virtual_source_config import VirtualSourceConfig
|
|
18
18
|
from shepherd_core.logger import log
|
|
19
19
|
from shepherd_core.reader import Reader
|
|
20
20
|
from shepherd_core.writer import Writer
|
|
@@ -35,81 +35,79 @@ def simulate_source(
|
|
|
35
35
|
|
|
36
36
|
FN returns the consumed energy of the target.
|
|
37
37
|
"""
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
with ExitStack() as stack:
|
|
39
|
+
file_inp = Reader(path_input, verbose=False)
|
|
40
|
+
stack.enter_context(file_inp)
|
|
41
|
+
cal_emu = CalibrationEmulator()
|
|
42
|
+
cal_inp = file_inp.get_calibration_data()
|
|
43
|
+
|
|
44
|
+
if path_output:
|
|
45
|
+
file_out = Writer(
|
|
46
|
+
path_output, cal_data=cal_emu, mode="emulator", verbose=False, force_overwrite=True
|
|
47
|
+
)
|
|
48
|
+
stack.enter_context(file_out)
|
|
49
|
+
file_out.store_hostname("emu_sim_" + config.name)
|
|
50
|
+
file_out.store_config(config.model_dump())
|
|
51
|
+
cal_out = file_out.get_calibration_data()
|
|
52
|
+
|
|
53
|
+
src = VirtualSourceModel(
|
|
54
|
+
config,
|
|
55
|
+
cal_emu,
|
|
56
|
+
dtype_in=file_inp.get_datatype(),
|
|
57
|
+
log_intermediate=False,
|
|
58
|
+
window_size=file_inp.get_window_samples(),
|
|
59
|
+
voltage_step_V=file_inp.get_voltage_step(),
|
|
47
60
|
)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
i_out_nA = 0
|
|
62
|
-
e_out_Ws = 0.0
|
|
63
|
-
if monitor_internals and path_output:
|
|
64
|
-
stats_sample = 0
|
|
65
|
-
stats_internal = np.empty((round(file_inp.runtime_s * file_inp.samplerate_sps), 11))
|
|
66
|
-
try:
|
|
67
|
-
# keep dependencies low
|
|
68
|
-
from matplotlib import pyplot as plt
|
|
69
|
-
except ImportError:
|
|
70
|
-
log.warning("Matplotlib not installed, plotting of internals disabled")
|
|
61
|
+
i_out_nA = 0
|
|
62
|
+
e_out_Ws = 0.0
|
|
63
|
+
if monitor_internals and path_output:
|
|
64
|
+
stats_sample = 0
|
|
65
|
+
stats_internal = np.empty((round(file_inp.runtime_s * file_inp.samplerate_sps), 11))
|
|
66
|
+
try:
|
|
67
|
+
# keep dependencies low
|
|
68
|
+
from matplotlib import pyplot as plt # noqa: PLC0415
|
|
69
|
+
except ImportError:
|
|
70
|
+
log.warning("Matplotlib not installed, plotting of internals disabled")
|
|
71
|
+
stats_internal = None
|
|
72
|
+
else:
|
|
71
73
|
stats_internal = None
|
|
72
|
-
else:
|
|
73
|
-
stats_internal = None
|
|
74
|
-
|
|
75
|
-
for _t, v_inp, i_inp in tqdm(
|
|
76
|
-
file_inp.read(is_raw=True), total=file_inp.chunks_n, desc="Chunk", leave=False
|
|
77
|
-
):
|
|
78
|
-
v_uV = 1e6 * cal_inp.voltage.raw_to_si(v_inp)
|
|
79
|
-
i_nA = 1e9 * cal_inp.current.raw_to_si(i_inp)
|
|
80
|
-
|
|
81
|
-
for _n in range(len(_t)):
|
|
82
|
-
v_uV[_n] = src.iterate_sampling(
|
|
83
|
-
V_inp_uV=int(v_uV[_n]),
|
|
84
|
-
I_inp_nA=int(i_nA[_n]),
|
|
85
|
-
I_out_nA=i_out_nA,
|
|
86
|
-
)
|
|
87
|
-
i_out_nA = target.step(int(v_uV[_n]), pwr_good=src.cnv.get_power_good())
|
|
88
|
-
i_nA[_n] = i_out_nA
|
|
89
|
-
|
|
90
|
-
if stats_internal is not None:
|
|
91
|
-
stats_internal[stats_sample] = [
|
|
92
|
-
_t[_n] * 1e-9, # s
|
|
93
|
-
src.hrv.voltage_hold * 1e-6,
|
|
94
|
-
src.cnv.V_input_request_uV * 1e-6, # V
|
|
95
|
-
src.hrv.voltage_set_uV * 1e-6,
|
|
96
|
-
src.cnv.V_mid_uV * 1e-6,
|
|
97
|
-
src.hrv.current_hold * 1e-6, # mA
|
|
98
|
-
src.hrv.current_delta * 1e-6,
|
|
99
|
-
i_out_nA * 1e-6,
|
|
100
|
-
src.cnv.P_inp_fW * 1e-12, # mW
|
|
101
|
-
src.cnv.P_out_fW * 1e-12,
|
|
102
|
-
src.cnv.get_power_good(),
|
|
103
|
-
]
|
|
104
|
-
stats_sample += 1
|
|
105
|
-
|
|
106
|
-
e_out_Ws += (v_uV * i_nA).sum() * 1e-15 * file_inp.sample_interval_s
|
|
107
|
-
if path_output:
|
|
108
|
-
v_out = cal_out.voltage.si_to_raw(1e-6 * v_uV)
|
|
109
|
-
i_out = cal_out.current.si_to_raw(1e-9 * i_nA)
|
|
110
|
-
file_out.append_iv_data_raw(_t, v_out, i_out)
|
|
111
74
|
|
|
112
|
-
|
|
75
|
+
for _t, v_inp, i_inp in tqdm(
|
|
76
|
+
file_inp.read(is_raw=True), total=file_inp.chunks_n, desc="Chunk", leave=False
|
|
77
|
+
):
|
|
78
|
+
v_uV = 1e6 * cal_inp.voltage.raw_to_si(v_inp)
|
|
79
|
+
i_nA = 1e9 * cal_inp.current.raw_to_si(i_inp)
|
|
80
|
+
|
|
81
|
+
for _n in range(len(_t)):
|
|
82
|
+
v_uV[_n] = src.iterate_sampling(
|
|
83
|
+
V_inp_uV=int(v_uV[_n]),
|
|
84
|
+
I_inp_nA=int(i_nA[_n]),
|
|
85
|
+
I_out_nA=i_out_nA,
|
|
86
|
+
)
|
|
87
|
+
i_out_nA = target.step(int(v_uV[_n]), pwr_good=src.cnv.get_power_good())
|
|
88
|
+
i_nA[_n] = i_out_nA
|
|
89
|
+
|
|
90
|
+
if stats_internal is not None:
|
|
91
|
+
stats_internal[stats_sample] = [
|
|
92
|
+
_t[_n] * 1e-9, # s
|
|
93
|
+
src.hrv.voltage_hold * 1e-6,
|
|
94
|
+
src.cnv.V_input_request_uV * 1e-6, # V
|
|
95
|
+
src.hrv.voltage_set_uV * 1e-6,
|
|
96
|
+
src.cnv.V_mid_uV * 1e-6,
|
|
97
|
+
src.hrv.current_hold * 1e-6, # mA
|
|
98
|
+
src.hrv.current_delta * 1e-6,
|
|
99
|
+
i_out_nA * 1e-6,
|
|
100
|
+
src.cnv.P_inp_fW * 1e-12, # mW
|
|
101
|
+
src.cnv.P_out_fW * 1e-12,
|
|
102
|
+
src.cnv.get_power_good(),
|
|
103
|
+
]
|
|
104
|
+
stats_sample += 1
|
|
105
|
+
|
|
106
|
+
e_out_Ws += (v_uV * i_nA).sum() * 1e-15 * file_inp.sample_interval_s
|
|
107
|
+
if path_output:
|
|
108
|
+
v_out = cal_out.voltage.si_to_raw(1e-6 * v_uV)
|
|
109
|
+
i_out = cal_out.current.si_to_raw(1e-9 * i_nA)
|
|
110
|
+
file_out.append_iv_data_raw(_t, v_out, i_out)
|
|
113
111
|
|
|
114
112
|
if stats_internal is not None:
|
|
115
113
|
stats_internal = stats_internal[:stats_sample, :]
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""this is ported py-version of the pru-code.
|
|
2
|
+
|
|
3
|
+
Goals:
|
|
4
|
+
|
|
5
|
+
- stay close to original code-base (fixed-point integer math)
|
|
6
|
+
- offer a comparison for the tests
|
|
7
|
+
- step 1 to a virtualization of emulation
|
|
8
|
+
|
|
9
|
+
NOTE1: DO NOT OPTIMIZE -> stay close to original c-code-base
|
|
10
|
+
|
|
11
|
+
Compromises:
|
|
12
|
+
|
|
13
|
+
- Py has to map the settings-list to internal vars -> is kernel-task
|
|
14
|
+
|
|
15
|
+
Expected deviations:
|
|
16
|
+
|
|
17
|
+
- lead charge ramp maxes out early on cell-voltage (max of V_uV_n8 is 16.78 V)
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from pydantic import PositiveFloat
|
|
22
|
+
from pydantic import validate_call
|
|
23
|
+
|
|
24
|
+
from shepherd_core import log
|
|
25
|
+
from shepherd_core.data_models.content.virtual_storage_config import LuT_SIZE
|
|
26
|
+
from shepherd_core.data_models.content.virtual_storage_config import LuT_SIZE_LOG
|
|
27
|
+
from shepherd_core.data_models.content.virtual_storage_config import StoragePRUConfig
|
|
28
|
+
from shepherd_core.data_models.content.virtual_storage_config import TIMESTEP_s_DEFAULT
|
|
29
|
+
from shepherd_core.data_models.content.virtual_storage_config import VirtualStorageConfig
|
|
30
|
+
from shepherd_core.data_models.content.virtual_storage_config import soc_t
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ModelStorage:
|
|
34
|
+
"""Abstract base class for storage models."""
|
|
35
|
+
|
|
36
|
+
def step(self, I_charge_A: float) -> tuple[float, float, float, float]: ...
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def u32s(i: float) -> int:
|
|
40
|
+
"""Guard to supervise calculated model-states."""
|
|
41
|
+
if i >= 2**32:
|
|
42
|
+
log.warning("u32-overflow")
|
|
43
|
+
if i < 0:
|
|
44
|
+
log.warning("u32-underflow")
|
|
45
|
+
return int(min(max(i, 0), 2**32 - 1))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def u64s(i: float) -> int:
|
|
49
|
+
"""Guard to supervise calculated model-states."""
|
|
50
|
+
if i >= 2**64:
|
|
51
|
+
log.warning("u64-overflow")
|
|
52
|
+
if i < 0:
|
|
53
|
+
log.warning("u64-underflow")
|
|
54
|
+
return int(min(max(i, 0), 2**64 - 1))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class VirtualStorageModelPRU:
|
|
58
|
+
"""Ported python version of the pru vStorage.
|
|
59
|
+
|
|
60
|
+
This model should behave like ModelKiBaMSimple
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
SoC_MAX_1_n62: int = 2**62 - 1
|
|
64
|
+
SoC_TO_POS_DIV: int = 2 ** (62 - LuT_SIZE_LOG)
|
|
65
|
+
|
|
66
|
+
@validate_call
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
cfg: StoragePRUConfig,
|
|
70
|
+
SoC_init: soc_t | None = None,
|
|
71
|
+
) -> None:
|
|
72
|
+
self.cfg_pru = cfg
|
|
73
|
+
# state
|
|
74
|
+
SoC_1_n30: float = 2**30 * SoC_init if SoC_init is not None else self.cfg_pru.SoC_init_1_n30
|
|
75
|
+
self.SoC_1_n62 = round(2**32 * SoC_1_n30)
|
|
76
|
+
self.V_OC_uV_n8 = self.cfg_pru.LuT_VOC_uV_n8[self.pos_LuT(self.SoC_1_n62)]
|
|
77
|
+
|
|
78
|
+
def pos_LuT(self, SoC_1_n62: int) -> int:
|
|
79
|
+
pos = u32s(SoC_1_n62 // self.SoC_TO_POS_DIV)
|
|
80
|
+
if pos >= LuT_SIZE:
|
|
81
|
+
pos = LuT_SIZE - 1
|
|
82
|
+
return pos
|
|
83
|
+
|
|
84
|
+
def calc_V_OC_uV(self) -> int:
|
|
85
|
+
pos_LuT = self.pos_LuT(self.SoC_1_n62)
|
|
86
|
+
return round(self.cfg_pru.LuT_VOC_uV_n8[pos_LuT] // 2**8)
|
|
87
|
+
|
|
88
|
+
def step(self, I_delta_nA_n4: float, *, is_charging: bool) -> float:
|
|
89
|
+
"""Calculate the battery SoC & cell-voltage after drawing a current over a time-step.
|
|
90
|
+
|
|
91
|
+
Note: 3x u64 multiplications
|
|
92
|
+
"""
|
|
93
|
+
dSoC_leak_1_n62 = u64s((self.V_OC_uV_n8 // 2**6) * self.cfg_pru.Constant_1_per_uV_n60)
|
|
94
|
+
if self.SoC_1_n62 >= dSoC_leak_1_n62:
|
|
95
|
+
self.SoC_1_n62 = u64s(self.SoC_1_n62 - dSoC_leak_1_n62)
|
|
96
|
+
else:
|
|
97
|
+
self.SoC_1_n62 = 0
|
|
98
|
+
|
|
99
|
+
dSoC_1_n62 = u64s(I_delta_nA_n4 * self.cfg_pru.Constant_1_per_nA_n60 // (2**2))
|
|
100
|
+
if is_charging:
|
|
101
|
+
self.SoC_1_n62 = u64s(self.SoC_1_n62 + dSoC_1_n62)
|
|
102
|
+
self.SoC_1_n62 = min(self.SoC_MAX_1_n62, self.SoC_1_n62)
|
|
103
|
+
elif self.SoC_1_n62 > dSoC_1_n62:
|
|
104
|
+
self.SoC_1_n62 = u64s(self.SoC_1_n62 - dSoC_1_n62)
|
|
105
|
+
else:
|
|
106
|
+
self.SoC_1_n62 = 0
|
|
107
|
+
|
|
108
|
+
pos_LuT = self.pos_LuT(self.SoC_1_n62)
|
|
109
|
+
self.V_OC_uV_n8 = self.cfg_pru.LuT_VOC_uV_n8[pos_LuT]
|
|
110
|
+
# TODO: is interpolation possible?
|
|
111
|
+
R_series_kOhm_n32 = self.cfg_pru.LuT_RSeries_kOhm_n32[pos_LuT]
|
|
112
|
+
V_delta_uV_n8 = u32s(u64s(I_delta_nA_n4 * R_series_kOhm_n32) // 2**28)
|
|
113
|
+
|
|
114
|
+
if is_charging:
|
|
115
|
+
V_cell_uV_n8 = u32s(self.V_OC_uV_n8 + V_delta_uV_n8)
|
|
116
|
+
elif self.V_OC_uV_n8 > V_delta_uV_n8:
|
|
117
|
+
V_cell_uV_n8 = u32s(self.V_OC_uV_n8 - V_delta_uV_n8)
|
|
118
|
+
else:
|
|
119
|
+
V_cell_uV_n8 = 0
|
|
120
|
+
|
|
121
|
+
if self.SoC_1_n62 == 0:
|
|
122
|
+
return 0 # cell voltage breaks down
|
|
123
|
+
return V_cell_uV_n8 // 2**8 # u32 uV
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class VirtualStorageModel(VirtualStorageModelPRU, ModelStorage):
|
|
127
|
+
"""Higher level Model that can run on a coarser timebase.
|
|
128
|
+
|
|
129
|
+
This model should behave like ModelKiBaMSimple
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
@validate_call
|
|
133
|
+
def __init__(
|
|
134
|
+
self,
|
|
135
|
+
cfg: VirtualStorageConfig,
|
|
136
|
+
SoC_init: soc_t | None = None,
|
|
137
|
+
dt_s: PositiveFloat = TIMESTEP_s_DEFAULT,
|
|
138
|
+
*,
|
|
139
|
+
optimize_clamp: bool = True,
|
|
140
|
+
) -> None:
|
|
141
|
+
# metadata for simulator
|
|
142
|
+
self.cfg: VirtualStorageConfig = cfg
|
|
143
|
+
self.dt_s = dt_s
|
|
144
|
+
# prepare PRU-Model
|
|
145
|
+
cfg_pru = StoragePRUConfig.from_vstorage(
|
|
146
|
+
cfg, TIMESTEP_s_DEFAULT, optimize_clamp=optimize_clamp
|
|
147
|
+
)
|
|
148
|
+
super().__init__(cfg_pru, SoC_init=SoC_init)
|
|
149
|
+
|
|
150
|
+
# just for simulation
|
|
151
|
+
self.steps_per_frame = round(dt_s / TIMESTEP_s_DEFAULT)
|
|
152
|
+
|
|
153
|
+
def step(self, I_charge_A: float) -> tuple[float, float, float, float]:
|
|
154
|
+
"""Slower outer step with step-size of simulation."""
|
|
155
|
+
I_delta_nA_n4 = abs(2**4 * (1e9 * I_charge_A))
|
|
156
|
+
is_charging = I_charge_A >= 0
|
|
157
|
+
for _ in range(self.steps_per_frame - 1):
|
|
158
|
+
super().step(I_delta_nA_n4, is_charging=is_charging)
|
|
159
|
+
V_cell_uV = super().step(I_delta_nA_n4, is_charging=is_charging)
|
|
160
|
+
# code below just for simulation
|
|
161
|
+
V_OC = (1e-6 / 2**8) * self.V_OC_uV_n8
|
|
162
|
+
V_cell = 1e-6 * V_cell_uV
|
|
163
|
+
SoC = (1.0 / 2**62) * self.SoC_1_n62
|
|
164
|
+
return V_OC, V_cell, SoC, SoC
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Playground to determine the best integer-math and fit for constants."""
|
|
2
|
+
|
|
3
|
+
from itertools import product
|
|
4
|
+
|
|
5
|
+
from shepherd_core import log
|
|
6
|
+
from shepherd_core.data_models.content.virtual_storage_config import LuT_SIZE_LOG
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def u32l(i: float) -> int:
|
|
10
|
+
"""Guard to supervise calculated model-states."""
|
|
11
|
+
if i >= 2**32:
|
|
12
|
+
log.warning("u32-overflow (%d)", i)
|
|
13
|
+
if i < 0:
|
|
14
|
+
log.warning("u32-underflow (%d)", i)
|
|
15
|
+
return round(min(max(i, 0), 2**32 - 1))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# #### I_charge-to-dSoC #####
|
|
19
|
+
# Goal: Allow ~1 uF Capacitor to 800 mAh battery
|
|
20
|
+
|
|
21
|
+
dt_s = 10e-6
|
|
22
|
+
qs_As = [1e-6 * 1 * 2.0, 1e-6 * 5 * 2.5, 1e-6 * 10 * 3.6, 800 * 3.6]
|
|
23
|
+
Constant_1u_per_nA_n40 = [u32l((2**40 / 1e3) * dt_s / q_As) for q_As in qs_As]
|
|
24
|
+
Constant_1_per_nA_n60 = [u32l((2**60 / 1e9) * dt_s / q_As) for q_As in qs_As]
|
|
25
|
+
|
|
26
|
+
# #### SoC-to-position #####
|
|
27
|
+
# Goal: As-simple-as-possible
|
|
28
|
+
|
|
29
|
+
SoCs_1u_n32 = [round(x / 10 * 1e6 * 2**32) for x in range(11)]
|
|
30
|
+
LUT_SIZE = 128
|
|
31
|
+
|
|
32
|
+
# First Approach (1 Division in pos-calc -> impossible for PRU)
|
|
33
|
+
SoC_min_1u = round(1e6 / LUT_SIZE)
|
|
34
|
+
positions1 = [int(SoC_1u_n32 / SoC_min_1u / 2**32) for SoC_1u_n32 in SoCs_1u_n32]
|
|
35
|
+
|
|
36
|
+
# Second Approach
|
|
37
|
+
SoC_min = 1.0 / LUT_SIZE
|
|
38
|
+
inv_SoC_min_1M_n32 = round(2**32 / 1e6 / SoC_min) # 1M / SoC_min
|
|
39
|
+
positions2 = [
|
|
40
|
+
int(int(SoC_1u_n32 / 2**32) * inv_SoC_min_1M_n32 / 2**32) for SoC_1u_n32 in SoCs_1u_n32
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
# third approach
|
|
44
|
+
SoCs_1_n62 = [round(x / 10 * 2**62) for x in range(11)]
|
|
45
|
+
positions3 = [int(int(SoC_1_n62 / 2**32) * LUT_SIZE / 2**30) for SoC_1_n62 in SoCs_1_n62]
|
|
46
|
+
|
|
47
|
+
# final approach (upper u32 & rest of shift)
|
|
48
|
+
positions4 = [u32l(SoC_1_n62 // 2 ** (62 - LuT_SIZE_LOG)) for SoC_1_n62 in SoCs_1_n62]
|
|
49
|
+
|
|
50
|
+
# #### R_Leak-to-dSoC #####
|
|
51
|
+
# Goal: biggest possible dynamic range
|
|
52
|
+
|
|
53
|
+
Rs_leak_Ohm = [1e3, 10e3, 100e3, 1e6, 10e6]
|
|
54
|
+
Constants_1_per_V = [dt_s / q_As / R_leak_Ohm for q_As, R_leak_Ohm in product(qs_As, Rs_leak_Ohm)]
|
|
55
|
+
Constants_1u_per_uV_n40 = [u32l((2**40) * c_1_per_V) for c_1_per_V in Constants_1_per_V]
|
|
56
|
+
Constants_1_per_uV_n60 = [u32l((2**60 / 1e6) * c_1_per_V) for c_1_per_V in Constants_1_per_V]
|
|
57
|
+
|
|
58
|
+
print("done") # noqa: T201
|