sigima 0.0.1.dev0__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. sigima/__init__.py +142 -2
  2. sigima/client/__init__.py +105 -0
  3. sigima/client/base.py +780 -0
  4. sigima/client/remote.py +469 -0
  5. sigima/client/stub.py +814 -0
  6. sigima/client/utils.py +90 -0
  7. sigima/config.py +444 -0
  8. sigima/data/logo/Sigima.svg +135 -0
  9. sigima/data/tests/annotations.json +798 -0
  10. sigima/data/tests/curve_fitting/exponential_fit.txt +511 -0
  11. sigima/data/tests/curve_fitting/gaussian_fit.txt +100 -0
  12. sigima/data/tests/curve_fitting/piecewiseexponential_fit.txt +1022 -0
  13. sigima/data/tests/curve_fitting/polynomial_fit.txt +100 -0
  14. sigima/data/tests/curve_fitting/twohalfgaussian_fit.txt +1000 -0
  15. sigima/data/tests/curve_formats/bandwidth.txt +201 -0
  16. sigima/data/tests/curve_formats/boxcar.npy +0 -0
  17. sigima/data/tests/curve_formats/datetime.txt +1001 -0
  18. sigima/data/tests/curve_formats/dynamic_parameters.txt +4000 -0
  19. sigima/data/tests/curve_formats/fw1e2.txt +301 -0
  20. sigima/data/tests/curve_formats/fwhm.txt +319 -0
  21. sigima/data/tests/curve_formats/multiple_curves.csv +29 -0
  22. sigima/data/tests/curve_formats/noised_saw.mat +0 -0
  23. sigima/data/tests/curve_formats/oscilloscope.csv +111 -0
  24. sigima/data/tests/curve_formats/other/other2/recursive2.txt +5 -0
  25. sigima/data/tests/curve_formats/other/recursive1.txt +5 -0
  26. sigima/data/tests/curve_formats/paracetamol.npy +0 -0
  27. sigima/data/tests/curve_formats/paracetamol.txt +1010 -0
  28. sigima/data/tests/curve_formats/paracetamol_dx_dy.csv +1000 -0
  29. sigima/data/tests/curve_formats/paracetamol_dy.csv +1001 -0
  30. sigima/data/tests/curve_formats/pulse1.npy +0 -0
  31. sigima/data/tests/curve_formats/pulse2.npy +0 -0
  32. sigima/data/tests/curve_formats/simple.txt +5 -0
  33. sigima/data/tests/curve_formats/spectrum.mca +2139 -0
  34. sigima/data/tests/curve_formats/square2.npy +0 -0
  35. sigima/data/tests/curve_formats/step.npy +0 -0
  36. sigima/data/tests/fabry-perot1.jpg +0 -0
  37. sigima/data/tests/fabry-perot2.jpg +0 -0
  38. sigima/data/tests/flower.npy +0 -0
  39. sigima/data/tests/image_formats/NF 180338201.scor-data +11003 -0
  40. sigima/data/tests/image_formats/binary_image.npy +0 -0
  41. sigima/data/tests/image_formats/binary_image.png +0 -0
  42. sigima/data/tests/image_formats/centroid_test.npy +0 -0
  43. sigima/data/tests/image_formats/coordinated_text/complex_image.txt +10011 -0
  44. sigima/data/tests/image_formats/coordinated_text/complex_ref_image.txt +10010 -0
  45. sigima/data/tests/image_formats/coordinated_text/image.txt +15 -0
  46. sigima/data/tests/image_formats/coordinated_text/image2.txt +14 -0
  47. sigima/data/tests/image_formats/coordinated_text/image_no_unit_no_label.txt +14 -0
  48. sigima/data/tests/image_formats/coordinated_text/image_with_nan.txt +15 -0
  49. sigima/data/tests/image_formats/coordinated_text/image_with_unit.txt +14 -0
  50. sigima/data/tests/image_formats/fiber.csv +480 -0
  51. sigima/data/tests/image_formats/fiber.jpg +0 -0
  52. sigima/data/tests/image_formats/fiber.png +0 -0
  53. sigima/data/tests/image_formats/fiber.txt +480 -0
  54. sigima/data/tests/image_formats/gaussian_spot_with_noise.npy +0 -0
  55. sigima/data/tests/image_formats/mr-brain.dcm +0 -0
  56. sigima/data/tests/image_formats/noised_gaussian.mat +0 -0
  57. sigima/data/tests/image_formats/sif_reader/nd_lum_image_no_glue.sif +0 -0
  58. sigima/data/tests/image_formats/sif_reader/raman1.sif +0 -0
  59. sigima/data/tests/image_formats/tiling.txt +10 -0
  60. sigima/data/tests/image_formats/uint16.tiff +0 -0
  61. sigima/data/tests/image_formats/uint8.tiff +0 -0
  62. sigima/data/tests/laser_beam/TEM00_z_13.jpg +0 -0
  63. sigima/data/tests/laser_beam/TEM00_z_18.jpg +0 -0
  64. sigima/data/tests/laser_beam/TEM00_z_23.jpg +0 -0
  65. sigima/data/tests/laser_beam/TEM00_z_30.jpg +0 -0
  66. sigima/data/tests/laser_beam/TEM00_z_35.jpg +0 -0
  67. sigima/data/tests/laser_beam/TEM00_z_40.jpg +0 -0
  68. sigima/data/tests/laser_beam/TEM00_z_45.jpg +0 -0
  69. sigima/data/tests/laser_beam/TEM00_z_50.jpg +0 -0
  70. sigima/data/tests/laser_beam/TEM00_z_55.jpg +0 -0
  71. sigima/data/tests/laser_beam/TEM00_z_60.jpg +0 -0
  72. sigima/data/tests/laser_beam/TEM00_z_65.jpg +0 -0
  73. sigima/data/tests/laser_beam/TEM00_z_70.jpg +0 -0
  74. sigima/data/tests/laser_beam/TEM00_z_75.jpg +0 -0
  75. sigima/data/tests/laser_beam/TEM00_z_80.jpg +0 -0
  76. sigima/enums.py +195 -0
  77. sigima/io/__init__.py +123 -0
  78. sigima/io/base.py +311 -0
  79. sigima/io/common/__init__.py +5 -0
  80. sigima/io/common/basename.py +164 -0
  81. sigima/io/common/converters.py +189 -0
  82. sigima/io/common/objmeta.py +181 -0
  83. sigima/io/common/textreader.py +58 -0
  84. sigima/io/convenience.py +157 -0
  85. sigima/io/enums.py +17 -0
  86. sigima/io/ftlab.py +395 -0
  87. sigima/io/image/__init__.py +9 -0
  88. sigima/io/image/base.py +177 -0
  89. sigima/io/image/formats.py +1016 -0
  90. sigima/io/image/funcs.py +414 -0
  91. sigima/io/signal/__init__.py +9 -0
  92. sigima/io/signal/base.py +129 -0
  93. sigima/io/signal/formats.py +290 -0
  94. sigima/io/signal/funcs.py +723 -0
  95. sigima/objects/__init__.py +260 -0
  96. sigima/objects/base.py +937 -0
  97. sigima/objects/image/__init__.py +88 -0
  98. sigima/objects/image/creation.py +556 -0
  99. sigima/objects/image/object.py +524 -0
  100. sigima/objects/image/roi.py +904 -0
  101. sigima/objects/scalar/__init__.py +57 -0
  102. sigima/objects/scalar/common.py +215 -0
  103. sigima/objects/scalar/geometry.py +502 -0
  104. sigima/objects/scalar/table.py +784 -0
  105. sigima/objects/shape.py +290 -0
  106. sigima/objects/signal/__init__.py +133 -0
  107. sigima/objects/signal/constants.py +27 -0
  108. sigima/objects/signal/creation.py +1428 -0
  109. sigima/objects/signal/object.py +444 -0
  110. sigima/objects/signal/roi.py +274 -0
  111. sigima/params.py +405 -0
  112. sigima/proc/__init__.py +96 -0
  113. sigima/proc/base.py +381 -0
  114. sigima/proc/decorator.py +330 -0
  115. sigima/proc/image/__init__.py +513 -0
  116. sigima/proc/image/arithmetic.py +335 -0
  117. sigima/proc/image/base.py +260 -0
  118. sigima/proc/image/detection.py +519 -0
  119. sigima/proc/image/edges.py +329 -0
  120. sigima/proc/image/exposure.py +406 -0
  121. sigima/proc/image/extraction.py +458 -0
  122. sigima/proc/image/filtering.py +219 -0
  123. sigima/proc/image/fourier.py +147 -0
  124. sigima/proc/image/geometry.py +661 -0
  125. sigima/proc/image/mathops.py +340 -0
  126. sigima/proc/image/measurement.py +195 -0
  127. sigima/proc/image/morphology.py +155 -0
  128. sigima/proc/image/noise.py +107 -0
  129. sigima/proc/image/preprocessing.py +182 -0
  130. sigima/proc/image/restoration.py +235 -0
  131. sigima/proc/image/threshold.py +217 -0
  132. sigima/proc/image/transformations.py +393 -0
  133. sigima/proc/signal/__init__.py +376 -0
  134. sigima/proc/signal/analysis.py +206 -0
  135. sigima/proc/signal/arithmetic.py +551 -0
  136. sigima/proc/signal/base.py +262 -0
  137. sigima/proc/signal/extraction.py +60 -0
  138. sigima/proc/signal/features.py +310 -0
  139. sigima/proc/signal/filtering.py +484 -0
  140. sigima/proc/signal/fitting.py +276 -0
  141. sigima/proc/signal/fourier.py +259 -0
  142. sigima/proc/signal/mathops.py +420 -0
  143. sigima/proc/signal/processing.py +580 -0
  144. sigima/proc/signal/stability.py +175 -0
  145. sigima/proc/title_formatting.py +227 -0
  146. sigima/proc/validation.py +272 -0
  147. sigima/tests/__init__.py +7 -0
  148. sigima/tests/common/__init__.py +0 -0
  149. sigima/tests/common/arithmeticparam_unit_test.py +26 -0
  150. sigima/tests/common/basename_unit_test.py +126 -0
  151. sigima/tests/common/client_unit_test.py +412 -0
  152. sigima/tests/common/converters_unit_test.py +77 -0
  153. sigima/tests/common/decorator_unit_test.py +176 -0
  154. sigima/tests/common/examples_unit_test.py +104 -0
  155. sigima/tests/common/kernel_normalization_unit_test.py +242 -0
  156. sigima/tests/common/roi_basic_unit_test.py +73 -0
  157. sigima/tests/common/roi_geometry_unit_test.py +171 -0
  158. sigima/tests/common/scalar_builder_unit_test.py +142 -0
  159. sigima/tests/common/scalar_unit_test.py +991 -0
  160. sigima/tests/common/shape_unit_test.py +183 -0
  161. sigima/tests/common/stat_unit_test.py +138 -0
  162. sigima/tests/common/title_formatting_unit_test.py +338 -0
  163. sigima/tests/common/tools_coordinates_unit_test.py +60 -0
  164. sigima/tests/common/transformations_unit_test.py +178 -0
  165. sigima/tests/common/validation_unit_test.py +205 -0
  166. sigima/tests/conftest.py +129 -0
  167. sigima/tests/data.py +998 -0
  168. sigima/tests/env.py +280 -0
  169. sigima/tests/guiutils.py +163 -0
  170. sigima/tests/helpers.py +532 -0
  171. sigima/tests/image/__init__.py +28 -0
  172. sigima/tests/image/binning_unit_test.py +128 -0
  173. sigima/tests/image/blob_detection_unit_test.py +312 -0
  174. sigima/tests/image/centroid_unit_test.py +170 -0
  175. sigima/tests/image/check_2d_array_unit_test.py +63 -0
  176. sigima/tests/image/contour_unit_test.py +172 -0
  177. sigima/tests/image/convolution_unit_test.py +178 -0
  178. sigima/tests/image/datatype_unit_test.py +67 -0
  179. sigima/tests/image/edges_unit_test.py +155 -0
  180. sigima/tests/image/enclosingcircle_unit_test.py +88 -0
  181. sigima/tests/image/exposure_unit_test.py +223 -0
  182. sigima/tests/image/fft2d_unit_test.py +189 -0
  183. sigima/tests/image/filtering_unit_test.py +166 -0
  184. sigima/tests/image/geometry_unit_test.py +654 -0
  185. sigima/tests/image/hough_circle_unit_test.py +147 -0
  186. sigima/tests/image/imageobj_unit_test.py +737 -0
  187. sigima/tests/image/morphology_unit_test.py +71 -0
  188. sigima/tests/image/noise_unit_test.py +57 -0
  189. sigima/tests/image/offset_correction_unit_test.py +72 -0
  190. sigima/tests/image/operation_unit_test.py +518 -0
  191. sigima/tests/image/peak2d_limits_unit_test.py +41 -0
  192. sigima/tests/image/peak2d_unit_test.py +133 -0
  193. sigima/tests/image/profile_unit_test.py +159 -0
  194. sigima/tests/image/projections_unit_test.py +121 -0
  195. sigima/tests/image/restoration_unit_test.py +141 -0
  196. sigima/tests/image/roi2dparam_unit_test.py +53 -0
  197. sigima/tests/image/roi_advanced_unit_test.py +588 -0
  198. sigima/tests/image/roi_grid_unit_test.py +279 -0
  199. sigima/tests/image/spectrum2d_unit_test.py +40 -0
  200. sigima/tests/image/threshold_unit_test.py +91 -0
  201. sigima/tests/io/__init__.py +0 -0
  202. sigima/tests/io/addnewformat_unit_test.py +125 -0
  203. sigima/tests/io/convenience_funcs_unit_test.py +470 -0
  204. sigima/tests/io/coordinated_text_format_unit_test.py +495 -0
  205. sigima/tests/io/datetime_csv_unit_test.py +198 -0
  206. sigima/tests/io/imageio_formats_test.py +41 -0
  207. sigima/tests/io/ioregistry_unit_test.py +69 -0
  208. sigima/tests/io/objmeta_unit_test.py +87 -0
  209. sigima/tests/io/readobj_unit_test.py +130 -0
  210. sigima/tests/io/readwriteobj_unit_test.py +67 -0
  211. sigima/tests/signal/__init__.py +0 -0
  212. sigima/tests/signal/analysis_unit_test.py +135 -0
  213. sigima/tests/signal/check_1d_arrays_unit_test.py +169 -0
  214. sigima/tests/signal/convolution_unit_test.py +404 -0
  215. sigima/tests/signal/datetime_unit_test.py +176 -0
  216. sigima/tests/signal/fft1d_unit_test.py +303 -0
  217. sigima/tests/signal/filters_unit_test.py +403 -0
  218. sigima/tests/signal/fitting_unit_test.py +929 -0
  219. sigima/tests/signal/fwhm_unit_test.py +111 -0
  220. sigima/tests/signal/noise_unit_test.py +128 -0
  221. sigima/tests/signal/offset_correction_unit_test.py +34 -0
  222. sigima/tests/signal/operation_unit_test.py +489 -0
  223. sigima/tests/signal/peakdetection_unit_test.py +145 -0
  224. sigima/tests/signal/processing_unit_test.py +657 -0
  225. sigima/tests/signal/pulse/__init__.py +112 -0
  226. sigima/tests/signal/pulse/crossing_times_unit_test.py +123 -0
  227. sigima/tests/signal/pulse/plateau_detection_unit_test.py +102 -0
  228. sigima/tests/signal/pulse/pulse_unit_test.py +1824 -0
  229. sigima/tests/signal/roi_advanced_unit_test.py +392 -0
  230. sigima/tests/signal/signalobj_unit_test.py +603 -0
  231. sigima/tests/signal/stability_unit_test.py +431 -0
  232. sigima/tests/signal/uncertainty_unit_test.py +611 -0
  233. sigima/tests/vistools.py +1030 -0
  234. sigima/tools/__init__.py +59 -0
  235. sigima/tools/checks.py +290 -0
  236. sigima/tools/coordinates.py +308 -0
  237. sigima/tools/datatypes.py +26 -0
  238. sigima/tools/image/__init__.py +97 -0
  239. sigima/tools/image/detection.py +451 -0
  240. sigima/tools/image/exposure.py +77 -0
  241. sigima/tools/image/extraction.py +48 -0
  242. sigima/tools/image/fourier.py +260 -0
  243. sigima/tools/image/geometry.py +190 -0
  244. sigima/tools/image/preprocessing.py +165 -0
  245. sigima/tools/signal/__init__.py +86 -0
  246. sigima/tools/signal/dynamic.py +254 -0
  247. sigima/tools/signal/features.py +135 -0
  248. sigima/tools/signal/filtering.py +171 -0
  249. sigima/tools/signal/fitting.py +1171 -0
  250. sigima/tools/signal/fourier.py +466 -0
  251. sigima/tools/signal/interpolation.py +70 -0
  252. sigima/tools/signal/peakdetection.py +126 -0
  253. sigima/tools/signal/pulse.py +1626 -0
  254. sigima/tools/signal/scaling.py +50 -0
  255. sigima/tools/signal/stability.py +258 -0
  256. sigima/tools/signal/windowing.py +90 -0
  257. sigima/worker.py +79 -0
  258. sigima-1.0.0.dist-info/METADATA +233 -0
  259. sigima-1.0.0.dist-info/RECORD +262 -0
  260. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/licenses/LICENSE +29 -29
  261. sigima-0.0.1.dev0.dist-info/METADATA +0 -60
  262. sigima-0.0.1.dev0.dist-info/RECORD +0 -6
  263. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/WHEEL +0 -0
  264. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,431 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Signal stability analysis unit test.
