The piecewise linear function from Fit piecewise-linear fn to I-B v4 shows artifacts on low and high currents. At low fields it is not a good fit due field measurement uncertainties from drift.

We smooth the calibration function first using a wiki:Savitzky–Golay filter, and then smooth out the edge points by extrapolation using an univariate spline
discrete_fn_v5 = DiscreteFunctionTransform(discrete_fn.xs.copy(), discrete_fn.ys.copy())
lower_thres = 400 # A
upper_thres = 5700 # A
ys_v5 = discrete_fn_v5.ys
ys_v5 = scipy.signal.savgol_filter(ys_v5, 11, 1)
weights = np.ones_like(discrete_fn_v5.xs)
weights[discrete_fn_v5.xs < lower_thres] = 0.1
weights[discrete_fn_v5.xs >= upper_thres] = 0.01
weights[-3:] = 2.
points = (discrete_fn_v5.xs >= lower_thres) & (discrete_fn_v5.xs < upper_thres)
points[-3:] = True
weights = weights[points]
spline = scipy.interpolate.InterpolatedUnivariateSpline(
discrete_fn_v5.xs[points],
ys_v5[points],
# bbox=[lower_thres, upper_thres],
w=weights,
k=3,
ext=0,
# s=.5
)
# discrete_fn_v5.ys = spline(discrete_fn_v5.xs)
discrete_fn_v5.ys = ys_v5
discrete_fn_v5.ys[discrete_fn_v5.xs < lower_thres] = spline(discrete_fn_v5.xs[discrete_fn_v5.xs < lower_thres])
discrete_fn_v5.ys[discrete_fn_v5.xs >= upper_thres] = spline(discrete_fn_v5.xs[discrete_fn_v5.xs >= upper_thres])The difference between the old and new calibration is shown below. The largest changes can be seen at the lower and upper ends, but also between 4000 and 5000 A there is a lag in the slope because of the savgol filter.

The new fit using a 3rd order univariate spline fits well on the lower end and the upper end, specifically at >5800 A.


There is a horizontal shift at flat bottom (sub 300 A) and flat top (>5600 A) to to the straightened out calibration function.
The new piecewise linear functions are written to