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,50 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ .. Scaling (see parent package :mod:`sigima.algorithms.signal`)
5
+
6
+ """
7
+
8
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
9
+
10
+ from __future__ import annotations
11
+
12
+ import numpy as np
13
+
14
+ from sigima.enums import NormalizationMethod
15
+
16
+
17
+ def normalize(
18
+ yin: np.ndarray,
19
+ parameter: NormalizationMethod = NormalizationMethod.MAXIMUM,
20
+ ) -> np.ndarray:
21
+ """Normalize input array to a given parameter.
22
+
23
+ Args:
24
+ yin: Input array
25
+ parameter: Normalization parameter. Defaults to MAXIMUM
26
+
27
+ Returns:
28
+ Normalized array
29
+ """
30
+ axis = len(yin.shape) - 1
31
+ if parameter == NormalizationMethod.MAXIMUM:
32
+ maximum = np.nanmax(yin, axis)
33
+ if axis == 1:
34
+ maximum = maximum.reshape((len(maximum), 1))
35
+ maxarray = np.tile(maximum, yin.shape[axis]).reshape(yin.shape)
36
+ return yin / maxarray
37
+ if parameter == NormalizationMethod.AMPLITUDE:
38
+ ytemp = np.array(yin, copy=True)
39
+ minimum = np.nanmin(yin, axis)
40
+ if axis == 1:
41
+ minimum = minimum.reshape((len(minimum), 1))
42
+ ytemp -= minimum
43
+ return normalize(ytemp, parameter=NormalizationMethod.MAXIMUM)
44
+ if parameter == NormalizationMethod.AREA:
45
+ return yin / np.nansum(yin)
46
+ if parameter == NormalizationMethod.ENERGY:
47
+ return yin / np.sqrt(np.nansum(yin * yin.conjugate()))
48
+ if parameter == NormalizationMethod.RMS:
49
+ return yin / np.sqrt(np.nanmean(yin * yin.conjugate()))
50
+ raise RuntimeError(f"Unsupported parameter {parameter}")
@@ -0,0 +1,258 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ .. Stability Analysis (see parent package :mod:`sigima.algorithms.signal`)
5
+
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import numpy as np
11
+
12
+ from sigima.tools.checks import check_1d_arrays
13
+
14
+
15
+ @check_1d_arrays(x_evenly_spaced=True)
16
+ def allan_variance(x: np.ndarray, y: np.ndarray, tau_values: np.ndarray) -> np.ndarray:
17
+ """
18
+ Calculate the Allan variance for given time and measurement values at specified
19
+ tau values.
20
+
21
+ Args:
22
+ x: Time array
23
+ y: Measured values array
24
+ tau_values: Allan deviation time values
25
+
26
+ Returns:
27
+ Allan variance values
28
+ """
29
+ if len(x) != len(y):
30
+ raise ValueError(
31
+ "Time array (x) and measured values array (y) must have the same length."
32
+ )
33
+
34
+ dt = np.mean(np.diff(x)) # Time step size
35
+ if not np.allclose(np.diff(x), dt):
36
+ raise ValueError("Time values (x) must be equally spaced.")
37
+
38
+ allan_var = []
39
+ for tau in tau_values:
40
+ m = int(round(tau / dt)) # Number of time steps in a tau
41
+ if m < 1:
42
+ raise ValueError(
43
+ f"Tau value {tau} is smaller than the sampling interval {dt}"
44
+ )
45
+ if m > len(y) // 2:
46
+ # Tau too large for reliable statistics
47
+ allan_var.append(np.nan)
48
+ continue
49
+
50
+ # Calculate the clusters/bins
51
+ clusters = y[: len(y) - (len(y) % m)].reshape(-1, m)
52
+ bin_means = clusters.mean(axis=1)
53
+
54
+ # Calculate Allan variance using the definition
55
+ # σ²(τ) = 1/(2(N-1)) Σ(y_(i+1) - y_i)²
56
+ # where y_i are the bin means
57
+ squared_diff = np.sum(np.diff(bin_means) ** 2)
58
+ n = len(bin_means) - 1
59
+
60
+ if n > 0:
61
+ var = squared_diff / (2.0 * n)
62
+ allan_var.append(var)
63
+ else:
64
+ allan_var.append(np.nan)
65
+
66
+ return np.array(allan_var)
67
+
68
+
69
+ @check_1d_arrays(x_evenly_spaced=True)
70
+ def allan_deviation(x: np.ndarray, y: np.ndarray, tau_values: np.ndarray) -> np.ndarray:
71
+ """
72
+ Calculate the Allan deviation for given time and measurement values at specified
73
+ tau values.
74
+
75
+ Args:
76
+ x: Time array
77
+ y: Measured values array
78
+ tau_values: Allan deviation time values
79
+
80
+ Returns:
81
+ Allan deviation values
82
+ """
83
+ return np.sqrt(allan_variance(x, y, tau_values))
84
+
85
+
86
+ @check_1d_arrays(x_evenly_spaced=True)
87
+ def overlapping_allan_variance(
88
+ x: np.ndarray, y: np.ndarray, tau_values: np.ndarray
89
+ ) -> np.ndarray:
90
+ """
91
+ Calculate the Overlapping Allan variance for given time and measurement values.
92
+
93
+ Args:
94
+ x: Time array
95
+ y: Measured values array
96
+ tau_values: Allan deviation time values
97
+
98
+ Returns:
99
+ Overlapping Allan variance values
100
+ """
101
+ if len(x) != len(y):
102
+ raise ValueError(
103
+ "Time array (x) and measured values array (y) must have the same length."
104
+ )
105
+
106
+ dt = np.mean(np.diff(x)) # Time step size
107
+ if not np.allclose(np.diff(x), dt):
108
+ raise ValueError("Time values (x) must be equally spaced.")
109
+
110
+ overlapping_var = []
111
+ for tau in tau_values:
112
+ tau_bins = int(tau / dt)
113
+ if tau_bins <= 1 or tau_bins > len(y) / 2:
114
+ overlapping_var.append(np.nan)
115
+ continue
116
+
117
+ m = len(y) - tau_bins # Number of overlapping segments
118
+ avg_values = [np.mean(y[i : i + tau_bins]) for i in range(m)]
119
+ diff = np.diff(avg_values)
120
+ overlapping_var.append(0.5 * np.mean(np.array(diff) ** 2))
121
+
122
+ return np.array(overlapping_var)
123
+
124
+
125
+ @check_1d_arrays(x_evenly_spaced=True)
126
+ def modified_allan_variance(
127
+ x: np.ndarray, y: np.ndarray, tau_values: np.ndarray
128
+ ) -> np.ndarray:
129
+ """
130
+ Calculate the Modified Allan variance for given time and measurement values.
131
+
132
+ Args:
133
+ x: Time array
134
+ y: Measured values array
135
+ tau_values: Modified Allan deviation time values
136
+
137
+ Returns:
138
+ Modified Allan variance values
139
+ """
140
+ if len(x) != len(y):
141
+ raise ValueError(
142
+ "Time array (x) and measured values array (y) must have the same length."
143
+ )
144
+
145
+ dt = np.mean(np.diff(x))
146
+ if not np.allclose(np.diff(x), dt):
147
+ raise ValueError("Time values (x) must be equally spaced.")
148
+
149
+ mod_allan_var = []
150
+ for tau in tau_values:
151
+ tau_bins = int(tau / dt)
152
+ if tau_bins <= 1 or tau_bins > len(y) / 2:
153
+ mod_allan_var.append(np.nan)
154
+ continue
155
+
156
+ m = int(len(y) / tau_bins)
157
+ reshaped = y[: m * tau_bins].reshape(m, tau_bins)
158
+
159
+ avg_values = reshaped.mean(axis=1)
160
+ squared_diff = (np.diff(avg_values)) ** 2
161
+ mod_allan_var.append(np.mean(squared_diff) / (2 * (tau_bins**2)))
162
+
163
+ return np.array(mod_allan_var)
164
+
165
+
166
+ @check_1d_arrays(x_evenly_spaced=True)
167
+ def hadamard_variance(
168
+ x: np.ndarray, y: np.ndarray, tau_values: np.ndarray
169
+ ) -> np.ndarray:
170
+ """
171
+ Calculate the Hadamard variance for given time and measurement values.
172
+
173
+ Args:
174
+ x: Time array
175
+ y: Measured values array
176
+ tau_values: Hadamard deviation time values
177
+
178
+ Returns:
179
+ Hadamard variance values
180
+ """
181
+ if len(x) != len(y):
182
+ raise ValueError(
183
+ "Time array (x) and measured values array (y) must have the same length."
184
+ )
185
+
186
+ dt = np.mean(np.diff(x))
187
+ if not np.allclose(np.diff(x), dt):
188
+ raise ValueError("Time values (x) must be equally spaced.")
189
+
190
+ hadamard_var = []
191
+ for tau in tau_values:
192
+ tau_bins = int(tau / dt)
193
+ if tau_bins <= 1 or tau_bins > len(y) / 3:
194
+ hadamard_var.append(np.nan)
195
+ continue
196
+
197
+ m = len(y) - 2 * tau_bins
198
+ avg_values = [np.mean(y[i : i + tau_bins]) for i in range(m)]
199
+ diff = np.diff(avg_values, n=2) # Second differences
200
+ hadamard_var.append(np.mean(diff**2) / 6)
201
+
202
+ return np.array(hadamard_var)
203
+
204
+
205
+ @check_1d_arrays(x_evenly_spaced=True)
206
+ def total_variance(x: np.ndarray, y: np.ndarray, tau_values: np.ndarray) -> np.ndarray:
207
+ """
208
+ Calculate the Total variance for given time and measurement values.
209
+
210
+ Args:
211
+ x: Time array
212
+ y: Measured values array
213
+ tau_values: Total variance time values
214
+
215
+ Returns:
216
+ Total variance values
217
+ """
218
+ if len(x) != len(y):
219
+ raise ValueError(
220
+ "Time array (x) and measured values array (y) must have the same length."
221
+ )
222
+
223
+ dt = np.mean(np.diff(x))
224
+ if not np.allclose(np.diff(x), dt):
225
+ raise ValueError("Time values (x) must be equally spaced.")
226
+
227
+ total_var = []
228
+ for tau in tau_values:
229
+ tau_bins = int(tau / dt)
230
+ if tau_bins <= 1 or tau_bins > len(y) / 2:
231
+ total_var.append(np.nan)
232
+ continue
233
+
234
+ m = int(len(y) / tau_bins)
235
+ reshaped = y[: m * tau_bins].reshape(m, tau_bins)
236
+
237
+ avg_values = reshaped.mean(axis=1)
238
+ squared_diff = np.diff(avg_values) ** 2
239
+ total_var.append(np.mean(squared_diff))
240
+
241
+ return np.array(total_var)
242
+
243
+
244
+ @check_1d_arrays(x_evenly_spaced=True)
245
+ def time_deviation(x: np.ndarray, y: np.ndarray, tau_values: np.ndarray) -> np.ndarray:
246
+ """
247
+ Calculate the Time Deviation (TDEV) for given time and measurement values.
248
+
249
+ Args:
250
+ x: Time array
251
+ y: Measured values array
252
+ tau_values: Time deviation time values
253
+
254
+ Returns:
255
+ Time deviation values
256
+ """
257
+ allan_var = allan_variance(x, y, tau_values)
258
+ return np.sqrt(allan_var) * tau_values
@@ -0,0 +1,90 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ .. Windowing (see parent package :mod:`sigima.algorithms.signal`)
5
+
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Callable
11
+
12
+ import numpy as np
13
+ import scipy.signal.windows
14
+
15
+ from sigima.enums import WindowingMethod
16
+
17
+
18
+ def get_window(method: WindowingMethod) -> Callable[[int], np.ndarray]:
19
+ """Get the window function.
20
+
21
+ .. note::
22
+
23
+ The window functions are from `scipy.signal.windows` and `numpy`.
24
+ All functions take an integer argument that specifies the length of the window,
25
+ and return a NumPy array of the same length.
26
+
27
+ Args:
28
+ method: Windowing function method.
29
+
30
+ Returns:
31
+ Window function.
32
+
33
+ Raises:
34
+ ValueError: If the method is not recognized.
35
+ """
36
+ win_func = {
37
+ WindowingMethod.BARTHANN: scipy.signal.windows.barthann,
38
+ WindowingMethod.BARTLETT: np.bartlett,
39
+ WindowingMethod.BLACKMAN: np.blackman,
40
+ WindowingMethod.BLACKMAN_HARRIS: scipy.signal.windows.blackmanharris,
41
+ WindowingMethod.BOHMAN: scipy.signal.windows.bohman,
42
+ WindowingMethod.BOXCAR: scipy.signal.windows.boxcar,
43
+ WindowingMethod.COSINE: scipy.signal.windows.cosine,
44
+ WindowingMethod.EXPONENTIAL: scipy.signal.windows.exponential,
45
+ WindowingMethod.FLAT_TOP: scipy.signal.windows.flattop,
46
+ WindowingMethod.HAMMING: np.hamming,
47
+ WindowingMethod.HANN: np.hanning,
48
+ WindowingMethod.LANCZOS: scipy.signal.windows.lanczos,
49
+ WindowingMethod.NUTTALL: scipy.signal.windows.nuttall,
50
+ WindowingMethod.PARZEN: scipy.signal.windows.parzen,
51
+ WindowingMethod.TAYLOR: scipy.signal.windows.taylor,
52
+ }.get(method)
53
+ if win_func is not None:
54
+ return win_func
55
+ raise ValueError(f"Invalid window type {method.value}")
56
+
57
+
58
+ def apply_window(
59
+ y: np.ndarray,
60
+ method: WindowingMethod = WindowingMethod.HAMMING,
61
+ alpha: float = 0.5,
62
+ beta: float = 14.0,
63
+ sigma: float = 7.0,
64
+ ) -> np.ndarray:
65
+ """Apply windowing to the input data.
66
+
67
+ Args:
68
+ x: X data.
69
+ y: Y data.
70
+ method: Windowing function. Defaults to "HAMMING".
71
+ alpha: Tukey window parameter. Defaults to 0.5.
72
+ beta: Kaiser window parameter. Defaults to 14.0.
73
+ sigma: Gaussian window parameter. Defaults to 7.0.
74
+
75
+ Returns:
76
+ Windowed Y data.
77
+
78
+ Raises:
79
+ ValueError: If the method is not recognized.
80
+ """
81
+ # Cases with parameters:
82
+ if method == WindowingMethod.GAUSSIAN:
83
+ return y * scipy.signal.windows.gaussian(len(y), sigma)
84
+ if method == WindowingMethod.KAISER:
85
+ return y * np.kaiser(len(y), beta)
86
+ if method == WindowingMethod.TUKEY:
87
+ return y * scipy.signal.windows.tukey(len(y), alpha)
88
+ # Cases without parameters:
89
+ win_func = get_window(method)
90
+ return y * win_func(len(y))
sigima/worker.py ADDED
@@ -0,0 +1,79 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Worker (:mod:`sigima.worker`)
5
+ ------------------------------
6
+
7
+ This module provides a minimal interface for executing long-running operations
8
+ with support for progress reporting and cancellation.
9
+
10
+ It defines a generic protocol (`CallbackWorkerProtocol`) and a console-based
11
+ implementation (`TextCallbackWorker`), suitable for non-GUI environments.
12
+
13
+ Example:
14
+
15
+ .. code-block:: python
16
+
17
+ from sigima.worker import TextCallbackWorker
18
+
19
+ def long_task(worker=None):
20
+ for i in range(10):
21
+ if worker and worker.was_canceled():
22
+ return None
23
+ worker.set_progress(i / 10)
24
+ return "done"
25
+
26
+ worker = TextCallbackWorker()
27
+ result = long_task(worker=worker)
28
+ """
29
+
30
+ from typing import Protocol, runtime_checkable
31
+
32
+
33
+ @runtime_checkable
34
+ class CallbackWorkerProtocol(Protocol):
35
+ """Protocol defining the minimal interface for progress/cancel-aware workers."""
36
+
37
+ def set_progress(self, value: float) -> None:
38
+ """Update progress (between 0.0 and 1.0)."""
39
+
40
+ def was_canceled(self) -> bool:
41
+ """Check whether the operation has been canceled."""
42
+
43
+
44
+ class TextCallbackWorker:
45
+ """Minimal worker implementation for console-based environments.
46
+
47
+ Provides `set_progress()` and `was_canceled()` methods for use in long-running
48
+ computations. Intended for use in `sigima` where no GUI (e.g. Qt) is available.
49
+
50
+ Attributes:
51
+ _canceled: Whether the operation was canceled.
52
+ _progress: Most recent progress value.
53
+ """
54
+
55
+ def __init__(self) -> None:
56
+ self._canceled = False
57
+ self._progress = 0.0
58
+
59
+ def set_progress(self, value: float) -> None:
60
+ """Set the progress of the operation (prints to console).
61
+
62
+ Args:
63
+ value: Float between 0.0 and 1.0.
64
+ """
65
+ self._progress = min(max(value, 0.0), 1.0)
66
+ percent = int(self._progress * 100)
67
+ print(f"[sigima] Progress: {percent}%")
68
+
69
+ def was_canceled(self) -> bool:
70
+ """Return whether the operation has been canceled."""
71
+ return self._canceled
72
+
73
+ def cancel(self) -> None:
74
+ """Cancel the operation."""
75
+ self._canceled = True
76
+
77
+ def get_progress(self) -> float:
78
+ """Return the current progress value."""
79
+ return self._progress