You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
3.1 KiB
96 lines
3.1 KiB
2 years ago
|
from __future__ import print_function
|
||
|
from scipy import interpolate
|
||
|
import numpy as np
|
||
|
|
||
|
|
||
|
def find_point(x, y, peakindex, val, direction="left", limits=None):
|
||
|
"""
|
||
|
Given a waveform defined by *x* and *y* arrays, return the first time
|
||
|
at which the waveform crosses (y[peakindex] * val). The search begins at
|
||
|
*peakindex* and proceeds in *direction*.
|
||
|
|
||
|
Optionally, *limits* may specify a smaller search region in the form of
|
||
|
(t0, t1, dt).
|
||
|
"""
|
||
|
# F = interpolate.UnivariateSpline(x, y, s=0) # declare function
|
||
|
# To find x at y then do:
|
||
|
istart = 0
|
||
|
iend = len(y)
|
||
|
if limits is not None:
|
||
|
istart = int(limits[0] / limits[2])
|
||
|
iend = int(limits[1] / limits[2])
|
||
|
yToFind = y[peakindex] * val
|
||
|
if direction == "left":
|
||
|
yreduced = np.array(y[istart:peakindex]) - yToFind
|
||
|
try:
|
||
|
Fr = interpolate.UnivariateSpline(x[istart:peakindex], yreduced, s=0)
|
||
|
except:
|
||
|
print("find_point: insufficient time points for analysis")
|
||
|
print("arg lengths:", len(x[istart:peakindex]), len(yreduced))
|
||
|
print("istart, peakindex: ", istart, peakindex)
|
||
|
print("ytofine: ", yToFind)
|
||
|
raise
|
||
|
res = float("nan")
|
||
|
return res
|
||
|
res = Fr.roots()
|
||
|
if len(res) > 1:
|
||
|
res = res[-1]
|
||
|
else:
|
||
|
yreduced = np.array(y[peakindex:iend]) - yToFind
|
||
|
try:
|
||
|
Fr = interpolate.UnivariateSpline(x[peakindex:iend], yreduced, s=0)
|
||
|
except:
|
||
|
print("find_point: insufficient time points for analysis?")
|
||
|
print("arg lengths:", len(x[peakindex:iend]), len(yreduced))
|
||
|
raise
|
||
|
res = float("nan")
|
||
|
return res
|
||
|
res = Fr.roots()
|
||
|
if len(res) > 1:
|
||
|
res = res[0]
|
||
|
# pdb.set_trace()
|
||
|
try:
|
||
|
res.pop()
|
||
|
except:
|
||
|
pass
|
||
|
if not res: # tricky - an empty list is False, but does not evaluate to False
|
||
|
res = float("nan") # replace with a NaN
|
||
|
else:
|
||
|
res = float(res) # make sure is just a simple number (no arrays)
|
||
|
return res
|
||
|
|
||
|
|
||
|
def find_crossing(data, start=0, direction=1, threshold=0):
|
||
|
"""Return the index at which *data* crosses *threshold*, starting
|
||
|
at index *start* and proceeding in *direction* (+/-1).
|
||
|
|
||
|
The value returned is a float indicating the interpolated index
|
||
|
position where the data crosses threshold, or NaN if the threshold was
|
||
|
never crossed.
|
||
|
"""
|
||
|
|
||
|
# Note: this function is very similar in purpose to find_point, but was
|
||
|
# added due to issues with interpolate.UnivariateSpline
|
||
|
|
||
|
assert direction in (1, -1)
|
||
|
cross_rising = data[start] < threshold
|
||
|
|
||
|
def test(x):
|
||
|
if cross_rising:
|
||
|
return x > threshold
|
||
|
else:
|
||
|
return x < threshold
|
||
|
|
||
|
while True:
|
||
|
next_ind = start + direction
|
||
|
if next_ind < 0 or next_ind >= len(data):
|
||
|
return np.nan
|
||
|
|
||
|
if test(data[next_ind]):
|
||
|
# crossed; return interpolated value
|
||
|
s1 = data[next_ind] - threshold
|
||
|
s2 = threshold = data[start]
|
||
|
return (next_ind * s2 + start * s1) / (s2 + s1)
|
||
|
|
||
|
start = next_ind
|