How can I detect flipping in a time series?

Viewed 135

For a system that operates on different operational modes, I want to reduce the flipping between modes. For this the detection of flipping and the correction is needed.

Let's assume we have a sequence where modes switch frequently:

before = [0,0,0,(1,0),1,1,1,2,2,(1,2),1,1,1,(0,1),0]   # parenthesis indicate flipping

I would like to kind of swap only at (changing points) to get :

after  = [0,0,0,(0,1),1,1,1,2,2,(2,1),1,1,1,(1,0),0]   # parenthesis indicate corrections

How can I achieve that?

2 Answers

There is a 'simpler' way to find flippings of range 1, but doesn't work for consecutive repeated flips

before = np.array([0,0,1,0,0,1,0,1,1,1,2,2,1,2,1,1,1,0,1,0,0])
goal = np.array(  [0,0,0,0,0,0,1,1,1,1,2,2,2,1,1,1,1,1,0,0,0])

diff = np.diff(before)          # find 'jumps' with range 1
diff[:-1][(diff == 0)[1:]] = 0  # correct 'right' side of 'jumps'
after = before - np.r_[0,diff]  # correct flipping

plt.plot(before, linestyle='--',label='before')
plt.plot(goal,   linestyle='-.',label='goal')
plt.plot(after,  linestyle=':', label='after')
plt.legend();

Output

smothed signal

Works with bigger steps and negative 'jumps'

before = np.array([0,0,-1,0,0,1,0,1,1,1,4,4,1,4,1,1,1,0,1,0,0])
goal = np.array(  [0,0, 0,0,0,0,1,1,1,1,4,4,4,1,1,1,1,1,0,0,0])

diff = np.diff(before)          # find flipping with range 1
diff[:-1][(diff == 0)[1:]] = 0  # correct 'right' side of signal
after = before - np.r_[0,diff]  # correct flipping

plt.plot(before, linestyle='--',label='before')
plt.plot(goal,   linestyle='-.',label='goal')
plt.plot(after,  linestyle=':', label='after')
plt.legend();

Output

with bigger steps


Limits of the solution

  • Consecutive repeated flips
    before = [0,1,0,1,0,1,1,1,1]
    goal   = [0,0,0,0,1,1,1,1,1]

wrong result

I solved the issue by developing a small convolution filter for flipping detection. So far it can detect a single flip (on-off-on or off-on-off)

building the differential signal allows to support different single swaps even between more than 2 operational modes.

import numpy as np
import matplotlib.pyplot as plt

before = np.array([0,0,1,0,0,1,0,1,1,1,2,2,1,2,1,1,1,0,1,0,0])
goal = np.array(  [0,0,0,0,0,0,1,1,1,1,2,2,2,1,1,1,1,1,0,0,0])
after  = before.copy()
fltr = np.array([1,2,5,10])        # convolution filter

for i in range(0,len(before)-4):
    dif = np.diff(after)
    conv = (fltr*dif[i:i+4]).sum() # conv-filter applied on diff()
    if abs(conv) == 3:       # 00100 = 00000 or 11011 = 11111
        after[i+2] = after[i+1]  
    if abs(conv) == 7:
        b = after[i+2]       # 00101 = 00011 or 11010 = 11100
        after[i+2] = after[i+3]
        after[i+3] = b

plt.plot(before, linestyle='--',label='before')
plt.plot(goal,   linestyle='-.',label='goal')
plt.plot(after,  linestyle=':', label='after')

plt.legend()
plt.show

Note: maybe this solution is incomplete and does not cover all possible scenarios. Please recommend more advanced / alternative solutions.

Related