Separating two interleaved arrays into continuous sequences

Solution 1:

I'm sure there are many adjustments to be made to improve performance, but here's my guess, based on second derivative thresholding:

# first derivative
deriv = np.diff(fun_c)
# second derivative
deriv2 = np.diff(deriv)
# adjust threshold to detect discontinuities
switch_points = deriv2 > 0.0002
# indices of points of intersection
touch_index = np.where(switch_points == True)[0]
# adjustment to prevent false positives
# (sometimes contigous samples like 127,128 are both detected)
duplicate_index = np.where(np.diff(touch_index) == 1)[0]
touch_index = np.delete(touch_index, duplicate_index)
# begin and ending points of sections to swap
begins = touch_index[::2]
ends = touch_index[1::2]

from itertools import zip_longest

# swap values in selected sections
tmp = fun_c.copy() # need a tmp array to swap
for begin, end in zip_longest(begins, ends, fillvalue=len(fun_c)):
    tmp[begin:end] = fun_d[begin:end]

# complete swapping, correcting fun_d
# on the indices we changed before
swapped = tmp != fun_c
fun_d[swapped] = fun_c[swapped]
fun_c = tmp

plt.plot(xs, fun_c)
plt.plot(xs, fun_d)

separated sin functions

I found it quite dependant on the sampling_rate (might fail if it is too low).

Edit: If it wasn't for the

touch_index = np.delete(touch_index, duplicate_index)

you could entirely skip all this:

begins = touch_index[::2]
ends = touch_index[1::2]
from itertools import zip_longest
# swap values in selected sections
tmp = fun_c.copy() # need a tmp array to swap
for begin, end in zip_longest(begins, ends, fillvalue=len(fun_c)):
    tmp[begin:end] = fun_d[begin:end]

with just

np.logical_xor.accumulate(touch_index) | touch_index