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,420 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Mathematical operations on signals
|
|
5
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
import guidata.dataset as gds
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
from sigima.config import _
|
|
16
|
+
from sigima.enums import AngleUnit
|
|
17
|
+
from sigima.objects import SignalObj
|
|
18
|
+
from sigima.proc.base import AngleUnitParam, PhaseParam, dst_1_to_1, dst_2_to_1
|
|
19
|
+
from sigima.proc.decorator import computation_function
|
|
20
|
+
from sigima.proc.signal.base import (
|
|
21
|
+
Wrap1to1Func,
|
|
22
|
+
is_uncertainty_data_available,
|
|
23
|
+
restore_data_outside_roi,
|
|
24
|
+
)
|
|
25
|
+
from sigima.tools import coordinates
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@computation_function()
|
|
29
|
+
def transpose(src: SignalObj) -> SignalObj:
|
|
30
|
+
"""Transpose signal (swap X and Y axes).
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
src: Source signal.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Result signal object.
|
|
37
|
+
"""
|
|
38
|
+
dst = dst_1_to_1(src, "transpose")
|
|
39
|
+
x, y = src.get_data()
|
|
40
|
+
dst.set_xydata(y, x, src.dy, src.dx)
|
|
41
|
+
dst.xlabel = src.ylabel
|
|
42
|
+
dst.ylabel = src.xlabel
|
|
43
|
+
dst.xunit = src.yunit
|
|
44
|
+
dst.yunit = src.xunit
|
|
45
|
+
return dst
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@computation_function()
|
|
49
|
+
def inverse(src: SignalObj) -> SignalObj:
|
|
50
|
+
"""Compute the element-wise inverse of a signal.
|
|
51
|
+
|
|
52
|
+
The function computes the reciprocal (1/y) of each element of the input signal.
|
|
53
|
+
|
|
54
|
+
.. note::
|
|
55
|
+
|
|
56
|
+
If the signal has a region of interest (ROI), the inverse is performed
|
|
57
|
+
only within the ROI.
|
|
58
|
+
|
|
59
|
+
.. note::
|
|
60
|
+
|
|
61
|
+
Uncertainties are propagated.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
src: Input signal object.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Result signal object representing the inverse of the input signal.
|
|
68
|
+
"""
|
|
69
|
+
dst = dst_1_to_1(src, "invert")
|
|
70
|
+
x, y = src.get_data()
|
|
71
|
+
with warnings.catch_warnings():
|
|
72
|
+
warnings.simplefilter("ignore", category=RuntimeWarning)
|
|
73
|
+
dst.set_xydata(x, np.reciprocal(y))
|
|
74
|
+
dst.y[np.isinf(dst.y)] = np.nan
|
|
75
|
+
if is_uncertainty_data_available(src):
|
|
76
|
+
err = np.abs(dst.y) * (src.dy / np.abs(src.y))
|
|
77
|
+
err[np.isinf(err)] = np.nan
|
|
78
|
+
dst.dy = err
|
|
79
|
+
restore_data_outside_roi(dst, src)
|
|
80
|
+
return dst
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@computation_function()
|
|
84
|
+
def absolute(src: SignalObj) -> SignalObj:
|
|
85
|
+
"""Compute absolute value with :py:data:`numpy.absolute`
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
src: source signal
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Result signal object
|
|
92
|
+
"""
|
|
93
|
+
return Wrap1to1Func(np.absolute)(src)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@computation_function()
|
|
97
|
+
def real(src: SignalObj) -> SignalObj:
|
|
98
|
+
"""Compute real part with :py:func:`numpy.real`
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
src: source signal
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Result signal object
|
|
105
|
+
"""
|
|
106
|
+
return Wrap1to1Func(np.real)(src)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@computation_function()
|
|
110
|
+
def imag(src: SignalObj) -> SignalObj:
|
|
111
|
+
"""Compute imaginary part with :py:func:`numpy.imag`
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
src: source signal
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Result signal object
|
|
118
|
+
"""
|
|
119
|
+
return Wrap1to1Func(np.imag)(src)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@computation_function()
|
|
123
|
+
def phase(src: SignalObj, p: PhaseParam) -> SignalObj:
|
|
124
|
+
"""Compute the phase (argument) of a complex signal.
|
|
125
|
+
|
|
126
|
+
The function uses :py:func:`numpy.angle` to compute the argument and
|
|
127
|
+
:py:func:`numpy.unwrap` to unwrap it.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
src: Input signal object.
|
|
131
|
+
p: Phase parameters.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Signal object containing the phase, optionally unwrapped.
|
|
135
|
+
"""
|
|
136
|
+
suffix = "unwrap" if p.unwrap else ""
|
|
137
|
+
dst = dst_1_to_1(src, "phase", suffix)
|
|
138
|
+
x, y = src.get_data()
|
|
139
|
+
argument = np.angle(y)
|
|
140
|
+
if p.unwrap:
|
|
141
|
+
argument = np.unwrap(argument)
|
|
142
|
+
if p.unit == AngleUnit.DEGREE:
|
|
143
|
+
argument = np.rad2deg(argument)
|
|
144
|
+
dst.set_xydata(x, argument, src.dx, None)
|
|
145
|
+
dst.yunit = p.unit
|
|
146
|
+
restore_data_outside_roi(dst, src)
|
|
147
|
+
return dst
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@computation_function()
|
|
151
|
+
def complex_from_real_imag(src1: SignalObj, src2: SignalObj) -> SignalObj:
|
|
152
|
+
"""Combine two real signals into a complex signal using real + i * imag.
|
|
153
|
+
|
|
154
|
+
.. warning::
|
|
155
|
+
|
|
156
|
+
The x coordinates of the two signals must be the same.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
src1: Real part signal.
|
|
160
|
+
src2: Imaginary part signal.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
Result signal object with complex-valued y.
|
|
164
|
+
"""
|
|
165
|
+
if not np.array_equal(src1.x, src2.x):
|
|
166
|
+
warnings.warn(
|
|
167
|
+
"The x coordinates of the two signals are not the same. "
|
|
168
|
+
"Results may be incorrect."
|
|
169
|
+
)
|
|
170
|
+
dst = dst_2_to_1(src1, src2, "real_imag")
|
|
171
|
+
y = src1.y + 1j * src2.y
|
|
172
|
+
dst.set_xydata(src1.x, y, src1.dx, None)
|
|
173
|
+
return dst
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@computation_function()
|
|
177
|
+
def complex_from_magnitude_phase(
|
|
178
|
+
src1: SignalObj, src2: SignalObj, p: AngleUnitParam
|
|
179
|
+
) -> SignalObj:
|
|
180
|
+
"""Combine magnitude and phase signals into a complex signal.
|
|
181
|
+
|
|
182
|
+
.. warning::
|
|
183
|
+
|
|
184
|
+
The x coordinates of the two signals must be the same.
|
|
185
|
+
|
|
186
|
+
.. warning::
|
|
187
|
+
|
|
188
|
+
Negative values are not allowed for the radius and will be clipped to 0.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
src1: Magnitude (module) signal.
|
|
192
|
+
src2: Phase (argument) signal.
|
|
193
|
+
p: Parameters (must provide unit for the phase).
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
Result signal object with complex-valued y.
|
|
197
|
+
"""
|
|
198
|
+
if not np.array_equal(src1.x, src2.x):
|
|
199
|
+
warnings.warn(
|
|
200
|
+
"The x coordinates of the two signals are not the same. "
|
|
201
|
+
"Results may be incorrect."
|
|
202
|
+
)
|
|
203
|
+
if np.any(src1.y < 0.0):
|
|
204
|
+
warnings.warn("Negative radius values are not allowed. They will be set to 0.")
|
|
205
|
+
src1.y = np.maximum(src1.y, 0.0)
|
|
206
|
+
dst = dst_2_to_1(src1, src2, "mag_phase")
|
|
207
|
+
assert p.unit is not None
|
|
208
|
+
y = coordinates.polar_to_complex(src1.y, src2.y, unit=p.unit)
|
|
209
|
+
dst.set_xydata(src1.x, y, src1.x, None)
|
|
210
|
+
return dst
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class DataTypeSParam(gds.DataSet, title=_("Convert data type")):
|
|
214
|
+
"""Convert signal data type parameters"""
|
|
215
|
+
|
|
216
|
+
dtype_str = gds.ChoiceItem(
|
|
217
|
+
_("Destination data type"),
|
|
218
|
+
list(zip(SignalObj.get_valid_dtypenames(), SignalObj.get_valid_dtypenames())),
|
|
219
|
+
help=_("Output image data type."),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@computation_function()
|
|
224
|
+
def astype(src: SignalObj, p: DataTypeSParam) -> SignalObj:
|
|
225
|
+
"""Convert data type with :py:func:`numpy.astype`
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
src: source signal
|
|
229
|
+
p: parameters
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Result signal object
|
|
233
|
+
"""
|
|
234
|
+
dst = dst_1_to_1(src, "astype", f"dtype={p.dtype_str}")
|
|
235
|
+
dst.xydata = src.xydata.astype(p.dtype_str)
|
|
236
|
+
return dst
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@computation_function()
|
|
240
|
+
def log10(src: SignalObj) -> SignalObj:
|
|
241
|
+
"""Compute Log10 with :py:data:`numpy.log10`
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
src: source signal
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Result signal object
|
|
248
|
+
"""
|
|
249
|
+
dst = dst_1_to_1(src, "log10")
|
|
250
|
+
x, y = src.get_data()
|
|
251
|
+
|
|
252
|
+
# Compute result
|
|
253
|
+
result_y = np.log10(y)
|
|
254
|
+
dst.set_xydata(x, result_y, src.dx, src.dy)
|
|
255
|
+
|
|
256
|
+
# Uncertainty propagation: σ(log₁₀(y)) = σ(y) / (y * ln(10))
|
|
257
|
+
if is_uncertainty_data_available(src):
|
|
258
|
+
with warnings.catch_warnings():
|
|
259
|
+
warnings.simplefilter("ignore", category=RuntimeWarning)
|
|
260
|
+
dst.dy = src.dy / (y * np.log(10))
|
|
261
|
+
dst.dy[np.isinf(dst.dy) | np.isnan(dst.dy)] = np.nan
|
|
262
|
+
|
|
263
|
+
restore_data_outside_roi(dst, src)
|
|
264
|
+
return dst
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@computation_function()
|
|
268
|
+
def exp(src: SignalObj) -> SignalObj:
|
|
269
|
+
"""Compute exponential with :py:data:`numpy.exp`
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
src: source signal
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
Result signal object
|
|
276
|
+
"""
|
|
277
|
+
dst = dst_1_to_1(src, "exp")
|
|
278
|
+
x, y = src.get_data()
|
|
279
|
+
|
|
280
|
+
# Compute result
|
|
281
|
+
result_y = np.exp(y)
|
|
282
|
+
dst.set_xydata(x, result_y, src.dx, src.dy)
|
|
283
|
+
|
|
284
|
+
# Uncertainty propagation: σ(eʸ) = eʸ * σ(y)
|
|
285
|
+
if is_uncertainty_data_available(src):
|
|
286
|
+
dst.dy = np.abs(result_y) * src.dy
|
|
287
|
+
|
|
288
|
+
restore_data_outside_roi(dst, src)
|
|
289
|
+
return dst
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
@computation_function()
|
|
293
|
+
def sqrt(src: SignalObj) -> SignalObj:
|
|
294
|
+
"""Compute square root with :py:data:`numpy.sqrt`
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
src: source signal
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
Result signal object
|
|
301
|
+
"""
|
|
302
|
+
dst = dst_1_to_1(src, "sqrt")
|
|
303
|
+
x, y = src.get_data()
|
|
304
|
+
|
|
305
|
+
# Compute result
|
|
306
|
+
result_y = np.sqrt(y)
|
|
307
|
+
dst.set_xydata(x, result_y, src.dx, src.dy)
|
|
308
|
+
|
|
309
|
+
# Uncertainty propagation: σ(√y) = σ(y) / (2√y)
|
|
310
|
+
if is_uncertainty_data_available(src):
|
|
311
|
+
with warnings.catch_warnings():
|
|
312
|
+
warnings.simplefilter("ignore", category=RuntimeWarning)
|
|
313
|
+
dst.dy = src.dy / (2 * np.sqrt(y))
|
|
314
|
+
dst.dy[np.isinf(dst.dy) | np.isnan(dst.dy)] = np.nan
|
|
315
|
+
|
|
316
|
+
restore_data_outside_roi(dst, src)
|
|
317
|
+
return dst
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class PowerParam(gds.DataSet, title=_("Power")):
|
|
321
|
+
"""Power parameters"""
|
|
322
|
+
|
|
323
|
+
power = gds.FloatItem(_("Power"), default=2.0)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
@computation_function()
|
|
327
|
+
def power(src: SignalObj, p: PowerParam) -> SignalObj:
|
|
328
|
+
"""Compute power with :py:data:`numpy.power`
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
src: source signal
|
|
332
|
+
p: parameters
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
Result signal object
|
|
336
|
+
"""
|
|
337
|
+
dst = dst_1_to_1(src, "^", str(p.power))
|
|
338
|
+
dst.y = np.power(src.y, p.power)
|
|
339
|
+
|
|
340
|
+
# Uncertainty propagation: σ(y^n) = |n * y^(n-1)| * σ(y)
|
|
341
|
+
if is_uncertainty_data_available(src):
|
|
342
|
+
with warnings.catch_warnings():
|
|
343
|
+
warnings.simplefilter("ignore", category=RuntimeWarning)
|
|
344
|
+
dst.dy *= np.abs(p.power * np.power(src.y, p.power - 1))
|
|
345
|
+
dst.dy[np.isinf(dst.dy) | np.isnan(dst.dy)] = np.nan
|
|
346
|
+
|
|
347
|
+
restore_data_outside_roi(dst, src)
|
|
348
|
+
return dst
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
@computation_function()
|
|
352
|
+
def to_polar(src: SignalObj, p: AngleUnitParam) -> SignalObj:
|
|
353
|
+
"""Convert Cartesian coordinates to polar coordinates.
|
|
354
|
+
|
|
355
|
+
This function converts the x and y coordinates of a signal to polar coordinates
|
|
356
|
+
using :py:func:`sigima.tools.coordinates.to_polar`.
|
|
357
|
+
|
|
358
|
+
.. warning::
|
|
359
|
+
|
|
360
|
+
X and y must share the same units for the computation to make sense.
|
|
361
|
+
|
|
362
|
+
Args:
|
|
363
|
+
src: Source signal.
|
|
364
|
+
p: Parameters.
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
Result signal object.
|
|
368
|
+
|
|
369
|
+
Raises:
|
|
370
|
+
ValueError: If the x and y units are not the same.
|
|
371
|
+
"""
|
|
372
|
+
assert p.unit is not None
|
|
373
|
+
if src.xunit != src.yunit:
|
|
374
|
+
warnings.warn(
|
|
375
|
+
f"X and y units are not the same: {src.xunit} != {src.yunit}. "
|
|
376
|
+
"Results will be incorrect."
|
|
377
|
+
)
|
|
378
|
+
dst = dst_1_to_1(src, "Polar coordinates", f"unit={p.unit}")
|
|
379
|
+
x, y = src.get_data()
|
|
380
|
+
r, theta = coordinates.to_polar(x, y, p.unit)
|
|
381
|
+
dst.set_xydata(r, theta)
|
|
382
|
+
dst.xlabel = _("Radius")
|
|
383
|
+
dst.ylabel = _("Angle")
|
|
384
|
+
dst.yunit = p.unit
|
|
385
|
+
return dst
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
@computation_function()
|
|
389
|
+
def to_cartesian(src: SignalObj, p: AngleUnitParam) -> SignalObj:
|
|
390
|
+
"""Convert polar coordinates to Cartesian coordinates.
|
|
391
|
+
|
|
392
|
+
This function converts the r and theta coordinates of a signal to Cartesian
|
|
393
|
+
coordinates using :py:func:`sigima.tools.coordinates.to_cartesian`.
|
|
394
|
+
|
|
395
|
+
.. note::
|
|
396
|
+
|
|
397
|
+
It is assumed that the x-axis represents the radius and the y-axis the angle.
|
|
398
|
+
|
|
399
|
+
.. warning::
|
|
400
|
+
|
|
401
|
+
Negative values are not allowed for the radius and will be clipped to 0.
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
src: Source signal.
|
|
405
|
+
p: Parameters.
|
|
406
|
+
|
|
407
|
+
Returns:
|
|
408
|
+
Result signal object.
|
|
409
|
+
"""
|
|
410
|
+
dst = dst_1_to_1(src, "Cartesian coordinates", f"unit={p.unit}")
|
|
411
|
+
r, theta = src.get_data()
|
|
412
|
+
if np.any(r < 0.0):
|
|
413
|
+
warnings.warn("Negative radius values are not allowed. They will be set to 0.")
|
|
414
|
+
r = np.maximum(r, 0.0)
|
|
415
|
+
x, y = coordinates.to_cartesian(r, theta, p.unit)
|
|
416
|
+
dst.set_xydata(x, y)
|
|
417
|
+
dst.xlabel = _("x")
|
|
418
|
+
dst.ylabel = _("y")
|
|
419
|
+
dst.yunit = src.xunit
|
|
420
|
+
return dst
|