5
+ """
6
+
7
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
8
+ # pylint: disable=duplicate-code
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Callable
13
+
14
+ import numpy as np
15
+ import pytest
16
+
17
+ import sigima.objects
18
+ import sigima.params
19
+ import sigima.proc.signal
20
+ from sigima.tests.helpers import check_array_result
21
+
22
+
23
+ def get_optimal_points(test_func: Callable) -> int:
24
+ """Return optimal number of points for different algorithms.
25
+
26
+ Args:
27
+ test_func: Test function object to determine algorithm type
28
+
29
+ Returns:
30
+ Optimal number of points balancing accuracy and performance
31
+ """
32
+ func_name = test_func.__name__
33
+ if "overlapping" in func_name or "hadamard" in func_name:
34
+ return 500 # Minimum for meaningful results
35
+ if "modified" in func_name or "total" in func_name:
36
+ return 1000 # Need more for averaging
37
+ # allan_variance, allan_deviation, time_deviation
38
+ return 2000 # Balance between speed and accuracy
39
+
40
+
41
+ def generate_white_noise(n_points: int, sigma=1.0) -> np.ndarray:
42
+ """Generate white noise with known characteristics.
43
+
44
+ Args:
45
+ n_points: Number of data points
46
+ sigma: Standard deviation of the white noise (default is 1.0)
47
+
48
+ Returns:
49
+ Array of white noise values
50
+ """
51
+ return np.random.normal(0, sigma, n_points)
52
+
53
+
54
+ def theoretical_allan_variance_white_noise(tau: float, sigma: float) -> float:
55
+ """Calculate theoretical Allan variance for white noise.
56
+
57
+ For white noise: AVAR(τ) = σ²/(2τ)
58
+ But the Allan variance is computed as AVAR(τ) = σ²τ/τ = σ²τ because of the
59
+ overlapping nature of the samples.
60
+
61
+ Args:
62
+ tau: Averaging time
63
+ sigma: Standard deviation of the white noise
64
+
65
+ Returns:
66
+ Allan variance value for the given tau and sigma
67
+ """
68
+ return sigma**2 / tau
69
+
70
+
71
+ def generate_drift_signal(
72
+ n_points: int, slope: float, intercept: float = 0
73
+ ) -> tuple[np.ndarray, np.ndarray]:
74
+ """Generate a linear drift signal.
75
+
76
+ Args:
77
+ n_points: Number of data points
78
+ slope: Slope of the linear drift
79
+ intercept: Intercept of the linear drift (default is 0)
80
+
81
+ Returns:
82
+ A tuple of (time array, values array)
83
+ """
84
+ time = np.arange(n_points)
85
+ values = slope * time + intercept
86
+ return time, values
87
+
88
+
89
+ def theoretical_allan_variance_drift(tau: float, slope: float) -> float:
90
+ """Theoretical Allan variance for a drift signal.
91
+
92
+ Args:
93
+ tau: Averaging time
94
+ slope: Slope of the linear drift
95
+
96
+ Returns:
97
+ Allan variance value for the given tau and slope
98
+ """
99
+ return (slope**2 * tau**2) / 2
100
+
101
+
102
+ @pytest.mark.validation
103
+ def test_signal_allan_variance():
104
+ """Test Allan variance computation against theoretical values."""
105
+ n_points = get_optimal_points(test_signal_allan_variance)
106
+ sigma = 1.0
107
+
108
+ # Set random seed for reproducibility
109
+ np.random.seed(42)
110
+
111
+ # Generate and test white noise signal
112
+ time_white = np.arange(n_points)
113
+ values_white = generate_white_noise(n_points, sigma)
114
+ sig1 = sigima.objects.create_signal("White Noise Test", time_white, values_white)
115
+
116
+ # Define Allan variance parameters - limit max_tau for more reliable statistics
117
+ param = sigima.params.AllanVarianceParam()
118
+ param.max_tau = 20 # Limited to ensure sufficient samples for averaging
119
+
120
+ # Compute Allan variance using the high-level function
121
+ res1 = sigima.proc.signal.allan_variance(sig1, param)
122
+ th_av_white = theoretical_allan_variance_white_noise(res1.x, sigma)
123
+
124
+ # Use relative tolerance for white noise (statistical variation scales)
125
+ # 20% tolerance accounts for statistical variance in Allan estimator
126
+ check_array_result(
127
+ "White noise Allan variance",
128
+ res1.y,
129
+ th_av_white,
130
+ rtol=0.20,
131
+ atol=0.005,
132
+ )
133
+
134
+ # Generate and test drift signal (deterministic - same seed not needed)
135
+ slope = 0.01
136
+ time, values = generate_drift_signal(n_points, slope)
137
+ sig2 = sigima.objects.create_signal("Drift Test", time, values)
138
+
139
+ # Compute Allan variance using the high-level function
140
+ res2 = sigima.proc.signal.allan_variance(sig2, param)
141
+ th_av_drift = theoretical_allan_variance_drift(res2.x, slope)
142
+
143
+ # Drift is deterministic, tighter tolerances apply
144
+ check_array_result(
145
+ "Drift Allan variance",
146
+ res2.y,
147
+ th_av_drift,
148
+ rtol=0.05,
149
+ atol=0.0001,
150
+ )
151
+
152
+
153
+ @pytest.mark.validation
154
+ def test_signal_allan_deviation():
155
+ """Test Allan deviation computation against theoretical values."""
156
+ n_points = get_optimal_points(test_signal_allan_deviation)
157
+ sigma = 1.0
158
+
159
+ # Set random seed for reproducibility
160
+ np.random.seed(43)
161
+
162
+ # Generate and test white noise signal
163
+ time_white = np.arange(n_points)
164
+ values_white = generate_white_noise(n_points, sigma)
165
+ sig1 = sigima.objects.create_signal("White Noise Test", time_white, values_white)
166
+
167
+ # Define Allan variance parameters - limit max_tau for more reliable statistics
168
+ param = sigima.params.AllanVarianceParam()
169
+ param.max_tau = 20 # Limited to ensure sufficient samples for averaging
170
+
171
+ # Compute Allan deviation using the high-level function
172
+ res1 = sigima.proc.signal.allan_deviation(sig1, param)
173
+ th_av_white = theoretical_allan_variance_white_noise(res1.x, sigma)
174
+
175
+ # Use relative tolerance for white noise (statistical variation scales)
176
+ # 20% tolerance accounts for statistical variance in Allan estimator
177
+ check_array_result(
178
+ "White noise Allan deviation",
179
+ res1.y,
180
+ np.sqrt(th_av_white),
181
+ rtol=0.20,
182
+ atol=0.005,
183
+ )
184
+
185
+ # Generate and test drift signal (deterministic - same seed not needed)
186
+ slope = 0.01
187
+ time, values = generate_drift_signal(n_points, slope)
188
+ sig2 = sigima.objects.create_signal("Drift Test", time, values)
189
+
190
+ # Compute Allan deviation using the high-level function
191
+ res2 = sigima.proc.signal.allan_deviation(sig2, param)
192
+ th_av_drift = theoretical_allan_variance_drift(res2.x, slope)
193
+
194
+ # Drift is deterministic, tighter tolerances apply
195
+ check_array_result(
196
+ "Drift Allan deviation",
197
+ res2.y,
198
+ np.sqrt(th_av_drift),
199
+ rtol=0.05,
200
+ atol=0.0001,
201
+ )
202
+
203
+
204
+ @pytest.mark.validation
205
+ def test_signal_overlapping_allan_variance():
206
+ """Test Overlapping Allan variance computation."""
207
+ n_points = get_optimal_points(test_signal_overlapping_allan_variance)
208
+ sigma = 1.0
209
+
210
+ # Generate and test white noise signal
211
+ time_white = np.arange(n_points)
212
+ values_white = generate_white_noise(n_points, sigma)
213
+ sig1 = sigima.objects.create_signal("White Noise Test", time_white, values_white)
214
+
215
+ # Define Allan variance parameters
216
+ param = sigima.params.AllanVarianceParam()
217
+ param.max_tau = 50
218
+
219
+ # Compute Overlapping Allan variance using the high-level function
220
+ res1 = sigima.proc.signal.overlapping_allan_variance(sig1, param)
221
+
222
+ # Overlapping Allan variance should produce finite, positive results
223
+ assert len(res1.y) > 0, "Overlapping Allan variance should produce results"
224
+ valid_values = res1.y[~np.isnan(res1.y)]
225
+ assert len(valid_values) > 0, "Overlapping Allan variance should have valid values"
226
+ assert np.all(valid_values > 0), "Overlapping Allan variance should be positive"
227
+
228
+ # For white noise, overlapping Allan variance should be related to the noise level
229
+ # and generally decrease with tau (though not necessarily following exact 1/tau)
230
+ expected_order = sigma**2
231
+ assert np.mean(valid_values) < 10 * expected_order, (
232
+ "Overlapping Allan variance should be reasonable for white noise"
233
+ )
234
+
235
+ # Generate and test drift signal
236
+ slope = 0.01
237
+ time, values = generate_drift_signal(n_points, slope)
238
+ sig2 = sigima.objects.create_signal("Drift Test", time, values)
239
+
240
+ # Compute Overlapping Allan variance using the high-level function
241
+ res2 = sigima.proc.signal.overlapping_allan_variance(sig2, param)
242
+
243
+ # For drift signals, overlapping Allan variance should also be finite and positive
244
+ valid_drift_values = res2.y[~np.isnan(res2.y)]
245
+ assert len(valid_drift_values) > 0, (
246
+ "Overlapping Allan variance should work for drift"
247
+ )
248
+ assert np.all(valid_drift_values > 0), (
249
+ "Overlapping Allan variance should be positive"
250
+ )
251
+
252
+ # Compare with regular Allan variance to ensure overlapping version
253
+ # produces reasonable results
254
+ res_regular = sigima.proc.signal.allan_variance(sig1, param)
255
+ valid_regular = res_regular.y[~np.isnan(res_regular.y)]
256
+ if len(valid_regular) > 0 and len(valid_values) > 0:
257
+ # Results should be of similar order of magnitude
258
+ ratio = np.mean(valid_values) / np.mean(valid_regular)
259
+ assert 0.1 < ratio < 10, (
260
+ "Overlapping and regular Allan variance should be of similar magnitude"
261
+ )
262
+
263
+
264
+ @pytest.mark.validation
265
+ def test_signal_modified_allan_variance():
266
+ """Test Modified Allan variance computation."""
267
+ n_points = get_optimal_points(test_signal_modified_allan_variance)
268
+ sigma = 1.0
269
+
270
+ # Generate and test white noise signal
271
+ time_white = np.arange(n_points)
272
+ values_white = generate_white_noise(n_points, sigma)
273
+ sig1 = sigima.objects.create_signal("White Noise Test", time_white, values_white)
274
+
275
+ # Define Allan variance parameters
276
+ param = sigima.params.AllanVarianceParam()
277
+ param.max_tau = 50
278
+
279
+ # Compute Modified Allan variance using the high-level function
280
+ res1 = sigima.proc.signal.modified_allan_variance(sig1, param)
281
+
282
+ # For white noise, Modified Allan variance should be proportional to 1/tau
283
+ # The exact relationship depends on the specific implementation
284
+ # We check that values are reasonable and decrease with tau
285
+ assert len(res1.y) > 0, "Modified Allan variance should produce results"
286
+ assert np.all(res1.y[~np.isnan(res1.y)] > 0), (
287
+ "Modified Allan variance should be positive"
288
+ )
289
+
290
+ # For white noise, Modified Allan variance typically decreases with tau
291
+ valid_indices = ~np.isnan(res1.y)
292
+ if np.sum(valid_indices) > 1:
293
+ valid_y = res1.y[valid_indices]
294
+ # Check general decreasing trend for first few points
295
+ if len(valid_y) >= 3:
296
+ assert valid_y[2] < valid_y[0], (
297
+ "Modified Allan variance should generally decrease for white noise"
298
+ )
299
+
300
+
301
+ @pytest.mark.validation
302
+ def test_signal_hadamard_variance():
303
+ """Test Hadamard variance computation."""
304
+ n_points = get_optimal_points(test_signal_hadamard_variance)
305
+ sigma = 1.0
306
+
307
+ # Generate and test white noise signal
308
+ time_white = np.arange(n_points)
309
+ values_white = generate_white_noise(n_points, sigma)
310
+ sig1 = sigima.objects.create_signal("White Noise Test", time_white, values_white)
311
+
312
+ # Define Allan variance parameters
313
+ param = sigima.params.AllanVarianceParam()
314
+ param.max_tau = 50
315
+
316
+ # Compute Hadamard variance using the high-level function
317
+ res1 = sigima.proc.signal.hadamard_variance(sig1, param)
318
+
319
+ # For white noise, Hadamard variance should be finite and positive
320
+ assert len(res1.y) > 0, "Hadamard variance should produce results"
321
+ valid_values = res1.y[~np.isnan(res1.y)]
322
+ assert len(valid_values) > 0, "Hadamard variance should have valid values"
323
+ assert np.all(valid_values > 0), "Hadamard variance should be positive"
324
+
325
+ # Generate and test linear drift signal
326
+ # (Hadamard variance is robust to linear drift)
327
+ slope = 0.01
328
+ time, values = generate_drift_signal(n_points, slope)
329
+ sig2 = sigima.objects.create_signal("Drift Test", time, values)
330
+
331
+ # Compute Hadamard variance for drift signal
332
+ res2 = sigima.proc.signal.hadamard_variance(sig2, param)
333
+
334
+ # Hadamard variance should be less sensitive to linear drift than Allan variance
335
+ # For pure linear drift, Hadamard variance should be close to zero or very small
336
+ valid_drift_values = res2.y[~np.isnan(res2.y)]
337
+ if len(valid_drift_values) > 0:
338
+ # Hadamard variance should be smaller for drift signals
339
+ assert np.mean(valid_drift_values) < np.mean(valid_values), (
340
+ "Hadamard variance should be smaller for drift signals than white noise"
341
+ )
342
+
343
+
344
+ @pytest.mark.validation
345
+ def test_signal_total_variance():
346
+ """Test Total variance computation."""
347
+ n_points = get_optimal_points(test_signal_total_variance)
348
+ sigma = 1.0
349
+
350
+ # Generate and test white noise signal
351
+ time_white = np.arange(n_points)
352
+ values_white = generate_white_noise(n_points, sigma)
353
+ sig1 = sigima.objects.create_signal("White Noise Test", time_white, values_white)
354
+
355
+ # Define Allan variance parameters
356
+ param = sigima.params.AllanVarianceParam()
357
+ param.max_tau = 50
358
+
359
+ # Compute Total variance using the high-level function
360
+ res1 = sigima.proc.signal.total_variance(sig1, param)
361
+
362
+ # Total variance should be finite and positive
363
+ assert len(res1.y) > 0, "Total variance should produce results"
364
+ valid_values = res1.y[~np.isnan(res1.y)]
365
+ assert len(valid_values) > 0, "Total variance should have valid values"
366
+ assert np.all(valid_values > 0), "Total variance should be positive"
367
+
368
+ # For white noise, total variance should be related to the noise level
369
+ # and should be of the same order of magnitude as the square of the noise
370
+ expected_order = sigma**2
371
+ assert np.mean(valid_values) < 100 * expected_order, (
372
+ "Total variance should be reasonable for white noise"
373
+ )
374
+
375
+
376
+ @pytest.mark.validation
377
+ def test_signal_time_deviation():
378
+ """Test Time Deviation computation."""
379
+ n_points = get_optimal_points(test_signal_time_deviation)
380
+ sigma = 1.0
381
+
382
+ # Generate and test white noise signal
383
+ time_white = np.arange(n_points)
384
+ values_white = generate_white_noise(n_points, sigma)
385
+ sig1 = sigima.objects.create_signal("White Noise Test", time_white, values_white)
386
+
387
+ # Define Allan variance parameters
388
+ param = sigima.params.AllanVarianceParam()
389
+ param.max_tau = 50
390
+
391
+ # Compute Time Deviation using the high-level function
392
+ res1 = sigima.proc.signal.time_deviation(sig1, param)
393
+
394
+ # Time deviation should be finite and positive
395
+ assert len(res1.y) > 0, "Time deviation should produce results"
396
+ valid_values = res1.y[~np.isnan(res1.y)]
397
+ assert len(valid_values) > 0, "Time deviation should have valid values"
398
+ assert np.all(valid_values > 0), "Time deviation should be positive"
399
+
400
+ # Time deviation is related to Allan variance: TDEV = sqrt(AVAR) * tau
401
+ # So it should increase with tau for white noise
402
+ if len(valid_values) >= 2:
403
+ valid_x = res1.x[~np.isnan(res1.y)]
404
+ # Check that time deviation generally increases with tau for white noise
405
+ correlation = np.corrcoef(valid_x[: len(valid_values)], valid_values)[0, 1]
406
+ assert correlation > 0.5, (
407
+ "Time deviation should generally increase with tau for white noise"
408
+ )
409
+
410
+ # Compare with Allan deviation to verify the relationship
411
+ res_adev = sigima.proc.signal.allan_deviation(sig1, param)
412
+
413
+ # TDEV = ADEV * tau (approximately)
414
+ # Check this relationship for some values
415
+ for i, tau in enumerate(res1.x[: min(5, len(res1.x))]):
416
+ if not np.isnan(res1.y[i]) and not np.isnan(res_adev.y[i]) and tau > 0:
417
+ expected_tdev = res_adev.y[i] * tau
418
+ relative_error = abs(res1.y[i] - expected_tdev) / expected_tdev
419
+ assert relative_error < 0.1, (
420
+ f"Time deviation should match ADEV * tau relationship at tau={tau}"
421
+ )
422
+
423
+
424
+ if __name__ == "__main__":
425
+ test_signal_allan_variance()
426
+ test_signal_allan_deviation()
427
+ test_signal_overlapping_allan_variance()
428
+ test_signal_modified_allan_variance()
429
+ test_signal_hadamard_variance()
430
+ test_signal_total_variance()
431
+ test_signal_time_deviation()