pyvale 2025.5.3__cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.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.

Potentially problematic release.


This version of pyvale might be problematic. Click here for more details.

Files changed (175) hide show
  1. pyvale/__init__.py +89 -0
  2. pyvale/analyticmeshgen.py +102 -0
  3. pyvale/analyticsimdatafactory.py +91 -0
  4. pyvale/analyticsimdatagenerator.py +323 -0
  5. pyvale/blendercalibrationdata.py +15 -0
  6. pyvale/blenderlightdata.py +26 -0
  7. pyvale/blendermaterialdata.py +15 -0
  8. pyvale/blenderrenderdata.py +30 -0
  9. pyvale/blenderscene.py +488 -0
  10. pyvale/blendertools.py +420 -0
  11. pyvale/camera.py +146 -0
  12. pyvale/cameradata.py +69 -0
  13. pyvale/cameradata2d.py +84 -0
  14. pyvale/camerastereo.py +217 -0
  15. pyvale/cameratools.py +522 -0
  16. pyvale/cython/rastercyth.c +32211 -0
  17. pyvale/cython/rastercyth.cpython-311-x86_64-linux-gnu.so +0 -0
  18. pyvale/cython/rastercyth.py +640 -0
  19. pyvale/data/__init__.py +5 -0
  20. pyvale/data/cal_target.tiff +0 -0
  21. pyvale/data/case00_HEX20_out.e +0 -0
  22. pyvale/data/case00_HEX27_out.e +0 -0
  23. pyvale/data/case00_HEX8_out.e +0 -0
  24. pyvale/data/case00_TET10_out.e +0 -0
  25. pyvale/data/case00_TET14_out.e +0 -0
  26. pyvale/data/case00_TET4_out.e +0 -0
  27. pyvale/data/case13_out.e +0 -0
  28. pyvale/data/case16_out.e +0 -0
  29. pyvale/data/case17_out.e +0 -0
  30. pyvale/data/case18_1_out.e +0 -0
  31. pyvale/data/case18_2_out.e +0 -0
  32. pyvale/data/case18_3_out.e +0 -0
  33. pyvale/data/case25_out.e +0 -0
  34. pyvale/data/case26_out.e +0 -0
  35. pyvale/data/optspeckle_2464x2056px_spec5px_8bit_gblur1px.tiff +0 -0
  36. pyvale/dataset.py +325 -0
  37. pyvale/errorcalculator.py +109 -0
  38. pyvale/errordriftcalc.py +146 -0
  39. pyvale/errorintegrator.py +336 -0
  40. pyvale/errorrand.py +607 -0
  41. pyvale/errorsyscalib.py +134 -0
  42. pyvale/errorsysdep.py +327 -0
  43. pyvale/errorsysfield.py +414 -0
  44. pyvale/errorsysindep.py +808 -0
  45. pyvale/examples/__init__.py +5 -0
  46. pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +131 -0
  47. pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +158 -0
  48. pyvale/examples/basics/ex1_3_customsens_therm3d.py +216 -0
  49. pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +153 -0
  50. pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +168 -0
  51. pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +133 -0
  52. pyvale/examples/basics/ex1_7_spatavg_therm2d.py +123 -0
  53. pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +112 -0
  54. pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +111 -0
  55. pyvale/examples/basics/ex2_3_sensangle_disp2d.py +139 -0
  56. pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +196 -0
  57. pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +109 -0
  58. pyvale/examples/basics/ex3_1_basictensors_strain2d.py +114 -0
  59. pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +111 -0
  60. pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +182 -0
  61. pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +171 -0
  62. pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +252 -0
  63. pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +35 -0
  64. pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +43 -0
  65. pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +80 -0
  66. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +79 -0
  67. pyvale/examples/renderblender/ex1_1_blenderscene.py +121 -0
  68. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +119 -0
  69. pyvale/examples/renderblender/ex2_1_stereoscene.py +128 -0
  70. pyvale/examples/renderblender/ex2_2_stereodeformed.py +131 -0
  71. pyvale/examples/renderblender/ex3_1_blendercalibration.py +120 -0
  72. pyvale/examples/renderrasterisation/ex_rastenp.py +153 -0
  73. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +218 -0
  74. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +187 -0
  75. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +190 -0
  76. pyvale/examples/visualisation/ex1_1_plot_traces.py +102 -0
  77. pyvale/examples/visualisation/ex2_1_animate_sim.py +89 -0
  78. pyvale/experimentsimulator.py +175 -0
  79. pyvale/field.py +128 -0
  80. pyvale/fieldconverter.py +351 -0
  81. pyvale/fieldsampler.py +111 -0
  82. pyvale/fieldscalar.py +166 -0
  83. pyvale/fieldtensor.py +218 -0
  84. pyvale/fieldtransform.py +388 -0
  85. pyvale/fieldvector.py +213 -0
  86. pyvale/generatorsrandom.py +505 -0
  87. pyvale/imagedef2d.py +569 -0
  88. pyvale/integratorfactory.py +240 -0
  89. pyvale/integratorquadrature.py +217 -0
  90. pyvale/integratorrectangle.py +165 -0
  91. pyvale/integratorspatial.py +89 -0
  92. pyvale/integratortype.py +43 -0
  93. pyvale/output.py +17 -0
  94. pyvale/pyvaleexceptions.py +11 -0
  95. pyvale/raster.py +31 -0
  96. pyvale/rastercy.py +77 -0
  97. pyvale/rasternp.py +603 -0
  98. pyvale/rendermesh.py +147 -0
  99. pyvale/sensorarray.py +178 -0
  100. pyvale/sensorarrayfactory.py +196 -0
  101. pyvale/sensorarraypoint.py +278 -0
  102. pyvale/sensordata.py +71 -0
  103. pyvale/sensordescriptor.py +213 -0
  104. pyvale/sensortools.py +142 -0
  105. pyvale/simcases/case00_HEX20.i +242 -0
  106. pyvale/simcases/case00_HEX27.i +242 -0
  107. pyvale/simcases/case00_HEX8.i +242 -0
  108. pyvale/simcases/case00_TET10.i +242 -0
  109. pyvale/simcases/case00_TET14.i +242 -0
  110. pyvale/simcases/case00_TET4.i +242 -0
  111. pyvale/simcases/case01.i +101 -0
  112. pyvale/simcases/case02.i +156 -0
  113. pyvale/simcases/case03.i +136 -0
  114. pyvale/simcases/case04.i +181 -0
  115. pyvale/simcases/case05.i +234 -0
  116. pyvale/simcases/case06.i +305 -0
  117. pyvale/simcases/case07.geo +135 -0
  118. pyvale/simcases/case07.i +87 -0
  119. pyvale/simcases/case08.geo +144 -0
  120. pyvale/simcases/case08.i +153 -0
  121. pyvale/simcases/case09.geo +204 -0
  122. pyvale/simcases/case09.i +87 -0
  123. pyvale/simcases/case10.geo +204 -0
  124. pyvale/simcases/case10.i +257 -0
  125. pyvale/simcases/case11.geo +337 -0
  126. pyvale/simcases/case11.i +147 -0
  127. pyvale/simcases/case12.geo +388 -0
  128. pyvale/simcases/case12.i +329 -0
  129. pyvale/simcases/case13.i +140 -0
  130. pyvale/simcases/case14.i +159 -0
  131. pyvale/simcases/case15.geo +337 -0
  132. pyvale/simcases/case15.i +150 -0
  133. pyvale/simcases/case16.geo +391 -0
  134. pyvale/simcases/case16.i +357 -0
  135. pyvale/simcases/case17.geo +135 -0
  136. pyvale/simcases/case17.i +144 -0
  137. pyvale/simcases/case18.i +254 -0
  138. pyvale/simcases/case18_1.i +254 -0
  139. pyvale/simcases/case18_2.i +254 -0
  140. pyvale/simcases/case18_3.i +254 -0
  141. pyvale/simcases/case19.geo +252 -0
  142. pyvale/simcases/case19.i +99 -0
  143. pyvale/simcases/case20.geo +252 -0
  144. pyvale/simcases/case20.i +250 -0
  145. pyvale/simcases/case21.geo +74 -0
  146. pyvale/simcases/case21.i +155 -0
  147. pyvale/simcases/case22.geo +82 -0
  148. pyvale/simcases/case22.i +140 -0
  149. pyvale/simcases/case23.geo +164 -0
  150. pyvale/simcases/case23.i +140 -0
  151. pyvale/simcases/case24.geo +79 -0
  152. pyvale/simcases/case24.i +123 -0
  153. pyvale/simcases/case25.geo +82 -0
  154. pyvale/simcases/case25.i +140 -0
  155. pyvale/simcases/case26.geo +166 -0
  156. pyvale/simcases/case26.i +140 -0
  157. pyvale/simcases/run_1case.py +61 -0
  158. pyvale/simcases/run_all_cases.py +69 -0
  159. pyvale/simcases/run_build_case.py +64 -0
  160. pyvale/simcases/run_example_cases.py +69 -0
  161. pyvale/simtools.py +67 -0
  162. pyvale/visualexpplotter.py +191 -0
  163. pyvale/visualimagedef.py +74 -0
  164. pyvale/visualimages.py +76 -0
  165. pyvale/visualopts.py +493 -0
  166. pyvale/visualsimanimator.py +111 -0
  167. pyvale/visualsimsensors.py +318 -0
  168. pyvale/visualtools.py +136 -0
  169. pyvale/visualtraceplotter.py +142 -0
  170. pyvale-2025.5.3.dist-info/METADATA +144 -0
  171. pyvale-2025.5.3.dist-info/RECORD +175 -0
  172. pyvale-2025.5.3.dist-info/WHEEL +6 -0
  173. pyvale-2025.5.3.dist-info/licenses/LICENSE +21 -0
  174. pyvale-2025.5.3.dist-info/top_level.txt +1 -0
  175. pyvale.libs/libgomp-a34b3233.so.1.0.0 +0 -0
