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,111 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Unit tests for full width computing features
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
+ import pytest
13
+
14
+ import sigima.objects
15
+ import sigima.params
16
+ import sigima.proc.signal
17
+ import sigima.tests.data
18
+ import sigima.tests.helpers
19
+ from sigima.tests import guiutils
20
+ from sigima.tests.env import execenv
21
+
22
+
23
+ def __test_fwhm_interactive(obj: sigima.objects.SignalObj, method: str) -> None:
24
+ """Interactive test for the full width at half maximum computation."""
25
+ # pylint: disable=import-outside-toplevel
26
+ from plotpy.builder import make
27
+
28
+ from sigima.tests import vistools
29
+
30
+ param = sigima.params.FWHMParam.create(method=method)
31
+ geometry = sigima.proc.signal.fwhm(obj, param)
32
+ x0, y0, x1, y1 = geometry.coords[0]
33
+ x, y = obj.xydata
34
+ vistools.view_curve_items(
35
+ [
36
+ make.mcurve(x.real, y.real, label=obj.title),
37
+ vistools.create_signal_segment(x0, y0, x1, y1, "FWHM"),
38
+ ],
39
+ title=f"FWHM [{method}]",
40
+ )
41
+
42
+
43
+ @pytest.mark.gui
44
+ def test_signal_fwhm_interactive() -> None:
45
+ """FWHM interactive test."""
46
+ with guiutils.lazy_qt_app_context(force=True):
47
+ execenv.print("Computing FWHM of a multi-peak signal:")
48
+ obj1 = sigima.tests.data.create_paracetamol_signal()
49
+ p = sigima.objects.NormalDistribution1DParam.create(sigma=0.05)
50
+ obj2 = sigima.tests.data.create_noisy_signal(p)
51
+ for method, _mname in sigima.params.FWHMParam.methods:
52
+ execenv.print(f" Method: {method}")
53
+ for obj in (obj1, obj2):
54
+ if method == "zero-crossing":
55
+ # Check that a warning is raised when using the zero-crossing method
56
+ with pytest.warns(UserWarning):
57
+ __test_fwhm_interactive(obj, method)
58
+ else:
59
+ __test_fwhm_interactive(obj, method)
60
+
61
+
62
+ @pytest.mark.validation
63
+ def test_signal_fwhm() -> None:
64
+ """Validation test for the full width at half maximum computation."""
65
+ obj = sigima.tests.data.get_test_signal("fwhm.txt")
66
+ real_fwhm = 2.675 # Manual validation
67
+ for method, exp in (
68
+ ("gauss", 2.40323),
69
+ ("lorentz", 2.78072),
70
+ ("voigt", 2.56591),
71
+ ("zero-crossing", real_fwhm),
72
+ ):
73
+ param = sigima.params.FWHMParam.create(method=method)
74
+ geometry = sigima.proc.signal.fwhm(obj, param)
75
+ length = geometry.segments_lengths()[0]
76
+ sigima.tests.helpers.check_scalar_result(
77
+ f"FWHM[{method}]", length, exp, rtol=0.05
78
+ )
79
+ obj = sigima.tests.data.create_paracetamol_signal()
80
+ with pytest.warns(UserWarning):
81
+ sigima.proc.signal.fwhm(
82
+ obj, sigima.params.FWHMParam.create(method="zero-crossing")
83
+ )
84
+
85
+
86
+ @pytest.mark.validation
87
+ def test_signal_fw1e2() -> None:
88
+ """Validation test for the full width at 1/e^2 maximum computation."""
89
+ obj = sigima.tests.data.get_test_signal("fw1e2.txt")
90
+ exp = 4.06 # Manual validation
91
+ geometry = sigima.proc.signal.fw1e2(obj)
92
+ length = geometry.segments_lengths()[0]
93
+ sigima.tests.helpers.check_scalar_result("FW1E2", length, exp, rtol=0.005)
94
+
95
+
96
+ @pytest.mark.validation
97
+ def test_signal_full_width_at_y() -> None:
98
+ """Validation test for the full width at y computation."""
99
+ obj = sigima.tests.data.get_test_signal("fwhm.txt")
100
+ real_fwhm = 2.675 # Manual validation
101
+ param = sigima.params.OrdinateParam.create(y=0.5)
102
+ geometry = sigima.proc.signal.full_width_at_y(obj, param)
103
+ length = geometry.segments_lengths()[0]
104
+ sigima.tests.helpers.check_scalar_result("∆X", length, real_fwhm, rtol=0.05)
105
+
106
+
107
+ if __name__ == "__main__":
108
+ test_signal_fwhm_interactive()
109
+ test_signal_fwhm()
110
+ test_signal_fw1e2()
111
+ test_signal_full_width_at_y()
@@ -0,0 +1,128 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """Unit tests for signal noise addition."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import numpy as np
8
+ import pytest
9
+
10
+ import sigima.proc.signal
11
+ from sigima.objects import SineParam, create_signal_from_param
12
+ from sigima.objects.signal import (
13
+ NormalDistribution1DParam,
14
+ PoissonDistribution1DParam,
15
+ UniformDistribution1DParam,
16
+ )
17
+ from sigima.tests import guiutils
18
+ from sigima.tests.helpers import check_array_result, check_scalar_result
19
+
20
+
21
+ @pytest.mark.validation
22
+ def test_add_gaussian_noise() -> None:
23
+ """Test :py:func:`sigima.proc.signal.add_gaussian_noise`."""
24
+ # Generate source signal.
25
+ size = 1024
26
+ param = SineParam.create(size=size, freq=1.0)
27
+ src = create_signal_from_param(param)
28
+ # Add Gaussian noise.
29
+ # Run twice with same parameters to check reproducibility.
30
+ p = NormalDistribution1DParam.create(seed=42, mu=0.0, sigma=0.1)
31
+ res1 = sigima.proc.signal.add_gaussian_noise(src, p)
32
+ res2 = sigima.proc.signal.add_gaussian_noise(src, p)
33
+
34
+ guiutils.view_curves_if_gui(
35
+ [src, res1, res2],
36
+ title="Gaussian Noise Addition: Noisy images should be identical (same seed)",
37
+ )
38
+
39
+ # X-axis must be preserved.
40
+ check_array_result("res1.x", res1.x, src.x)
41
+
42
+ # Check noise statistics.
43
+ noise = res1.y - src.y
44
+ mean_noise = float(np.mean(noise))
45
+ assert p.mu is not None
46
+ assert p.sigma is not None
47
+ expected_error = 5.0 * p.sigma / np.sqrt(src.x.size)
48
+ check_scalar_result("Mean noise", mean_noise, p.mu, atol=expected_error)
49
+
50
+ # Identical results for same seed and distribution parameters.
51
+ check_array_result("Reproducibility", res1.y, res2.y)
52
+
53
+
54
+ @pytest.mark.validation
55
+ def test_add_poisson_noise() -> None:
56
+ """Test :py:func:`sigima.proc.signal.add_poisson_noise`."""
57
+ # Generate source signal.
58
+ size = 1024
59
+ param = SineParam.create(size=size, freq=1.0)
60
+ src = create_signal_from_param(param)
61
+ # Add Poisson noise.
62
+ # Run twice with same parameters to check reproducibility.
63
+ p = PoissonDistribution1DParam.create(seed=42, lam=2.0)
64
+ res1 = sigima.proc.signal.add_poisson_noise(src, p)
65
+ res2 = sigima.proc.signal.add_poisson_noise(src, p)
66
+
67
+ guiutils.view_curves_if_gui(
68
+ [src, res1, res2],
69
+ title="Poisson Noise Addition: Noisy signals should be identical (same seed)",
70
+ )
71
+
72
+ # X-axis must be preserved.
73
+ check_array_result("res1.x", res1.x, src.x)
74
+
75
+ # Check noise statistics.
76
+ noise = res1.y - src.y
77
+ mean_noise = float(np.mean(noise))
78
+ assert p.lam is not None
79
+ # For Poisson distribution, mean equals lambda, but we check with tolerance
80
+ # since we're adding noise to an existing signal
81
+ expected_error = 5.0 * np.sqrt(p.lam) / np.sqrt(src.x.size)
82
+ check_scalar_result("Mean noise", mean_noise, p.lam, atol=expected_error)
83
+
84
+ # Identical results for same seed and distribution parameters.
85
+ check_array_result("Reproducibility", res1.y, res2.y)
86
+
87
+
88
+ @pytest.mark.validation
89
+ def test_add_uniform_noise() -> None:
90
+ """Test :py:func:`sigima.proc.signal.add_uniform_noise`."""
91
+ # Generate source signal.
92
+ size = 1024
93
+ param = SineParam.create(size=size, freq=1.0)
94
+ src = create_signal_from_param(param)
95
+ # Add uniform noise.
96
+ # Run twice with same parameters to check reproducibility.
97
+ p = UniformDistribution1DParam.create(seed=42, vmin=-0.5, vmax=0.5)
98
+ res1 = sigima.proc.signal.add_uniform_noise(src, p)
99
+ res2 = sigima.proc.signal.add_uniform_noise(src, p)
100
+
101
+ guiutils.view_curves_if_gui(
102
+ [src, res1, res2],
103
+ title="Uniform Noise Addition: Noisy signals should be identical (same seed)",
104
+ )
105
+
106
+ # X-axis must be preserved.
107
+ check_array_result("res1.x", res1.x, src.x)
108
+
109
+ # Check noise statistics.
110
+ noise = res1.y - src.y
111
+ mean_noise = float(np.mean(noise))
112
+ assert p.vmin is not None
113
+ assert p.vmax is not None
114
+ expected_mean = (p.vmin + p.vmax) / 2.0
115
+ # For uniform distribution, standard deviation is (vmax - vmin) / sqrt(12)
116
+ expected_std = (p.vmax - p.vmin) / np.sqrt(12.0)
117
+ expected_error = 5.0 * expected_std / np.sqrt(src.x.size)
118
+ check_scalar_result("Mean noise", mean_noise, expected_mean, atol=expected_error)
119
+
120
+ # Identical results for same seed and distribution parameters.
121
+ check_array_result("Reproducibility", res1.y, res2.y)
122
+
123
+
124
+ if __name__ == "__main__":
125
+ guiutils.enable_gui()
126
+ test_add_gaussian_noise()
127
+ test_add_poisson_noise()
128
+ test_add_uniform_noise()
@@ -0,0 +1,34 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Signal offset correction 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
+ import numpy as np
13
+ import pytest
14
+
15
+ import sigima.objects
16
+ import sigima.proc.signal
17
+ from sigima.tests.data import create_paracetamol_signal
18
+
19
+
20
+ @pytest.mark.validation
21
+ def test_signal_offset_correction() -> None:
22
+ """Signal offset correction validation test."""
23
+ s1 = create_paracetamol_signal()
24
+ param = sigima.objects.ROI1DParam.create(xmin=10.0, xmax=12.0)
25
+ s2 = sigima.proc.signal.offset_correction(s1, param)
26
+
27
+ # Check that the offset correction has been applied
28
+ imin, imax = np.searchsorted(s1.x, [param.xmin, param.xmax])
29
+ offset = np.mean(s1.y[imin:imax])
30
+ assert np.allclose(s2.y, s1.y - offset), "Offset correction failed"
31
+
32
+
33
+ if __name__ == "__main__":
34
+ test_signal_offset_correction()