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.
- sigima/__init__.py +142 -2
- sigima/client/__init__.py +105 -0
- sigima/client/base.py +780 -0
- sigima/client/remote.py +469 -0
- sigima/client/stub.py +814 -0
- sigima/client/utils.py +90 -0
- sigima/config.py +444 -0
- sigima/data/logo/Sigima.svg +135 -0
- sigima/data/tests/annotations.json +798 -0
- sigima/data/tests/curve_fitting/exponential_fit.txt +511 -0
- sigima/data/tests/curve_fitting/gaussian_fit.txt +100 -0
- sigima/data/tests/curve_fitting/piecewiseexponential_fit.txt +1022 -0
- sigima/data/tests/curve_fitting/polynomial_fit.txt +100 -0
- sigima/data/tests/curve_fitting/twohalfgaussian_fit.txt +1000 -0
- sigima/data/tests/curve_formats/bandwidth.txt +201 -0
- sigima/data/tests/curve_formats/boxcar.npy +0 -0
- sigima/data/tests/curve_formats/datetime.txt +1001 -0
- sigima/data/tests/curve_formats/dynamic_parameters.txt +4000 -0
- sigima/data/tests/curve_formats/fw1e2.txt +301 -0
- sigima/data/tests/curve_formats/fwhm.txt +319 -0
- sigima/data/tests/curve_formats/multiple_curves.csv +29 -0
- sigima/data/tests/curve_formats/noised_saw.mat +0 -0
- sigima/data/tests/curve_formats/oscilloscope.csv +111 -0
- sigima/data/tests/curve_formats/other/other2/recursive2.txt +5 -0
- sigima/data/tests/curve_formats/other/recursive1.txt +5 -0
- sigima/data/tests/curve_formats/paracetamol.npy +0 -0
- sigima/data/tests/curve_formats/paracetamol.txt +1010 -0
- sigima/data/tests/curve_formats/paracetamol_dx_dy.csv +1000 -0
- sigima/data/tests/curve_formats/paracetamol_dy.csv +1001 -0
- sigima/data/tests/curve_formats/pulse1.npy +0 -0
- sigima/data/tests/curve_formats/pulse2.npy +0 -0
- sigima/data/tests/curve_formats/simple.txt +5 -0
- sigima/data/tests/curve_formats/spectrum.mca +2139 -0
- sigima/data/tests/curve_formats/square2.npy +0 -0
- sigima/data/tests/curve_formats/step.npy +0 -0
- sigima/data/tests/fabry-perot1.jpg +0 -0
- sigima/data/tests/fabry-perot2.jpg +0 -0
- sigima/data/tests/flower.npy +0 -0
- sigima/data/tests/image_formats/NF 180338201.scor-data +11003 -0
- sigima/data/tests/image_formats/binary_image.npy +0 -0
- sigima/data/tests/image_formats/binary_image.png +0 -0
- sigima/data/tests/image_formats/centroid_test.npy +0 -0
- sigima/data/tests/image_formats/coordinated_text/complex_image.txt +10011 -0
- sigima/data/tests/image_formats/coordinated_text/complex_ref_image.txt +10010 -0
- sigima/data/tests/image_formats/coordinated_text/image.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image2.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_no_unit_no_label.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_nan.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_unit.txt +14 -0
- sigima/data/tests/image_formats/fiber.csv +480 -0
- sigima/data/tests/image_formats/fiber.jpg +0 -0
- sigima/data/tests/image_formats/fiber.png +0 -0
- sigima/data/tests/image_formats/fiber.txt +480 -0
- sigima/data/tests/image_formats/gaussian_spot_with_noise.npy +0 -0
- sigima/data/tests/image_formats/mr-brain.dcm +0 -0
- sigima/data/tests/image_formats/noised_gaussian.mat +0 -0
- sigima/data/tests/image_formats/sif_reader/nd_lum_image_no_glue.sif +0 -0
- sigima/data/tests/image_formats/sif_reader/raman1.sif +0 -0
- sigima/data/tests/image_formats/tiling.txt +10 -0
- sigima/data/tests/image_formats/uint16.tiff +0 -0
- sigima/data/tests/image_formats/uint8.tiff +0 -0
- sigima/data/tests/laser_beam/TEM00_z_13.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_18.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_23.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_30.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_35.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_40.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_45.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_50.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_55.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_60.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_65.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_70.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_75.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_80.jpg +0 -0
- sigima/enums.py +195 -0
- sigima/io/__init__.py +123 -0
- sigima/io/base.py +311 -0
- sigima/io/common/__init__.py +5 -0
- sigima/io/common/basename.py +164 -0
- sigima/io/common/converters.py +189 -0
- sigima/io/common/objmeta.py +181 -0
- sigima/io/common/textreader.py +58 -0
- sigima/io/convenience.py +157 -0
- sigima/io/enums.py +17 -0
- sigima/io/ftlab.py +395 -0
- sigima/io/image/__init__.py +9 -0
- sigima/io/image/base.py +177 -0
- sigima/io/image/formats.py +1016 -0
- sigima/io/image/funcs.py +414 -0
- sigima/io/signal/__init__.py +9 -0
- sigima/io/signal/base.py +129 -0
- sigima/io/signal/formats.py +290 -0
- sigima/io/signal/funcs.py +723 -0
- sigima/objects/__init__.py +260 -0
- sigima/objects/base.py +937 -0
- sigima/objects/image/__init__.py +88 -0
- sigima/objects/image/creation.py +556 -0
- sigima/objects/image/object.py +524 -0
- sigima/objects/image/roi.py +904 -0
- sigima/objects/scalar/__init__.py +57 -0
- sigima/objects/scalar/common.py +215 -0
- sigima/objects/scalar/geometry.py +502 -0
- sigima/objects/scalar/table.py +784 -0
- sigima/objects/shape.py +290 -0
- sigima/objects/signal/__init__.py +133 -0
- sigima/objects/signal/constants.py +27 -0
- sigima/objects/signal/creation.py +1428 -0
- sigima/objects/signal/object.py +444 -0
- sigima/objects/signal/roi.py +274 -0
- sigima/params.py +405 -0
- sigima/proc/__init__.py +96 -0
- sigima/proc/base.py +381 -0
- sigima/proc/decorator.py +330 -0
- sigima/proc/image/__init__.py +513 -0
- sigima/proc/image/arithmetic.py +335 -0
- sigima/proc/image/base.py +260 -0
- sigima/proc/image/detection.py +519 -0
- sigima/proc/image/edges.py +329 -0
- sigima/proc/image/exposure.py +406 -0
- sigima/proc/image/extraction.py +458 -0
- sigima/proc/image/filtering.py +219 -0
- sigima/proc/image/fourier.py +147 -0
- sigima/proc/image/geometry.py +661 -0
- sigima/proc/image/mathops.py +340 -0
- sigima/proc/image/measurement.py +195 -0
- sigima/proc/image/morphology.py +155 -0
- sigima/proc/image/noise.py +107 -0
- sigima/proc/image/preprocessing.py +182 -0
- sigima/proc/image/restoration.py +235 -0
- sigima/proc/image/threshold.py +217 -0
- sigima/proc/image/transformations.py +393 -0
- sigima/proc/signal/__init__.py +376 -0
- sigima/proc/signal/analysis.py +206 -0
- sigima/proc/signal/arithmetic.py +551 -0
- sigima/proc/signal/base.py +262 -0
- sigima/proc/signal/extraction.py +60 -0
- sigima/proc/signal/features.py +310 -0
- sigima/proc/signal/filtering.py +484 -0
- sigima/proc/signal/fitting.py +276 -0
- sigima/proc/signal/fourier.py +259 -0
- sigima/proc/signal/mathops.py +420 -0
- sigima/proc/signal/processing.py +580 -0
- sigima/proc/signal/stability.py +175 -0
- sigima/proc/title_formatting.py +227 -0
- sigima/proc/validation.py +272 -0
- sigima/tests/__init__.py +7 -0
- sigima/tests/common/__init__.py +0 -0
- sigima/tests/common/arithmeticparam_unit_test.py +26 -0
- sigima/tests/common/basename_unit_test.py +126 -0
- sigima/tests/common/client_unit_test.py +412 -0
- sigima/tests/common/converters_unit_test.py +77 -0
- sigima/tests/common/decorator_unit_test.py +176 -0
- sigima/tests/common/examples_unit_test.py +104 -0
- sigima/tests/common/kernel_normalization_unit_test.py +242 -0
- sigima/tests/common/roi_basic_unit_test.py +73 -0
- sigima/tests/common/roi_geometry_unit_test.py +171 -0
- sigima/tests/common/scalar_builder_unit_test.py +142 -0
- sigima/tests/common/scalar_unit_test.py +991 -0
- sigima/tests/common/shape_unit_test.py +183 -0
- sigima/tests/common/stat_unit_test.py +138 -0
- sigima/tests/common/title_formatting_unit_test.py +338 -0
- sigima/tests/common/tools_coordinates_unit_test.py +60 -0
- sigima/tests/common/transformations_unit_test.py +178 -0
- sigima/tests/common/validation_unit_test.py +205 -0
- sigima/tests/conftest.py +129 -0
- sigima/tests/data.py +998 -0
- sigima/tests/env.py +280 -0
- sigima/tests/guiutils.py +163 -0
- sigima/tests/helpers.py +532 -0
- sigima/tests/image/__init__.py +28 -0
- sigima/tests/image/binning_unit_test.py +128 -0
- sigima/tests/image/blob_detection_unit_test.py +312 -0
- sigima/tests/image/centroid_unit_test.py +170 -0
- sigima/tests/image/check_2d_array_unit_test.py +63 -0
- sigima/tests/image/contour_unit_test.py +172 -0
- sigima/tests/image/convolution_unit_test.py +178 -0
- sigima/tests/image/datatype_unit_test.py +67 -0
- sigima/tests/image/edges_unit_test.py +155 -0
- sigima/tests/image/enclosingcircle_unit_test.py +88 -0
- sigima/tests/image/exposure_unit_test.py +223 -0
- sigima/tests/image/fft2d_unit_test.py +189 -0
- sigima/tests/image/filtering_unit_test.py +166 -0
- sigima/tests/image/geometry_unit_test.py +654 -0
- sigima/tests/image/hough_circle_unit_test.py +147 -0
- sigima/tests/image/imageobj_unit_test.py +737 -0
- sigima/tests/image/morphology_unit_test.py +71 -0
- sigima/tests/image/noise_unit_test.py +57 -0
- sigima/tests/image/offset_correction_unit_test.py +72 -0
- sigima/tests/image/operation_unit_test.py +518 -0
- sigima/tests/image/peak2d_limits_unit_test.py +41 -0
- sigima/tests/image/peak2d_unit_test.py +133 -0
- sigima/tests/image/profile_unit_test.py +159 -0
- sigima/tests/image/projections_unit_test.py +121 -0
- sigima/tests/image/restoration_unit_test.py +141 -0
- sigima/tests/image/roi2dparam_unit_test.py +53 -0
- sigima/tests/image/roi_advanced_unit_test.py +588 -0
- sigima/tests/image/roi_grid_unit_test.py +279 -0
- sigima/tests/image/spectrum2d_unit_test.py +40 -0
- sigima/tests/image/threshold_unit_test.py +91 -0
- sigima/tests/io/__init__.py +0 -0
- sigima/tests/io/addnewformat_unit_test.py +125 -0
- sigima/tests/io/convenience_funcs_unit_test.py +470 -0
- sigima/tests/io/coordinated_text_format_unit_test.py +495 -0
- sigima/tests/io/datetime_csv_unit_test.py +198 -0
- sigima/tests/io/imageio_formats_test.py +41 -0
- sigima/tests/io/ioregistry_unit_test.py +69 -0
- sigima/tests/io/objmeta_unit_test.py +87 -0
- sigima/tests/io/readobj_unit_test.py +130 -0
- sigima/tests/io/readwriteobj_unit_test.py +67 -0
- sigima/tests/signal/__init__.py +0 -0
- sigima/tests/signal/analysis_unit_test.py +135 -0
- sigima/tests/signal/check_1d_arrays_unit_test.py +169 -0
- sigima/tests/signal/convolution_unit_test.py +404 -0
- sigima/tests/signal/datetime_unit_test.py +176 -0
- sigima/tests/signal/fft1d_unit_test.py +303 -0
- sigima/tests/signal/filters_unit_test.py +403 -0
- sigima/tests/signal/fitting_unit_test.py +929 -0
- sigima/tests/signal/fwhm_unit_test.py +111 -0
- sigima/tests/signal/noise_unit_test.py +128 -0
- sigima/tests/signal/offset_correction_unit_test.py +34 -0
- sigima/tests/signal/operation_unit_test.py +489 -0
- sigima/tests/signal/peakdetection_unit_test.py +145 -0
- sigima/tests/signal/processing_unit_test.py +657 -0
- sigima/tests/signal/pulse/__init__.py +112 -0
- sigima/tests/signal/pulse/crossing_times_unit_test.py +123 -0
- sigima/tests/signal/pulse/plateau_detection_unit_test.py +102 -0
- sigima/tests/signal/pulse/pulse_unit_test.py +1824 -0
- sigima/tests/signal/roi_advanced_unit_test.py +392 -0
- sigima/tests/signal/signalobj_unit_test.py +603 -0
- sigima/tests/signal/stability_unit_test.py +431 -0
- sigima/tests/signal/uncertainty_unit_test.py +611 -0
- sigima/tests/vistools.py +1030 -0
- sigima/tools/__init__.py +59 -0
- sigima/tools/checks.py +290 -0
- sigima/tools/coordinates.py +308 -0
- sigima/tools/datatypes.py +26 -0
- sigima/tools/image/__init__.py +97 -0
- sigima/tools/image/detection.py +451 -0
- sigima/tools/image/exposure.py +77 -0
- sigima/tools/image/extraction.py +48 -0
- sigima/tools/image/fourier.py +260 -0
- sigima/tools/image/geometry.py +190 -0
- sigima/tools/image/preprocessing.py +165 -0
- sigima/tools/signal/__init__.py +86 -0
- sigima/tools/signal/dynamic.py +254 -0
- sigima/tools/signal/features.py +135 -0
- sigima/tools/signal/filtering.py +171 -0
- sigima/tools/signal/fitting.py +1171 -0
- sigima/tools/signal/fourier.py +466 -0
- sigima/tools/signal/interpolation.py +70 -0
- sigima/tools/signal/peakdetection.py +126 -0
- sigima/tools/signal/pulse.py +1626 -0
- sigima/tools/signal/scaling.py +50 -0
- sigima/tools/signal/stability.py +258 -0
- sigima/tools/signal/windowing.py +90 -0
- sigima/worker.py +79 -0
- sigima-1.0.0.dist-info/METADATA +233 -0
- sigima-1.0.0.dist-info/RECORD +262 -0
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/licenses/LICENSE +29 -29
- sigima-0.0.1.dev0.dist-info/METADATA +0 -60
- sigima-0.0.1.dev0.dist-info/RECORD +0 -6
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/WHEEL +0 -0
- {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()
|