@@ -0,0 +1,134 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ from typing import Callable
8
+ import numpy as np
9
+ from pyvale.errorcalculator import (IErrCalculator,
10
+ EErrType,
11
+ EErrDep)
12
+ from pyvale.sensordata import SensorData
13
+
14
+ # TODO: add option to use Newton's method for function inversion instead of a
15
+ # cal table.
16
+
17
+ class ErrSysCalibration(IErrCalculator):
18
+ """Systematic error calculator for calibration errors. The user specifies an
19
+ assumed calibration and a ground truth calibration function. The ground
20
+ truth calibration function is inverted and linearly interpolated numerically
21
+ based on the number of divisions specified by the user.
22
+
23
+ Implements the `IErrCalculator` interface.
24
+ """
25
+ __slots__ = ("_assumed_cali","_truth_calib","_cal_range","_n_cal_divs",
26
+ "_err_dep","_truth_calc_table")
27
+
28
+ def __init__(self,
29
+ assumed_calib: Callable[[np.ndarray],np.ndarray],
30
+ truth_calib: Callable[[np.ndarray],np.ndarray],
31
+ cal_range: tuple[float,float],
32
+ n_cal_divs: int = 10000,
33
+ err_dep: EErrDep = EErrDep.INDEPENDENT) -> None:
34
+ """
35
+ Parameters
36
+ ----------
37
+ assumed_calib : Callable[[np.ndarray],np.ndarray]
38
+ Assumed calibration function taking the input unitless 'signal' and
39
+ converting it to the same units as the physical field being sampled
40
+ by the sensor array.
41
+ truth_calib : Callable[[np.ndarray],np.ndarray]
42
+ Assumed calibration function taking the input unitless 'signal' and
43
+ converting it to the same units as the physical field being sampled
44
+ by the sensor array.
45
+ cal_range : tuple[float,float]
46
+ Range over which the calibration functions are valid. This is
47
+ normally based on a voltage range such as (0,10) volts.
48
+ n_cal_divs : int, optional
49
+ Number of divisions to discretise the the truth calibration function
50
+ for numerical inversion, by default 10000.
51
+ err_dep : EErrDependence, optional
52
+ Error calculation dependence, by default EErrDependence.INDEPENDENT.
53
+ """
54
+ self._assumed_calib = assumed_calib
55
+ self._truth_calib = truth_calib
56
+ self._cal_range = cal_range
57
+ self._n_cal_divs = n_cal_divs
58
+ self._err_dep = err_dep
59
+
60
+ self._truth_cal_table = np.zeros((n_cal_divs,2))
61
+ self._truth_cal_table[:,0] = np.linspace(cal_range[0],
62
+ cal_range[1],
63
+ n_cal_divs)
64
+ self._truth_cal_table[:,1] = self._truth_calib(
65
+ self._truth_cal_table[:,0])
66
+
67
+ def get_error_dep(self) -> EErrDep:
68
+ """Gets the error dependence state for this error calculator. An
69
+ independent error is calculated based on the input truth values as the
70
+ error basis. A dependent error is calculated based on the accumulated
71
+ sensor reading from all preceeding errors in the chain.
72
+
73
+ Returns
74
+ -------
75
+ EErrDependence
76
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
77
+ """
78
+ return self._err_dep
79
+
80
+ def set_error_dep(self, dependence: EErrDep) -> None:
81
+ """Sets the error dependence state for this error calculator. An
82
+ independent error is calculated based on the input truth values as the
83
+ error basis. A dependent error is calculated based on the accumulated
84
+ sensor reading from all preceeding errors in the chain.
85
+
86
+ Parameters
87
+ ----------
88
+ dependence : EErrDependence
89
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
90
+ """
91
+ self._err_dep = dependence
92
+
93
+ def get_error_type(self) -> EErrType:
94
+ """Gets the error type.
95
+
96
+ Returns
97
+ -------
98
+ EErrType
99
+ Enumeration definining RANDOM or SYSTEMATIC error types.
100
+ """
101
+ return EErrType.SYSTEMATIC
102
+
103
+ def calc_errs(self,
104
+ err_basis: np.ndarray,
105
+ sens_data: SensorData,
106
+ ) -> tuple[np.ndarray, SensorData]:
107
+ """Calculates the error array based on the size of the input.
108
+
109
+ Parameters
110
+ ----------
111
+ err_basis : np.ndarray
112
+ Array of values with the same dimensions as the sensor measurement
113
+ matrix.
114
+ sens_data : SensorData
115
+ The accumulated sensor state data for all errors prior to this one.
116
+
117
+ Returns
118
+ -------
119
+ tuple[np.ndarray, SensorData]
120
+ Tuple containing the calculated error array and pass through of the
121
+ sensor data object as it is not modified by this class. The returned
122
+ error array has the same shape as the input error basis.
123
+ """
124
+ # shape=(n_sens,n_comps,n_time_steps)
125
+ signal_from_field = np.interp(err_basis,
126
+ self._truth_cal_table[:,1],
127
+ self._truth_cal_table[:,0])
128
+ # shape=(n_sens,n_comps,n_time_steps)
129
+ field_from_assumed_calib = self._assumed_calib(signal_from_field)
130
+
131
+ sys_errs = field_from_assumed_calib - err_basis
132
+
133
+ return (sys_errs,sens_data)
134
+
pyvale/errorsysdep.py ADDED
@@ -0,0 +1,327 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ import enum
8
+ from typing import Callable
9
+ import numpy as np
10
+ from pyvale.sensordata import SensorData
11
+ from pyvale.errorcalculator import (IErrCalculator,
12
+ EErrType,
13
+ EErrDep)
14
+
15
+
16
+ class ERoundMethod(enum.Enum):
17
+ """Enumeration used to specify the method for rounding floats to integers.
18
+ """
19
+ ROUND = enum.auto()
20
+ FLOOR = enum.auto()
21
+ CEIL = enum.auto()
22
+
23
+
24
+ def _select_round_method(method: ERoundMethod) -> Callable:
25
+ """Helper function for selecting the rounding method based on the user
26
+ specified enumeration. Returns a numpy function for rounding.
27
+
28
+ Parameters
29
+ ----------
30
+ method : ERoundMethod
31
+ Enumeration specifying the rounding method.
32
+
33
+ Returns
34
+ -------
35
+ Callable
36
+ numpy rounding method as np.floor, np.ceil or np.round.
37
+ """
38
+ if method == ERoundMethod.FLOOR:
39
+ return np.floor
40
+ if method == ERoundMethod.CEIL:
41
+ return np.ceil
42
+ return np.round
43
+
44
+
45
+ class ErrSysRoundOff(IErrCalculator):
46
+ """Systematic error calculator for round off error. The user can specify the
47
+ floor, ceiling or nearest integer method for rounding. The user can also
48
+ specify a base to round to that defaults 1. Implements the `IErrCalculator`
49
+ interface.
50
+ """
51
+ __slots__ = ("_base","_method","_err_dep")
52
+
53
+ def __init__(self,
54
+ method: ERoundMethod = ERoundMethod.ROUND,
55
+ base: float = 1.0,
56
+ err_dep: EErrDep = EErrDep.DEPENDENT) -> None:
57
+ """
58
+ Parameters
59
+ ----------
60
+ method : ERoundMethod, optional
61
+ Enumeration specifying the rounding method, by default
62
+ ERoundMethod.ROUND.
63
+ base : float, optional
64
+ Base to round to, by default 1.0.
65
+ err_dep : EErrDependence, optional
66
+ Error calculation dependence, by default EErrDependence.DEPENDENT.
67
+ """
68
+ self._base = base
69
+ self._method = _select_round_method(method)
70
+ self._err_dep = err_dep
71
+
72
+ def get_error_dep(self) -> EErrDep:
73
+ """Gets the error dependence state for this error calculator. An
74
+ independent error is calculated based on the input truth values as the
75
+ error basis. A dependent error is calculated based on the accumulated
76
+ sensor reading from all preceeding errors in the chain.
77
+
78
+ Returns
79
+ -------
80
+ EErrDependence
81
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
82
+ """
83
+ return self._err_dep
84
+
85
+ def set_error_dep(self, dependence: EErrDep) -> None:
86
+ """Sets the error dependence state for this error calculator. An
87
+ independent error is calculated based on the input truth values as the
88
+ error basis. A dependent error is calculated based on the accumulated
89
+ sensor reading from all preceeding errors in the chain.
90
+
91
+ Parameters
92
+ ----------
93
+ dependence : EErrDependence
94
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
95
+ """
96
+ self._err_dep = dependence
97
+
98
+ def get_error_type(self) -> EErrType:
99
+ """Gets the error type.
100
+
101
+ Returns
102
+ -------
103
+ EErrType
104
+ Enumeration definining RANDOM or SYSTEMATIC error types.
105
+ """
106
+ return EErrType.SYSTEMATIC
107
+
108
+ def calc_errs(self,
109
+ err_basis: np.ndarray,
110
+ sens_data: SensorData,
111
+ ) -> tuple[np.ndarray, SensorData]:
112
+ """Calculates the error array based on the size of the input.
113
+
114
+ Parameters
115
+ ----------
116
+ err_basis : np.ndarray
117
+ Array of values with the same dimensions as the sensor measurement
118
+ matrix.
119
+ sens_data : SensorData
120
+ The accumulated sensor state data for all errors prior to this one.
121
+
122
+ Returns
123
+ -------
124
+ tuple[np.ndarray, SensorData]
125
+ Tuple containing the calculated error array and pass through of the
126
+ sensor data object as it is not modified by this class. The returned
127
+ error array has the same shape as the input error basis.
128
+ """
129
+ rounded_measurements = self._base*self._method(err_basis/self._base)
130
+
131
+ return (rounded_measurements - err_basis,sens_data)
132
+
133
+
134
+ class ErrSysDigitisation(IErrCalculator):
135
+ """Systematic error calculator for digitisation error base on a user
136
+ specified number of bits per physical unit and rounding method. Implements
137
+ the `IErrCalculator` interface.
138
+ """
139
+ __slots__ = ("_units_per_bit","_method","_err_dep")
140
+
141
+ def __init__(self,
142
+ bits_per_unit: float,
143
+ method: ERoundMethod = ERoundMethod.ROUND,
144
+ err_dep: EErrDep = EErrDep.DEPENDENT) -> None:
145
+ """
146
+ Parameters
147
+ ----------
148
+ bits_per_unit : float
149
+ The number of bits per physical unit used to determine the
150
+ digitisation error.
151
+ method : ERoundMethod, optional
152
+ User specified rounding method, by default ERoundMethod.ROUND.
153
+ err_dep : EErrDependence, optional
154
+ Error calculation dependence, by default EErrDependence.DEPENDENT.
155
+ """
156
+ self._units_per_bit = 1/float(bits_per_unit)
157
+ self._method = _select_round_method(method)
158
+ self._err_dep = err_dep
159
+
160
+ def get_error_dep(self) -> EErrDep:
161
+ """Gets the error dependence state for this error calculator. An
162
+ independent error is calculated based on the input truth values as the
163
+ error basis. A dependent error is calculated based on the accumulated
164
+ sensor reading from all preceeding errors in the chain.
165
+
166
+ Returns
167
+ -------
168
+ EErrDependence
169
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
170
+ """
171
+ return self._err_dep
172
+
173
+ def set_error_dep(self, dependence: EErrDep) -> None:
174
+ """Sets the error dependence state for this error calculator. An
175
+ independent error is calculated based on the input truth values as the
176
+ error basis. A dependent error is calculated based on the accumulated
177
+ sensor reading from all preceeding errors in the chain.
178
+
179
+ Parameters
180
+ ----------
181
+ dependence : EErrDependence
182
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
183
+ """
184
+ self._err_dep = dependence
185
+
186
+ def get_error_type(self) -> EErrType:
187
+ """Gets the error type.
188
+
189
+ Returns
190
+ -------
191
+ EErrType
192
+ Enumeration definining RANDOM or SYSTEMATIC error types.
193
+ """
194
+ return EErrType.SYSTEMATIC
195
+
196
+ def calc_errs(self,
197
+ err_basis: np.ndarray,
198
+ sens_data: SensorData,
199
+ ) -> tuple[np.ndarray, SensorData]:
200
+ """Calculates the error array based on the size of the input.
201
+
202
+ Parameters
203
+ ----------
204
+ err_basis : np.ndarray
205
+ Array of values with the same dimensions as the sensor measurement
206
+ matrix.
207
+ sens_data : SensorData
208
+ The accumulated sensor state data for all errors prior to this one.
209
+
210
+ Returns
211
+ -------
212
+ tuple[np.ndarray, SensorData]
213
+ Tuple containing the calculated error array and pass through of the
214
+ sensor data object as it is not modified by this class. The returned
215
+ error array has the same shape as the input error basis.
216
+ """
217
+ rounded_measurements = self._units_per_bit*self._method(
218
+ err_basis/self._units_per_bit)
219
+
220
+ return (rounded_measurements - err_basis,sens_data)
221
+
222
+
223
+ class ErrSysSaturation(IErrCalculator):
224
+ """Systematic error calculator for saturation error base on user specified
225
+ minimum and maximum measurement values. Implements the `IErrCalculator`
226
+ interface.
227
+
228
+ NOTE: For this error to function as expected and clamp the measurement
229
+ within the specified range it must be placed last in the error chain and
230
+ the behaviour must be set to: EErrDependence.DEPENDENT.
231
+ """
232
+ __slots__ = ("_min","_max","_err_dep")
233
+
234
+ def __init__(self,
235
+ meas_min: float,
236
+ meas_max: float) -> None:
237
+ """
238
+ Parameters
239
+ ----------
240
+ meas_min : float
241
+ Minimum value to saturate the measurement to.
242
+ meas_max : float
243
+ Maximum value to saturate the measurement to.
244
+
245
+ Raises
246
+ ------
247
+ ValueError
248
+ Raised if the user specified minimum measurement is greater than the
249
+ maximum measurement.
250
+ """
251
+ if meas_min > meas_max:
252
+ raise ValueError("Minimum must be smaller than maximum for "+
253
+ "systematic error saturation")
254
+
255
+ self._min = meas_min
256
+ self._max = meas_max
257
+ self._err_dep = EErrDep.DEPENDENT
258
+
259
+ def get_error_dep(self) -> EErrDep:
260
+ """Gets the error dependence state for this error calculator. An
261
+ independent error is calculated based on the input truth values as the
262
+ error basis. A dependent error is calculated based on the accumulated
263
+ sensor reading from all preceeding errors in the chain.
264
+
265
+ Returns
266
+ -------
267
+ EErrDependence
268
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
269
+ """
270
+ return self._err_dep
271
+
272
+ def set_error_dep(self, dependence: EErrDep) -> None:
273
+ """Sets the error dependence state for this error calculator. An
274
+ independent error is calculated based on the input truth values as the
275
+ error basis. A dependent error is calculated based on the accumulated
276
+ sensor reading from all preceeding errors in the chain.
277
+
278
+ NOTE: For this error to function as expected the error dependence must
279
+ be set to `EErrDependence.DEPENDENT`.
280
+
281
+ Parameters
282
+ ----------
283
+ dependence : EErrDependence
284
+ Enumeration defining INDEPENDENT or DEPENDENT behaviour.
285
+ """
286
+ self._err_dep = dependence
287
+
288
+ def get_error_type(self) -> EErrType:
289
+ """Gets the error type.
290
+
291
+ Returns
292
+ -------
293
+ EErrType
294
+ Enumeration definining RANDOM or SYSTEMATIC error types.
295
+ """
296
+ return EErrType.SYSTEMATIC
297
+
298
+ def calc_errs(self,
299
+ err_basis: np.ndarray,
300
+ sens_data: SensorData,
301
+ ) -> tuple[np.ndarray, SensorData]:
302
+ """Calculates the error array based on the size of the input.
303
+
304
+ Parameters
305
+ ----------
306
+ err_basis : np.ndarray
307
+ Array of values with the same dimensions as the sensor measurement
308
+ matrix.
309
+ sens_data : SensorData
310
+ The accumulated sensor state data for all errors prior to this one.
311
+
312
+ Returns
313
+ -------
314
+ tuple[np.ndarray, SensorData]
315
+ Tuple containing the calculated error array and pass through of the
316
+ sensor data object as it is not modified by this class. The returned
317
+ error array has the same shape as the input error basis.
318
+ """
319
+ saturated = np.copy(err_basis)
320
+ saturated[saturated > self._max] = self._max
321
+ saturated[saturated < self._min] = self._min
322
+
323
+ return (saturated - err_basis,sens_data)
324
+
325
+
326
+
327
+