spikesafe-python 1.8.3__tar.gz → 1.10.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.
- {spikesafe_python-1.8.3/spikesafe_python.egg-info → spikesafe_python-1.10.2}/PKG-INFO +5 -2
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/README.md +2 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/pyproject.toml +1 -1
- spikesafe_python-1.10.2/spikesafe_python/Compensation.py +566 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/DigitizerData.py +2 -0
- spikesafe_python-1.10.2/spikesafe_python/DigitizerDataFetch.py +551 -0
- spikesafe_python-1.10.2/spikesafe_python/DigitizerInfo.py +40 -0
- spikesafe_python-1.10.2/spikesafe_python/Discharge.py +44 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/EventData.py +9 -4
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/MemoryTableReadData.py +21 -14
- spikesafe_python-1.10.2/spikesafe_python/Precision.py +264 -0
- spikesafe_python-1.10.2/spikesafe_python/PulseWidthCorrection.py +2620 -0
- spikesafe_python-1.10.2/spikesafe_python/ReadAllEvents.py +194 -0
- spikesafe_python-1.10.2/spikesafe_python/ScpiFormatter.py +53 -0
- spikesafe_python-1.10.2/spikesafe_python/SerialPortConnection.py +207 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/SpikeSafeError.py +2 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/SpikeSafeEvents.py +20 -6
- spikesafe_python-1.10.2/spikesafe_python/SpikeSafeInfo.py +91 -0
- spikesafe_python-1.10.2/spikesafe_python/SpikeSafeInfoParser.py +348 -0
- spikesafe_python-1.10.2/spikesafe_python/Threading.py +37 -0
- spikesafe_python-1.10.2/spikesafe_python/__init__.py +117 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2/spikesafe_python.egg-info}/PKG-INFO +5 -2
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python.egg-info/SOURCES.txt +11 -1
- spikesafe_python-1.10.2/tests/test_custom_compensation.py +66 -0
- spikesafe_python-1.10.2/tests/test_digitizer_fetch_time_of_sampling.py +509 -0
- spikesafe_python-1.10.2/tests/test_event_data.py +30 -0
- spikesafe_python-1.10.2/tests/test_event_data_old.py +30 -0
- spikesafe_python-1.10.2/tests/test_optimum_compensation.py +42 -0
- spikesafe_python-1.10.2/tests/test_optimum_pulse_width_correction.py +29 -0
- spikesafe_python-1.8.3/spikesafe_python/Compensation.py +0 -506
- spikesafe_python-1.8.3/spikesafe_python/DigitizerDataFetch.py +0 -465
- spikesafe_python-1.8.3/spikesafe_python/Discharge.py +0 -29
- spikesafe_python-1.8.3/spikesafe_python/Precision.py +0 -152
- spikesafe_python-1.8.3/spikesafe_python/PulseWidthCorrection.py +0 -2600
- spikesafe_python-1.8.3/spikesafe_python/ReadAllEvents.py +0 -158
- spikesafe_python-1.8.3/spikesafe_python/ScpiFormatter.py +0 -29
- spikesafe_python-1.8.3/spikesafe_python/Threading.py +0 -18
- spikesafe_python-1.8.3/spikesafe_python/__init__.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/LICENSE +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/setup.cfg +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/setup.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/ChannelData.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/DigitizerEnums.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/DigitizerVfCustomSequence.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/DigitizerVfCustomSequenceStep.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/SpikeSafeEnums.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/TcpSocket.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python/TemperatureData.py +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python.egg-info/dependency_links.txt +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python.egg-info/requires.txt +0 -0
- {spikesafe_python-1.8.3 → spikesafe_python-1.10.2}/spikesafe_python.egg-info/top_level.txt +0 -0
- /spikesafe_python-1.8.3/tests/test_custom_compensation.py → /spikesafe_python-1.10.2/tests/test_custom_compensation_old.py +0 -0
- /spikesafe_python-1.8.3/tests/test_digitizer_fetch_time_of_sampling.py → /spikesafe_python-1.10.2/tests/test_digitizer_fetch_time_of_sampling_old.py +0 -0
- /spikesafe_python-1.8.3/tests/test_optimum_compensation.py → /spikesafe_python-1.10.2/tests/test_optimum_compensation_old.py +0 -0
- /spikesafe_python-1.8.3/tests/test_optimum_pulse_width_correction.py → /spikesafe_python-1.10.2/tests/test_optimum_pulse_width_correction_old.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: spikesafe-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.2
|
|
4
4
|
Summary: SpikeSafe Python Library
|
|
5
5
|
Author-email: Vektrex <support@vektrex.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -10,6 +10,7 @@ Requires-Python: >=3.10
|
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Requires-Dist: jsonschema>=4.2.3
|
|
13
|
+
Dynamic: license-file
|
|
13
14
|
|
|
14
15
|
# spikesafe-python
|
|
15
16
|
|
|
@@ -25,6 +26,8 @@ GitHub Repository: [SpikeSafe Python Samples](https://github.com/VektrexElectron
|
|
|
25
26
|
|
|
26
27
|
Library help documentation: [spikesafe_python_lib_docs](https://github.com/VektrexElectronicSystems/SpikeSafePythonSamples/tree/master/spikesafe_python_lib_docs)
|
|
27
28
|
|
|
29
|
+
Release notes: [spikesafe_python_lib_docs/_releases](https://github.com/VektrexElectronicSystems/SpikeSafePythonSamples/tree/master/spikesafe_python_lib_docs/_releases)
|
|
30
|
+
|
|
28
31
|
## About
|
|
29
32
|
|
|
30
33
|
The **spikesafe-python** package provides light-weight access Python helper classes and functions to easily communicate with to your SpikeSafe and parse data into easy to use objects.
|
|
@@ -12,6 +12,8 @@ GitHub Repository: [SpikeSafe Python Samples](https://github.com/VektrexElectron
|
|
|
12
12
|
|
|
13
13
|
Library help documentation: [spikesafe_python_lib_docs](https://github.com/VektrexElectronicSystems/SpikeSafePythonSamples/tree/master/spikesafe_python_lib_docs)
|
|
14
14
|
|
|
15
|
+
Release notes: [spikesafe_python_lib_docs/_releases](https://github.com/VektrexElectronicSystems/SpikeSafePythonSamples/tree/master/spikesafe_python_lib_docs/_releases)
|
|
16
|
+
|
|
15
17
|
## About
|
|
16
18
|
|
|
17
19
|
The **spikesafe-python** package provides light-weight access Python helper classes and functions to easily communicate with to your SpikeSafe and parse data into easy to use objects.
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import jsonschema
|
|
3
|
+
from jsonschema import validate
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
from .SpikeSafeEnums import LoadImpedance, RiseTime
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
class Compensation():
|
|
11
|
+
"""
|
|
12
|
+
Provides a collection of helper functions you can use to help with SpikeSafe compensation settings.
|
|
13
|
+
|
|
14
|
+
...
|
|
15
|
+
|
|
16
|
+
Attributes
|
|
17
|
+
----------
|
|
18
|
+
custom_compensation_table_schema : dict
|
|
19
|
+
JSON schema to validate a custom compensation table
|
|
20
|
+
|
|
21
|
+
Methods
|
|
22
|
+
-------
|
|
23
|
+
Compensation.get_optimum_compensation(spikesafe_model_max_current_amps, set_current_amps, pulse_on_time_seconds = None, enable_logging = False)
|
|
24
|
+
Returns the optimum compensation for a given set current, and optionally a given pulse on time
|
|
25
|
+
Compensation.get_custom_compensation(spikesafe_model_max_current_amps, set_current_amps, device_type, custom_compensation_table, pulse_on_time_seconds = None, enable_logging = False)
|
|
26
|
+
Returns the custom compensation for a given set current, device type, and custom compensation table, and optionally a given pulse on time
|
|
27
|
+
Compensation.load_custom_compensation_table(file_path)
|
|
28
|
+
Loads a custom compensation table from a file path
|
|
29
|
+
Compensation.load_custom_compensation_unique_device_types(custom_compensation_table)
|
|
30
|
+
Returns a list of unique device types in a custom compensation table
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# Dictionary string constants
|
|
34
|
+
low_current_range_maximum = 'low_current_range_maximum'
|
|
35
|
+
load_impedance_high_range_1 = 'load_impedance_high_range_1'
|
|
36
|
+
rise_time_high_range_1 = 'rise_time_high_range_1'
|
|
37
|
+
load_impedance_high_range_2 = 'load_impedance_high_range_2'
|
|
38
|
+
rise_time_high_range_2 = 'rise_time_high_range_2'
|
|
39
|
+
load_impedance_high_range_3 = 'load_impedance_high_range_3'
|
|
40
|
+
rise_time_high_range_3 = 'rise_time_high_range_3'
|
|
41
|
+
load_impedance_low_range_1 = 'load_impedance_low_range_1'
|
|
42
|
+
rise_time_low_range_1 = 'rise_time_low_range_1'
|
|
43
|
+
load_impedance_low_range_2 = 'load_impedance_low_range_2'
|
|
44
|
+
rise_time_low_range_2 = 'rise_time_low_range_2'
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def get_optimum_compensation(spikesafe_model_max_current_amps, set_current_amps, pulse_on_time_seconds = None, enable_logging = False):
|
|
48
|
+
"""
|
|
49
|
+
Returns the optimum compensation for a given set current, and optionally a given pulse on time
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
spikesafe_model_max_current_amps : float
|
|
54
|
+
Maximum current of the SpikeSafe model
|
|
55
|
+
set_current_amps : float
|
|
56
|
+
Current to be set on SpikeSafe
|
|
57
|
+
pulse_on_time_seconds : float, optional
|
|
58
|
+
Pulse On Time to be set on SpikeSafe
|
|
59
|
+
enable_logging : bool, optional
|
|
60
|
+
Enables logging (default is False)
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
LoadImpedance
|
|
65
|
+
Load Impedance compensation value. This should be an instance of the LoadImpedance IntEnum from SpikeSafeEnums.
|
|
66
|
+
RiseTime
|
|
67
|
+
Rise Time compensation value. This should be an instance of the RiseTime IntEnum from SpikeSafeEnums.
|
|
68
|
+
|
|
69
|
+
Remarks
|
|
70
|
+
-------
|
|
71
|
+
This function assumes the set current is operating on the optimized current range. If operating on the high range with a set current normally programmed on the low range, the compensation values will not be optimal. See online specification for range limits.
|
|
72
|
+
|
|
73
|
+
If Load Impedance is returned as Medium or High, it is best practice to increase the Compliance Voltage setting by 5V to 30V. This helps the current amplifier to overcome inductance. If Compliance Voltage is not increased, then a Low Side Over Current or an Unstable Waveform error may occur.
|
|
74
|
+
|
|
75
|
+
If an Operating Mode is used to sweep through steps of currents where the compensation settings are the same across the sweep, such as Pulse Sweep or Multiple Pulse Burst, it is recommended use the optimum compensation settings targeting the Stop Current.
|
|
76
|
+
|
|
77
|
+
Raises
|
|
78
|
+
------
|
|
79
|
+
ValueError
|
|
80
|
+
If set_current_amps is greater than spikesafe_model_max_current_amps
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
if set_current_amps > spikesafe_model_max_current_amps:
|
|
84
|
+
raise ValueError(f'Measurement current {set_current_amps}A exceeds SpikeSafe model maximum current capability of {spikesafe_model_max_current_amps}A.')
|
|
85
|
+
|
|
86
|
+
# Non-pulsing, or DC based modes, do not require compensation
|
|
87
|
+
if pulse_on_time_seconds is None:
|
|
88
|
+
if enable_logging:
|
|
89
|
+
log.warning("DC based modes do not require compensation, defaulting to LoadImpedance.VERY_LOW and RiseTime.VERY_SLOW")
|
|
90
|
+
return LoadImpedance.VERY_LOW, RiseTime.VERY_SLOW
|
|
91
|
+
|
|
92
|
+
# Optimum compensation is intended for Pulse On Time of 500us or less
|
|
93
|
+
optimum_compensation_minimum_pulse_on_time_seconds = 0.0005
|
|
94
|
+
if pulse_on_time_seconds is not None and pulse_on_time_seconds > optimum_compensation_minimum_pulse_on_time_seconds:
|
|
95
|
+
if enable_logging:
|
|
96
|
+
log.warning(f"Compensation is intended for Pulse On Time of {optimum_compensation_minimum_pulse_on_time_seconds}s or less, defaulting to LoadImpedance.VERY_LOW and RiseTime.VERY_SLOW")
|
|
97
|
+
return LoadImpedance.VERY_LOW, RiseTime.VERY_SLOW
|
|
98
|
+
|
|
99
|
+
# Dictionary to store values for different model max currents
|
|
100
|
+
model_params = {
|
|
101
|
+
0.05: {
|
|
102
|
+
Compensation.low_current_range_maximum: 0.004,
|
|
103
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.MEDIUM,
|
|
104
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
105
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.VERY_LOW, Compensation.rise_time_high_range_3: RiseTime.SLOW,
|
|
106
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
107
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
108
|
+
},
|
|
109
|
+
0.5: {
|
|
110
|
+
Compensation.low_current_range_maximum: 0.04,
|
|
111
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
112
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
113
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
114
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
115
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
116
|
+
},
|
|
117
|
+
2: {
|
|
118
|
+
Compensation.low_current_range_maximum: 0.2,
|
|
119
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
120
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
121
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
122
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
123
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
124
|
+
},
|
|
125
|
+
3: {
|
|
126
|
+
Compensation.low_current_range_maximum: 0.2,
|
|
127
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
128
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
129
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
130
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
131
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
132
|
+
},
|
|
133
|
+
4: {
|
|
134
|
+
Compensation.low_current_range_maximum: 0.2,
|
|
135
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
136
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
137
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
138
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
139
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
140
|
+
},
|
|
141
|
+
5: {
|
|
142
|
+
Compensation.low_current_range_maximum: 0.2,
|
|
143
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
144
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
145
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
146
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
147
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
148
|
+
},
|
|
149
|
+
8: {
|
|
150
|
+
Compensation.low_current_range_maximum: 0.4,
|
|
151
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
152
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
153
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
154
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
155
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
156
|
+
},
|
|
157
|
+
# Tested for Mini 10A, but will also be used for PSMU HC 10A
|
|
158
|
+
10: {
|
|
159
|
+
Compensation.low_current_range_maximum: 0.4,
|
|
160
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
161
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
162
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
163
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
164
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
165
|
+
},
|
|
166
|
+
16: {
|
|
167
|
+
Compensation.low_current_range_maximum: 0.8,
|
|
168
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
169
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
170
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
171
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
172
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
173
|
+
},
|
|
174
|
+
20: {
|
|
175
|
+
Compensation.low_current_range_maximum: 0.8,
|
|
176
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
177
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
178
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
179
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
180
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
181
|
+
},
|
|
182
|
+
32: {
|
|
183
|
+
Compensation.low_current_range_maximum: 1.6,
|
|
184
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
185
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
186
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
187
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
188
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
189
|
+
},
|
|
190
|
+
40: {
|
|
191
|
+
Compensation.low_current_range_maximum: 1.6,
|
|
192
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
193
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
194
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
195
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
196
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
197
|
+
},
|
|
198
|
+
60: {
|
|
199
|
+
Compensation.low_current_range_maximum: 3.2,
|
|
200
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
201
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
202
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
203
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
204
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
205
|
+
},
|
|
206
|
+
80: {
|
|
207
|
+
Compensation.low_current_range_maximum: 3.2,
|
|
208
|
+
Compensation.load_impedance_high_range_1: LoadImpedance.MEDIUM, Compensation.rise_time_high_range_1: RiseTime.FAST,
|
|
209
|
+
Compensation.load_impedance_high_range_2: LoadImpedance.LOW, Compensation.rise_time_high_range_2: RiseTime.FAST,
|
|
210
|
+
Compensation.load_impedance_high_range_3: LoadImpedance.LOW, Compensation.rise_time_high_range_3: RiseTime.MEDIUM,
|
|
211
|
+
Compensation.load_impedance_low_range_1: LoadImpedance.HIGH, Compensation.rise_time_low_range_1: RiseTime.FAST,
|
|
212
|
+
Compensation.load_impedance_low_range_2: LoadImpedance.MEDIUM, Compensation.rise_time_low_range_2: RiseTime.FAST
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if spikesafe_model_max_current_amps not in model_params:
|
|
217
|
+
if enable_logging:
|
|
218
|
+
log.warning(f"{spikesafe_model_max_current_amps}A SpikeSafe Model not defined for optimum compensation, defaulting to LoadImpedance.MEDIUM and RiseTime.FAST")
|
|
219
|
+
return LoadImpedance.MEDIUM, RiseTime.FAST
|
|
220
|
+
|
|
221
|
+
model_params_current = model_params[spikesafe_model_max_current_amps]
|
|
222
|
+
|
|
223
|
+
if Compensation.__is_high_range__(set_current_amps, model_params_current):
|
|
224
|
+
load_impedance, rise_time = Compensation.__use_high_range_compensation__(spikesafe_model_max_current_amps, set_current_amps, model_params_current)
|
|
225
|
+
else:
|
|
226
|
+
load_impedance, rise_time = Compensation.__use_low_range_compensation__(set_current_amps, model_params_current)
|
|
227
|
+
|
|
228
|
+
if enable_logging:
|
|
229
|
+
log.info(f"Optimum compensation for {set_current_amps}A on {spikesafe_model_max_current_amps}A SpikeSafe model is LoadImpedance.{load_impedance} and RiseTime.{rise_time}.")
|
|
230
|
+
return load_impedance, rise_time
|
|
231
|
+
|
|
232
|
+
@staticmethod
|
|
233
|
+
def get_custom_compensation(spikesafe_model_max_current_amps, set_current_amps, device_type, custom_compensation_table, pulse_on_time_seconds=None, enable_logging=False):
|
|
234
|
+
"""
|
|
235
|
+
Returns the custom compensation values for a given set_current_amps and device_type based on a custom_compensation_table, and optionally a given pulse on time
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
spikesafe_model_max_current_amps : float
|
|
240
|
+
Maximum current of the SpikeSafe model
|
|
241
|
+
set_current_amps : float
|
|
242
|
+
Current to be set on SpikeSafe
|
|
243
|
+
device_type : str
|
|
244
|
+
Device type of the DUT
|
|
245
|
+
custom_compensation_table : list
|
|
246
|
+
Custom compensation table to be used for compensation. This should be the result of calling the load_custom_compensation_table(file_path) function conforming to the custom_compensation_table_schema.
|
|
247
|
+
pulse_on_time_seconds : float, optional
|
|
248
|
+
Pulse On Time to be set on SpikeSafe (default is None)
|
|
249
|
+
enable_logging : bool, optional
|
|
250
|
+
Enables logging (default is False)
|
|
251
|
+
|
|
252
|
+
Returns
|
|
253
|
+
-------
|
|
254
|
+
LoadImpedance
|
|
255
|
+
Load Impedance compensation value. This should be an instance of the LoadImpedance IntEnum from SpikeSafeEnums.
|
|
256
|
+
RiseTime
|
|
257
|
+
Rise Time compensation value. This should be an instance of the RiseTime IntEnum from SpikeSafeEnums.
|
|
258
|
+
|
|
259
|
+
Raises
|
|
260
|
+
------
|
|
261
|
+
ValueError
|
|
262
|
+
If set_current_amps is greater than spikesafe_model_max_current_amps
|
|
263
|
+
"""
|
|
264
|
+
# Validate the custom_compensation_table against the JSON schema
|
|
265
|
+
try:
|
|
266
|
+
validate(instance=custom_compensation_table, schema=Compensation.custom_compensation_table_schema)
|
|
267
|
+
except Exception:
|
|
268
|
+
raise Exception("Invalid Custom Compensation Table format. Please ensure 'custom_compensation_table' is correctly instantiated by calling 'load_custom_compensation_table(file_path)'.")
|
|
269
|
+
|
|
270
|
+
# Check if the set_current_amps exceeds the model's max current capability
|
|
271
|
+
if set_current_amps > spikesafe_model_max_current_amps:
|
|
272
|
+
raise ValueError(f'Measurement current {set_current_amps}A exceeds SpikeSafe model maximum current capability of {spikesafe_model_max_current_amps}A.')
|
|
273
|
+
|
|
274
|
+
# Non-pulsing or DC-based modes do not require compensation
|
|
275
|
+
if pulse_on_time_seconds is None or pulse_on_time_seconds > 0.0005:
|
|
276
|
+
return LoadImpedance.VERY_LOW, RiseTime.VERY_SLOW
|
|
277
|
+
|
|
278
|
+
# Preprocess the custom compensation table into a dictionary
|
|
279
|
+
compensation_dict = Compensation.__preprocess_compensation_table(custom_compensation_table)
|
|
280
|
+
|
|
281
|
+
# Find the default entry
|
|
282
|
+
default_load_impedance = None
|
|
283
|
+
default_rise_time = None
|
|
284
|
+
|
|
285
|
+
if (spikesafe_model_max_current_amps, device_type) in compensation_dict:
|
|
286
|
+
for entry in compensation_dict[(spikesafe_model_max_current_amps, device_type)]:
|
|
287
|
+
if entry.get('is_default', True):
|
|
288
|
+
default_load_impedance = entry['load_impedance']
|
|
289
|
+
default_rise_time = entry['rise_time']
|
|
290
|
+
break # Once default is found, stop the search
|
|
291
|
+
|
|
292
|
+
# Raise an error if no default entry was found
|
|
293
|
+
if default_load_impedance is None or default_rise_time is None:
|
|
294
|
+
raise ValueError(f'No default entry specified for spikesafe_model_max_current_amps {spikesafe_model_max_current_amps}A {device_type}. Please specify a default entry.')
|
|
295
|
+
|
|
296
|
+
# Find the target entry based on set_current_amps range
|
|
297
|
+
target_load_impedance = default_load_impedance # Start with default values
|
|
298
|
+
target_rise_time = default_rise_time
|
|
299
|
+
|
|
300
|
+
for entry in compensation_dict.get((spikesafe_model_max_current_amps, device_type), []):
|
|
301
|
+
# Check if set_current_amps is within the start and end range
|
|
302
|
+
if (set_current_amps >= entry['set_current_amps_start_range'] and set_current_amps < entry['set_current_amps_end_range']) or set_current_amps == entry['spikesafe_model_max_current_amps']:
|
|
303
|
+
target_load_impedance = entry['load_impedance']
|
|
304
|
+
target_rise_time = entry['rise_time']
|
|
305
|
+
break # Exit the loop once the first match is found
|
|
306
|
+
|
|
307
|
+
# Use the target entry if found, otherwise return the default entry
|
|
308
|
+
# Convert from string to IntEnum before returning
|
|
309
|
+
if enable_logging:
|
|
310
|
+
log.info(f"Custom compensation for {set_current_amps}A on {spikesafe_model_max_current_amps}A SpikeSafe model and device type '{device_type}' is LoadImpedance.{target_load_impedance} and RiseTime.{target_rise_time}.")
|
|
311
|
+
return LoadImpedance[target_load_impedance], RiseTime[target_rise_time]
|
|
312
|
+
|
|
313
|
+
@staticmethod
|
|
314
|
+
def load_custom_compensation_table(file_path):
|
|
315
|
+
"""
|
|
316
|
+
Returns a custom compensation table from a JSON file
|
|
317
|
+
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
file_path : str
|
|
321
|
+
Path to the JSON file containing the custom compensation table
|
|
322
|
+
|
|
323
|
+
Returns
|
|
324
|
+
-------
|
|
325
|
+
list
|
|
326
|
+
Custom compensation table as a list of dictionaries conforming to the custom_compensation_table_schema
|
|
327
|
+
|
|
328
|
+
Raises
|
|
329
|
+
------
|
|
330
|
+
FileNotFoundError
|
|
331
|
+
If the file does not exist
|
|
332
|
+
IOError
|
|
333
|
+
If an error occurs while loading the file
|
|
334
|
+
ValueError
|
|
335
|
+
If the file contains invalid JSON, schema validation error, or custom compensation table validation error
|
|
336
|
+
"""
|
|
337
|
+
# Check if the file exists
|
|
338
|
+
if not os.path.exists(file_path):
|
|
339
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
340
|
+
|
|
341
|
+
# Try to load the file and parse the JSON
|
|
342
|
+
try:
|
|
343
|
+
with open(file_path, 'r') as file:
|
|
344
|
+
custom_compensation_table = json.load(file)
|
|
345
|
+
except json.JSONDecodeError as e:
|
|
346
|
+
raise ValueError(f"Custom Compensation Table file contains invalid JSON: {str(e)}")
|
|
347
|
+
except Exception as e:
|
|
348
|
+
raise IOError(f"An error occurred while loading the Custom Compensation Table file: {str(e)}")
|
|
349
|
+
|
|
350
|
+
# Validate the JSON against the schema
|
|
351
|
+
try:
|
|
352
|
+
validate(instance=custom_compensation_table, schema=Compensation.custom_compensation_table_schema)
|
|
353
|
+
except jsonschema.ValidationError as e:
|
|
354
|
+
raise ValueError(f"Custom Compensation Table file schema validation error: {e.message} in element {list(e.path)}")
|
|
355
|
+
except jsonschema.SchemaError as e:
|
|
356
|
+
raise ValueError(f"Custom Compensation Table file schema definition error: {e.message}")
|
|
357
|
+
|
|
358
|
+
Compensation.__validate_custom_compensation_table(custom_compensation_table)
|
|
359
|
+
|
|
360
|
+
return custom_compensation_table
|
|
361
|
+
|
|
362
|
+
@staticmethod
|
|
363
|
+
def load_custom_compensation_unique_device_types(custom_compensation_table):
|
|
364
|
+
"""
|
|
365
|
+
Returns the unique device types from a custom compensation table
|
|
366
|
+
|
|
367
|
+
Parameters
|
|
368
|
+
----------
|
|
369
|
+
custom_compensation_table : list
|
|
370
|
+
Custom compensation table to be used for compensation. This should be the result of calling the load_custom_compensation_table(file_path) function conforming to the custom_compensation_table_schema
|
|
371
|
+
|
|
372
|
+
Returns
|
|
373
|
+
-------
|
|
374
|
+
list
|
|
375
|
+
List of unique device types in the custom compensation table
|
|
376
|
+
"""
|
|
377
|
+
device_types = {entry['device_type'] for entry in custom_compensation_table}
|
|
378
|
+
return list(device_types)
|
|
379
|
+
|
|
380
|
+
# Helper function to determine if high current range should be used
|
|
381
|
+
@staticmethod
|
|
382
|
+
def __is_high_range__(set_current_amps, model_params_current):
|
|
383
|
+
if set_current_amps > model_params_current[Compensation.low_current_range_maximum]:
|
|
384
|
+
return True
|
|
385
|
+
else:
|
|
386
|
+
return False
|
|
387
|
+
|
|
388
|
+
# Helper function to use high current range compensation settings
|
|
389
|
+
@staticmethod
|
|
390
|
+
def __use_high_range_compensation__(spikesafe_model_max_current_amps, set_current_amps, model_params_current):
|
|
391
|
+
range_ratio = set_current_amps / spikesafe_model_max_current_amps
|
|
392
|
+
if range_ratio < 0.5:
|
|
393
|
+
return model_params_current[Compensation.load_impedance_high_range_1], model_params_current[Compensation.rise_time_high_range_1]
|
|
394
|
+
elif range_ratio < 0.7:
|
|
395
|
+
return model_params_current[Compensation.load_impedance_high_range_2], model_params_current[Compensation.rise_time_high_range_2]
|
|
396
|
+
else:
|
|
397
|
+
return model_params_current[Compensation.load_impedance_high_range_3], model_params_current[Compensation.rise_time_high_range_3]
|
|
398
|
+
|
|
399
|
+
# Helper function to use low current range compensation settings
|
|
400
|
+
@staticmethod
|
|
401
|
+
def __use_low_range_compensation__(set_current_amps, model_params_current):
|
|
402
|
+
range_ratio = set_current_amps / model_params_current[Compensation.low_current_range_maximum]
|
|
403
|
+
if range_ratio < 0.7:
|
|
404
|
+
return model_params_current[Compensation.load_impedance_low_range_1], model_params_current[Compensation.rise_time_low_range_1]
|
|
405
|
+
else:
|
|
406
|
+
return model_params_current[Compensation.load_impedance_low_range_2], model_params_current[Compensation.rise_time_low_range_2]
|
|
407
|
+
|
|
408
|
+
# Define the schema for validation
|
|
409
|
+
custom_compensation_table_schema = {
|
|
410
|
+
"type": "array",
|
|
411
|
+
"minItems": 1,
|
|
412
|
+
"items": {
|
|
413
|
+
"type": "object",
|
|
414
|
+
"properties": {
|
|
415
|
+
"spikesafe_model_max_current_amps": {
|
|
416
|
+
"type": "number",
|
|
417
|
+
"minimum": 0
|
|
418
|
+
},
|
|
419
|
+
"device_type": {"type": "string"},
|
|
420
|
+
"is_default": {"type": "boolean"},
|
|
421
|
+
"set_current_amps_start_range": {
|
|
422
|
+
"type": "number",
|
|
423
|
+
"minimum": 0
|
|
424
|
+
},
|
|
425
|
+
"set_current_amps_end_range": {
|
|
426
|
+
"type": "number",
|
|
427
|
+
"minimum": 0
|
|
428
|
+
},
|
|
429
|
+
"load_impedance": {
|
|
430
|
+
"type": "string",
|
|
431
|
+
"enum": ["HIGH", "MEDIUM", "LOW", "VERY_LOW"]
|
|
432
|
+
},
|
|
433
|
+
"rise_time": {
|
|
434
|
+
"type": "string",
|
|
435
|
+
"enum": ["FAST", "MEDIUM", "LOW", "VERY_SLOW"]
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
"required": [
|
|
439
|
+
"spikesafe_model_max_current_amps",
|
|
440
|
+
"device_type",
|
|
441
|
+
"is_default",
|
|
442
|
+
"set_current_amps_start_range",
|
|
443
|
+
"set_current_amps_end_range",
|
|
444
|
+
"load_impedance",
|
|
445
|
+
"rise_time"
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
@staticmethod
|
|
451
|
+
def __preprocess_compensation_table(custom_compensation_table):
|
|
452
|
+
compensation_dict = {}
|
|
453
|
+
for entry in custom_compensation_table:
|
|
454
|
+
key = (entry['spikesafe_model_max_current_amps'], entry['device_type'])
|
|
455
|
+
if key not in compensation_dict:
|
|
456
|
+
compensation_dict[key] = []
|
|
457
|
+
compensation_dict[key].append(entry)
|
|
458
|
+
return compensation_dict
|
|
459
|
+
|
|
460
|
+
@staticmethod
|
|
461
|
+
def __validate_custom_compensation_table(custom_compensation_table):
|
|
462
|
+
# Group entries by unique combination of "spikesafe_model_max_current_amps" and "device_type"
|
|
463
|
+
# e.g. (5.0, "laser_green"): [
|
|
464
|
+
# (0, { "spikesafe_model_max_current_amps": 5.0, "device_type": "laser_green" ... }),
|
|
465
|
+
# (1, { "spikesafe_model_max_current_amps": 5.0, "device_type": "laser_green" ... }),
|
|
466
|
+
# ...],
|
|
467
|
+
grouped_entries = {}
|
|
468
|
+
|
|
469
|
+
# Perform validations on each element
|
|
470
|
+
for index, entry in enumerate(custom_compensation_table):
|
|
471
|
+
Compensation.__validate_element_set_current_ranges(entry, index)
|
|
472
|
+
|
|
473
|
+
# Group by max current and device type
|
|
474
|
+
combination_key = (entry["spikesafe_model_max_current_amps"], entry["device_type"])
|
|
475
|
+
|
|
476
|
+
# Check if the combination_key already exists in grouped_entries
|
|
477
|
+
if combination_key not in grouped_entries:
|
|
478
|
+
grouped_entries[combination_key] = [] # Initialize with an empty list if it does not exist
|
|
479
|
+
|
|
480
|
+
# Append the current index and entry to the list for this combination_key
|
|
481
|
+
grouped_entries[combination_key].append((index, entry))
|
|
482
|
+
|
|
483
|
+
# Perform validations on each group
|
|
484
|
+
for (spikesafe_model_max_current_amps, device_type), entries in grouped_entries.items():
|
|
485
|
+
Compensation.__validate_group_has_is_default(entries, spikesafe_model_max_current_amps, device_type)
|
|
486
|
+
Compensation.__validate_group_set_current_ranges(entries, spikesafe_model_max_current_amps, device_type)
|
|
487
|
+
|
|
488
|
+
@staticmethod
|
|
489
|
+
def __validate_element_set_current_ranges(entry, index):
|
|
490
|
+
# Validation Rule: Validate that set_current_amps_start_range is less than or equal to set_current_amps_end_range
|
|
491
|
+
if entry['set_current_amps_start_range'] > entry['set_current_amps_end_range']:
|
|
492
|
+
raise ValueError(
|
|
493
|
+
f"'set_current_amps_start_range' ({entry['set_current_amps_start_range']}) cannot be greater than "
|
|
494
|
+
f"'set_current_amps_end_range' ({entry['set_current_amps_end_range']}) in element [{index}]"
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
@staticmethod
|
|
498
|
+
def __validate_group_has_is_default(entries, spikesafe_model_max_current_amps, device_type):
|
|
499
|
+
# Validation Rule: Ensure each group has exactly one "is_default" set to True
|
|
500
|
+
|
|
501
|
+
# Initialize a list to store entries with "is_default" set to True
|
|
502
|
+
defaults = []
|
|
503
|
+
|
|
504
|
+
# Iterate through each entry to check for the "is_default" flag
|
|
505
|
+
for index, entry in entries: # entry is a tuple (index, entry)
|
|
506
|
+
if entry['is_default']: # Access the dictionary part of the tuple
|
|
507
|
+
defaults.append(entry) # Append the dictionary to defaults
|
|
508
|
+
|
|
509
|
+
num_defaults = len(defaults)
|
|
510
|
+
|
|
511
|
+
if num_defaults == 0:
|
|
512
|
+
raise ValueError(f"No 'is_default' true entry found for combination: "
|
|
513
|
+
f"'spikesafe_model_max_current_amps' {spikesafe_model_max_current_amps}, 'device_type' {device_type}")
|
|
514
|
+
|
|
515
|
+
if num_defaults > 1:
|
|
516
|
+
raise ValueError(f"Multiple 'is_default' true entries found for combination: "
|
|
517
|
+
f"'spikesafe_model_max_current_amps' {spikesafe_model_max_current_amps}, 'device_type' {device_type}")
|
|
518
|
+
|
|
519
|
+
@staticmethod
|
|
520
|
+
def __validate_group_set_current_ranges(entries, spikesafe_model_max_current_amps, device_type):
|
|
521
|
+
# Validation Rule: Ensure that the ranges do not overlap
|
|
522
|
+
# Sort entries by set_current_amps_start_range to validate range continuity
|
|
523
|
+
sorted_entries = sorted(entries, key=lambda x: x[1]['set_current_amps_start_range'])
|
|
524
|
+
|
|
525
|
+
for i in range(1, len(sorted_entries)):
|
|
526
|
+
prev_index, prev_entry = sorted_entries[i - 1]
|
|
527
|
+
current_index, current_entry = sorted_entries[i]
|
|
528
|
+
|
|
529
|
+
# Check if the previous end range is greater than the current start range (overlap)
|
|
530
|
+
if prev_entry['set_current_amps_end_range'] > current_entry['set_current_amps_start_range']:
|
|
531
|
+
raise ValueError(
|
|
532
|
+
f"Set Current Range Overlap detected: 'set_current_amps_start_range' ({current_entry['set_current_amps_start_range']}) "
|
|
533
|
+
f"overlaps with element {prev_index} 'set_current_amps_end_range' ({prev_entry['set_current_amps_end_range']}) "
|
|
534
|
+
f"in element [{current_index}] for device_type: {device_type}, max current: {spikesafe_model_max_current_amps}"
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
# Optionally, check for gaps in the range
|
|
538
|
+
# if prev_entry['set_current_amps_end_range'] < current_entry['set_current_amps_start_range']:
|
|
539
|
+
# print(f"Warning: Gap detected between element {prev_index} end range ({prev_entry['set_current_amps_end_range']}) "
|
|
540
|
+
# f"and element {current_index} start range ({current_entry['set_current_amps_start_range']}) "
|
|
541
|
+
# f"for device_type: {device_type}, max current: {max_current}")
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def get_optimum_compensation(spikesafe_model_max_current_amps, set_current_amps, pulse_on_time_seconds = None, enable_logging = False):
|
|
545
|
+
"""
|
|
546
|
+
Obsolete: Use Compensation.get_optimum_compensation() instead.
|
|
547
|
+
"""
|
|
548
|
+
return Compensation.get_optimum_compensation(spikesafe_model_max_current_amps, set_current_amps, pulse_on_time_seconds, enable_logging)
|
|
549
|
+
|
|
550
|
+
def get_custom_compensation(spikesafe_model_max_current_amps, set_current_amps, device_type, custom_compensation_table, pulse_on_time_seconds=None, enable_logging=False):
|
|
551
|
+
"""
|
|
552
|
+
Obsolete: Use Compensation.get_custom_compensation() instead.
|
|
553
|
+
"""
|
|
554
|
+
return Compensation.get_custom_compensation(spikesafe_model_max_current_amps, set_current_amps, device_type, custom_compensation_table, pulse_on_time_seconds, enable_logging)
|
|
555
|
+
|
|
556
|
+
def load_custom_compensation_table(file_path):
|
|
557
|
+
"""
|
|
558
|
+
Obsolete: Use Compensation.load_custom_compensation_table() instead.
|
|
559
|
+
"""
|
|
560
|
+
return Compensation.load_custom_compensation_table(file_path)
|
|
561
|
+
|
|
562
|
+
def load_custom_compensation_unique_device_types(custom_compensation_table):
|
|
563
|
+
"""
|
|
564
|
+
Obsolete: Use Compensation.load_custom_compensation_unique_device_types() instead.
|
|
565
|
+
"""
|
|
566
|
+
return Compensation.load_custom_compensation_unique_device_types(custom_compensation_table)
|