Skip to content
Snippets Groups Projects
Commit 42b9876c authored by Laurent Mercadier's avatar Laurent Mercadier Committed by Cammille Carinan
Browse files

Add generic fit function, generalize prepare_arrays()

parent 3c4d3669
No related branches found
No related tags found
No related merge requests found
...@@ -8,7 +8,7 @@ def knife_edge(positions, intensities, axisRange=None, p0=None): ...@@ -8,7 +8,7 @@ def knife_edge(positions, intensities, axisRange=None, p0=None):
axisRange=axisRange, p0=p0) axisRange=axisRange, p0=p0)
width, std = 0, 0 width, std = 0, 0
if popt is not None and pcov is not None: if popt is not None and pcov is not None:
width, std = popt[1], pcov[1, 1]**0.5 width, std = np.abs(popt[1]), pcov[1, 1]**0.5
return width, std return width, std
...@@ -17,40 +17,58 @@ def knife_edge_base(positions, intensities, axisRange=None, p0=None): ...@@ -17,40 +17,58 @@ def knife_edge_base(positions, intensities, axisRange=None, p0=None):
""" """
# Prepare arrays # Prepare arrays
positions, intensities = prepare_arrays(positions, intensities, axisRange) positions, intensities = prepare_arrays(positions, intensities,
xRange=axisRange)
# Estimate initial fitting params # Estimate initial fitting params
if p0 is None: if p0 is None:
p0 = [np.mean(positions), 0.1, np.max(intensities) / 2, 0] p0 = [np.mean(positions), 0.1, np.max(intensities) / 2, 0]
# Fit
popt, pcov = function_fit(erfc, positions, intensities, p0=p0)
return popt, pcov
def function_fit(func, x, y, **kwargs):
"""A wrapper for scipy.optimize curve_fit()
"""
# Fit # Fit
try: try:
popt, pcov = curve_fit(erfc, positions, intensities, p0=p0) popt, pcov = curve_fit(func, x, y, **kwargs)
except (TypeError, RuntimeError): except (TypeError, RuntimeError) as err:
print("Fit did not converge.") print("Fit did not converge:", err)
popt, pcov = (None, None) popt, pcov = (None, None)
return popt, pcov return popt, pcov
def prepare_arrays(positions: np.ndarray, intensities: np.ndarray, def prepare_arrays(arrX: np.ndarray, arrY: np.ndarray,
axisRange=None): xRange=None, yRange=None):
# Slice
if axisRange is not None:
slice_ = range_mask(positions, *axisRange)
positions = positions[slice_]
intensities = intensities[slice_]
# Convert both arrays to 1D of the same size # Convert both arrays to 1D of the same size
intensities = intensities.flatten() assert arrX.shape[0] == arrY.shape[0]
positions = np.repeat(positions, len(intensities) // len(positions)) arrX = arrX.flatten()
assert positions.shape == intensities.shape arrY = arrY.flatten()
if len(arrX) > len(arrY):
arrY = np.repeat(arrY, len(arrX) // len(arrY))
else:
arrX = np.repeat(arrX, len(arrY) // len(arrX))
# Select ranges
if xRange is not None:
mask_ = range_mask(arrX, *xRange)
arrX = arrX[mask_]
arrY = arrY[mask_]
if yRange is not None:
mask_ = range_mask(arrY, *yRange)
arrX = arrX[mask_]
arrY = arrY[mask_]
# Clean both arrays by only getting finite values # Clean both arrays by only getting finite values
finite_idx = np.isfinite(positions) & np.isfinite(intensities) finite_idx = np.isfinite(arrX) & np.isfinite(arrY)
positions = positions[finite_idx] arrX = arrX[finite_idx]
intensities = intensities[finite_idx] arrY = arrY[finite_idx]
return positions, intensities return arrX, arrY
def range_mask(array, minimum=None, maximum=None): def range_mask(array, minimum=None, maximum=None):
...@@ -69,10 +87,5 @@ def range_mask(array, minimum=None, maximum=None): ...@@ -69,10 +87,5 @@ def range_mask(array, minimum=None, maximum=None):
return min_slice & max_slice return min_slice & max_slice
def covariance(a: np.ndarray, b: np.ndarray):
assert a.ndim == b.ndim == 1
return np.cov(a, b)[0][1]
def erfc(x, x0, w0, a, b): def erfc(x, x0, w0, a, b):
return a * special.erfc(np.sqrt(2) * (x - x0) / w0) + b return a * special.erfc(np.sqrt(2) * (x - x0) / w0) + b
...@@ -86,9 +86,9 @@ def test_prepare_arrays_size(): ...@@ -86,9 +86,9 @@ def test_prepare_arrays_size():
assert intensities.shape == (size,) assert intensities.shape == (size,)
# Test finite motor and 1D signals # Test finite motor and 1D signals
positions, intensities = prepare_arrays(motor, signal.reshape(1, -1)) positions, intensities = prepare_arrays(motor, signal[:, 0])
assert positions.shape == (size,) assert positions.shape == (trains,)
assert intensities.shape == (size,) assert intensities.shape == (trains,)
def test_knife_edge_base(): def test_knife_edge_base():
...@@ -96,14 +96,14 @@ def test_knife_edge_base(): ...@@ -96,14 +96,14 @@ def test_knife_edge_base():
x = np.linspace(-3, 3) x = np.linspace(-3, 3)
y = erfc(x, *p0) y = erfc(x, *p0)
noise = y * np.random.normal(0, .02, y.shape) # 2% error noise = y * np.random.normal(0, .02, y.shape) # 2% error
eff_y = (y + noise).reshape(1, -1) eff_y = y + noise
# Test noisy data # Test noisy data
popt, _ = knife_edge_base(x, eff_y) popt, _ = knife_edge_base(x, eff_y)
np.testing.assert_allclose(p0, popt, atol=1e-1) np.testing.assert_allclose(p0, popt, atol=1e-1)
# Test flipped data # Test flipped data
popt, _ = knife_edge_base(x, eff_y[:, ::-1]) popt, _ = knife_edge_base(x, eff_y[::-1])
p0[1] = abs(p0[1]) # Absolute value when flipped p0[1] = abs(p0[1]) # Absolute value when flipped
np.testing.assert_allclose(p0, popt, atol=1e-1) np.testing.assert_allclose(p0, popt, atol=1e-1)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment