def getCovMatrix(IQdata, lags=100, hp=False): # 0: <I1I2> # 1: <Q1Q2> # 2: <I1Q2> # 3: <Q1I2> # 4: <Squeezing> Magnitude # 5: <Squeezing> Phase lags = int(lags) I1 = np.asarray(IQdata[0]) Q1 = np.asarray(IQdata[1]) I2 = np.asarray(IQdata[2]) Q2 = np.asarray(IQdata[3]) CovMat = np.zeros([10, lags * 2 + 1]) start = len(I1) - lags - 1 stop = len(I1) + lags sI1 = np.array(I1.shape) shape0 = sI1 * 2 - 1 fshape = [_next_regular(int(d)) for d in shape0] # padding to optimal size for FFTPACK fslice = tuple([slice(0, int(sz)) for sz in shape0]) # Do FFTs and get Cov Matrix fftI1 = rfftn(I1, fshape) fftQ1 = rfftn(Q1, fshape) fftI2 = rfftn(I2, fshape) fftQ2 = rfftn(Q2, fshape) rfftI1 = rfftn(I1[::-1], fshape) # there should be a simple relationship to fftI1 rfftQ1 = rfftn(Q1[::-1], fshape) rfftI2 = rfftn(I2[::-1], fshape) rfftQ2 = rfftn(Q2[::-1], fshape) CovMat[0, :] = irfftn((fftI1 * rfftI2))[fslice].copy()[start:stop] / fshape CovMat[1, :] = irfftn((fftQ1 * rfftQ2))[fslice].copy()[start:stop] / fshape CovMat[2, :] = irfftn((fftI1 * rfftQ2))[fslice].copy()[start:stop] / fshape CovMat[3, :] = irfftn((fftQ1 * rfftI2))[fslice].copy()[start:stop] / fshape psi = (1j * (CovMat[2, :] + CovMat[3, :]) + (CovMat[0, :] - CovMat[1, :])) CovMat[4, :] = abs(psi) CovMat[5, :] = np.angle(psi) CovMat[6, :] = irfftn((fftI1 * rfftI1))[fslice].copy()[start:stop] / fshape CovMat[7, :] = irfftn((fftQ1 * rfftQ1))[fslice].copy()[start:stop] / fshape CovMat[8, :] = irfftn((fftI2 * rfftI2))[fslice].copy()[start:stop] / fshape CovMat[9, :] = irfftn((fftQ2 * rfftQ2))[fslice].copy()[start:stop] / fshape return CovMat
def get_g2(P1, P2, lags=20): ''' Returns the Top part of the G2 equation (<P1P2> - <P1><P2>)''' lags = int(lags) P1 = np.asarray(P1) P2 = np.asarray(P2) # G2 = np.zeros([lags*2-1]) start = len(P1*2-1)-lags stop = len(P1*2-1)-1+lags # assume I1 Q1 have the same shape sP1 = np.array(P1.shape) complex_result = np.issubdtype(P1.dtype, np.complex) shape = sP1 - 1 HPfilt = (int(sP1/(lags*4))) # smallest features visible is lamda/4 # Speed up FFT by padding to optimal size for FFTPACK fshape = [_next_regular(int(d)) for d in shape] fslice = tuple([slice(0, int(sz)) for sz in shape]) # Pre-1.9 NumPy FFT routines are not threadsafe. For older NumPys, make # sure we only call rfftn/irfftn from one thread at a time. if not complex_result and _rfft_lock.acquire(False): try: fftP1 = rfftn(P1, fshape) rfftP2 = rfftn(P2[::-1], fshape) fftP1 = np.concatenate((np.zeros(HPfilt), fftP1[HPfilt:])) rfftP2 = np.concatenate((np.zeros(HPfilt), rfftP2[HPfilt:])) G2 = irfftn((fftP1*rfftP2))[fslice].copy()[start:stop]/len(fftP1) return finally: _rfft_lock.release() else: # If we're here, it's either because we need a complex result, or we # failed to acquire _rfft_lock (meaning rfftn isn't threadsafe and # is already in use by another thread). In either case, use the # (threadsafe but slower) SciPy complex-FFT routines instead. # ret = ifftn(fftn(in1, fshape) * fftn(in2, fshape))[fslice].copy() print 'Abort, reason:complex input or Multithreaded FFT not available' if not complex_result: pass # ret = ret.real P12var = np.var(P1)*np.var(P2) return G2-P12var
def _fftn_14(image, kernel): """ return the fourier transpose of the kernel in same modes as image :param image: :param kernel: :return: """ in1 = signaltools.asarray(image) in2 = signaltools.asarray(kernel) s1 = signaltools.array(in1.shape) s2 = signaltools.array(in2.shape) shape = s1 + s2 - 1 fshape = [signaltools._next_regular(int(d)) for d in shape] kernel_fft = signaltools.rfftn(in2, fshape) return kernel_fft
def getCovMatrix(I1, Q1, I2, Q2, lags=20): # calc <I1I2>, <I1Q2>, Q1I2, Q1Q2 lags = int(lags) I1 = np.asarray(I1) Q1 = np.asarray(Q1) I2 = np.asarray(I2) Q2 = np.asarray(Q2) CovMat = np.zeros([6, lags*2-1]) start = len(I1*2-1)-lags stop = len(I1*2-1)-1+lags sI1 = np.array(I1.shape) sQ2 = np.array(Q2.shape) shape = sI1 + sQ2 - 1 HPfilt = (int(sI1/(lags*4))) # smallest features visible is lamda/4 fshape = [_next_regular(int(d)) for d in shape] # padding to optimal size for FFTPACK fslice = tuple([slice(0, int(sz)) for sz in shape]) # Do FFTs and get Cov Matrix fftI1 = rfftn(I1, fshape) fftQ1 = rfftn(Q1, fshape) fftI2 = rfftn(I2, fshape) fftQ2 = rfftn(Q2, fshape) rfftI1 = rfftn(I1[::-1], fshape) rfftQ1 = rfftn(Q1[::-1], fshape) rfftI2 = rfftn(I2[::-1], fshape) rfftQ2 = rfftn(Q2[::-1], fshape) # filter frequencies outside the lags range fftI1 = np.concatenate((np.zeros(HPfilt), fftI1[HPfilt:])) fftQ1 = np.concatenate((np.zeros(HPfilt), fftQ1[HPfilt:])) fftI2 = np.concatenate((np.zeros(HPfilt), fftI2[HPfilt:])) fftQ2 = np.concatenate((np.zeros(HPfilt), fftQ2[HPfilt:])) # filter frequencies outside the lags range rfftI1 = np.concatenate((np.zeros(HPfilt), rfftI1[HPfilt:])) rfftQ1 = np.concatenate((np.zeros(HPfilt), rfftQ1[HPfilt:])) rfftI2 = np.concatenate((np.zeros(HPfilt), rfftI2[HPfilt:])) rfftQ2 = np.concatenate((np.zeros(HPfilt), rfftQ2[HPfilt:])) CovMat[0, :] = (irfftn((fftI1*rfftI2))[fslice].copy()[start:stop] / len(fftI1)) # 0: <I1I2> CovMat[1, :] = (irfftn((fftQ1*rfftQ2))[fslice].copy()[start:stop] / len(fftI1)) # 1: <Q1Q2> CovMat[2, :] = (irfftn((fftI1*rfftQ2))[fslice].copy()[start:stop] / len(fftI1)) # 2: <I1Q2> CovMat[3, :] = (irfftn((fftQ1*rfftI2))[fslice].copy()[start:stop] / len(fftI1)) # 3: <Q1I2> CovMat[4, :] = (abs(1j*(CovMat[2, :]+CovMat[3, :]) + (CovMat[0, :] - CovMat[1, :]))) # 4: <Squeezing> Magnitude CovMat[5, :] = np.angle(1j*(CovMat[2, :]+CovMat[3, :]) + (CovMat[0, :] - CovMat[1, :])) # 5: <Squeezing> Angle return CovMat
def _fftconvolve_14(in1, in2, int2_fft, mode="same"): """ scipy routine scipy.signal.fftconvolve with kernel already fourier transformed """ in1 = signaltools.asarray(in1) in2 = signaltools.asarray(in2) if in1.ndim == in2.ndim == 0: # scalar inputs return in1 * in2 elif not in1.ndim == in2.ndim: raise ValueError("in1 and in2 should have the same dimensionality") elif in1.size == 0 or in2.size == 0: # empty arrays return signaltools.array([]) s1 = signaltools.array(in1.shape) s2 = signaltools.array(in2.shape) shape = s1 + s2 - 1 # Speed up FFT by padding to optimal size for FFTPACK fshape = [signaltools._next_regular(int(d)) for d in shape] fslice = tuple([slice(0, int(sz)) for sz in shape]) # Pre-1.9 NumPy FFT routines are not threadsafe. For older NumPys, make # sure we only call rfftn/irfftn from one thread at a time. ret = signaltools.irfftn( signaltools.rfftn(in1, fshape) * int2_fft, fshape)[fslice].copy() #np.fft.rfftn(in2, fshape) if mode == "full": return ret elif mode == "same": return signaltools._centered(ret, s1) elif mode == "valid": return signaltools._centered(ret, s1 - s2 + 1) else: raise ValueError("Acceptable mode flags are 'valid'," " 'same', or 'full'.")
def get_covariance_submatrix_full(IQdata, lags): I1 = np.asarray(IQdata[0]) # Q1 = np.asarray(IQdata[1]) # I2 = np.asarray(IQdata[2]) Q2 = np.asarray(IQdata[3]) lags = int(lags) start = len(I1) - lags - 1 stop = len(I1) + lags sub_matrix = np.zeros([16, lags * 2 + 1]) sI1 = np.array(I1.shape) shap0 = sI1*2 - 1 fshape = [_next_regular(int(d)) for d in shap0] # padding to optimal size for FFTPACK fslice = tuple([slice(0, int(sz)) for sz in shap0]) # remove padding later fftIQ = 4*[None] rfftIQ = 4*[None] for i in range(4): fftIQ[i] = rfftn(IQdata[i], fshape) rfftIQ[i] = rfftn(IQdata[i][::-1], fshape) for j in range(4): for i in range(4): idx = i + j*4 sub_matrix[idx] = (irfftn(fftIQ[i]*rfftIQ[j]))[fslice].copy()[start:stop]/len(fftIQ[i]) return sub_matrix
def get_covariance_submatrix(IQdata, lags, q): logging.debug('Calculating Submatrix') I1 = np.asarray(IQdata[0]) Q1 = np.asarray(IQdata[1]) I2 = np.asarray(IQdata[2]) Q2 = np.asarray(IQdata[3]) lags = int(lags) start = len(I1) - lags - 1 stop = len(I1) + lags sub_matrix = np.zeros([4, lags * 2 + 1]) sI1 = np.array(I1.shape) shape0 = sI1*2 - 1 fshape = [_next_regular(int(d)) for d in shape0] # padding to optimal size for FFTPACK fslice = tuple([slice(0, int(sz)) for sz in shape0]) # remove padding later fftI1 = rfftn(I1, fshape)/fshape fftQ1 = rfftn(Q1, fshape)/fshape rfftI2 = rfftn(I2[::-1], fshape)/fshape rfftQ2 = rfftn(Q2[::-1], fshape)/fshape sub_matrix[0] = irfftn((fftI1 * rfftI2))[fslice].copy()[start:stop] # <II> sub_matrix[1] = irfftn((fftI1 * rfftQ2))[fslice].copy()[start:stop] # <IQ> sub_matrix[2] = irfftn((fftQ1 * rfftI2))[fslice].copy()[start:stop] # <QI> sub_matrix[3] = irfftn((fftQ1 * rfftQ2))[fslice].copy()[start:stop] # <QQ> q.put(sub_matrix)
def test_next_regular(self): np.random.seed(1234) def ns(): for j in range(1, 1000): yield j yield 2**5 * 3**5 * 4**5 + 1 for n in ns(): m = signaltools._next_regular(n) msg = "n=%d, m=%d" % (n, m) assert_(m >= n, msg) # check regularity k = m for d in [2, 3, 5]: while True: a, b = divmod(k, d) if b == 0: k = a else: break assert_equal(k, 1, err_msg=msg)
def test_next_regular_strict(self): hams = { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 8, 8: 8, 14: 15, 15: 15, 16: 16, 17: 18, 1021: 1024, 1536: 1536, 51200000: 51200000, 510183360: 510183360, 510183360 + 1: 512000000, 511000000: 512000000, 854296875: 854296875, 854296875 + 1: 859963392, 196608000000: 196608000000, 196608000000 + 1: 196830000000, 8789062500000: 8789062500000, 8789062500000 + 1: 8796093022208, 206391214080000: 206391214080000, 206391214080000 + 1: 206624260800000, 470184984576000: 470184984576000, 470184984576000 + 1: 470715894135000, 7222041363087360: 7222041363087360, 7222041363087360 + 1: 7230196133913600, # power of 5 5**23 11920928955078125: 11920928955078125, 11920928955078125 - 1: 11920928955078125, # power of 3 3**34 16677181699666569: 16677181699666569, 16677181699666569 - 1: 16677181699666569, # power of 2 2**54 18014398509481984: 18014398509481984, 18014398509481984 - 1: 18014398509481984, # above this, int(ceil(n)) == int(ceil(n+1)) 19200000000000000: 19200000000000000, 19200000000000000 + 1: 19221679687500000, 288230376151711744: 288230376151711744, 288230376151711744 + 1: 288325195312500000, 288325195312500000 - 1: 288325195312500000, 288325195312500000: 288325195312500000, 288325195312500000 + 1: 288555831593533440, # power of 3 3**83 3990838394187339929534246675572349035227 - 1: 3990838394187339929534246675572349035227, 3990838394187339929534246675572349035227: 3990838394187339929534246675572349035227, # power of 2 2**135 43556142965880123323311949751266331066368 - 1: 43556142965880123323311949751266331066368, 43556142965880123323311949751266331066368: 43556142965880123323311949751266331066368, # power of 5 5**57 6938893903907228377647697925567626953125 - 1: 6938893903907228377647697925567626953125, 6938893903907228377647697925567626953125: 6938893903907228377647697925567626953125, # http://www.drdobbs.com/228700538 # 2**96 * 3**1 * 5**13 290142196707511001929482240000000000000 - 1: 290142196707511001929482240000000000000, 290142196707511001929482240000000000000: 290142196707511001929482240000000000000, 290142196707511001929482240000000000000 + 1: 290237644800000000000000000000000000000, # 2**36 * 3**69 * 5**7 4479571262811807241115438439905203543080960000000 - 1: 4479571262811807241115438439905203543080960000000, 4479571262811807241115438439905203543080960000000: 4479571262811807241115438439905203543080960000000, 4479571262811807241115438439905203543080960000000 + 1: 4480327901140333639941336854183943340032000000000, # 2**37 * 3**44 * 5**42 30774090693237851027531250000000000000000000000000000000000000 - 1: 30774090693237851027531250000000000000000000000000000000000000, 30774090693237851027531250000000000000000000000000000000000000: 30774090693237851027531250000000000000000000000000000000000000, 30774090693237851027531250000000000000000000000000000000000000 + 1: 30778180617309082445871527002041377406962596539492679680000000, } for x, y in hams.items(): assert_equal(signaltools._next_regular(x), y)
def test_next_regular_strict(self): hams = { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 8, 8: 8, 14: 15, 15: 15, 16: 16, 17: 18, 1021: 1024, 1536: 1536, 51200000: 51200000, 510183360: 510183360, 510183360+1: 512000000, 511000000: 512000000, 854296875: 854296875, 854296875+1: 859963392, 196608000000: 196608000000, 196608000000+1: 196830000000, 8789062500000: 8789062500000, 8789062500000+1: 8796093022208, 206391214080000: 206391214080000, 206391214080000+1: 206624260800000, 470184984576000: 470184984576000, 470184984576000+1: 470715894135000, 7222041363087360: 7222041363087360, 7222041363087360+1: 7230196133913600, # power of 5 5**23 11920928955078125: 11920928955078125, 11920928955078125-1: 11920928955078125, # power of 3 3**34 16677181699666569: 16677181699666569, 16677181699666569-1: 16677181699666569, # power of 2 2**54 18014398509481984: 18014398509481984, 18014398509481984-1: 18014398509481984, # above this, int(ceil(n)) == int(ceil(n+1)) 19200000000000000: 19200000000000000, 19200000000000000+1: 19221679687500000, 288230376151711744: 288230376151711744, 288230376151711744+1: 288325195312500000, 288325195312500000-1: 288325195312500000, 288325195312500000: 288325195312500000, 288325195312500000+1: 288555831593533440, # power of 3 3**83 3990838394187339929534246675572349035227-1: 3990838394187339929534246675572349035227, 3990838394187339929534246675572349035227: 3990838394187339929534246675572349035227, # power of 2 2**135 43556142965880123323311949751266331066368-1: 43556142965880123323311949751266331066368, 43556142965880123323311949751266331066368: 43556142965880123323311949751266331066368, # power of 5 5**57 6938893903907228377647697925567626953125-1: 6938893903907228377647697925567626953125, 6938893903907228377647697925567626953125: 6938893903907228377647697925567626953125, # http://www.drdobbs.com/228700538 # 2**96 * 3**1 * 5**13 290142196707511001929482240000000000000-1: 290142196707511001929482240000000000000, 290142196707511001929482240000000000000: 290142196707511001929482240000000000000, 290142196707511001929482240000000000000+1: 290237644800000000000000000000000000000, # 2**36 * 3**69 * 5**7 4479571262811807241115438439905203543080960000000-1: 4479571262811807241115438439905203543080960000000, 4479571262811807241115438439905203543080960000000: 4479571262811807241115438439905203543080960000000, 4479571262811807241115438439905203543080960000000+1: 4480327901140333639941336854183943340032000000000, # 2**37 * 3**44 * 5**42 30774090693237851027531250000000000000000000000000000000000000-1: 30774090693237851027531250000000000000000000000000000000000000, 30774090693237851027531250000000000000000000000000000000000000: 30774090693237851027531250000000000000000000000000000000000000, 30774090693237851027531250000000000000000000000000000000000000+1: 30778180617309082445871527002041377406962596539492679680000000, } for x, y in hams.items(): assert_equal(signaltools._next_regular(x), y)
def getCovMatrix(I1, Q1, I2, Q2, lags=20): ''' This function was adaped from scipy.signal.fft.convolve. By Defining the number of lags one defines an interrest of region meaning any effect should happen on that oder of time scale; thus lower frequency effects cannot be displayed on that scale and can be discarded from the convolution. All input shapes need to be the same. requires an updated numpy version (1.9.0 +). # 0: <I1I1> # 1: <Q1Q1> # 2: <I2I2> # 3: <Q2Q2> # 4: <I1Q1> # 5: <I2Q2> # 6: <I1I2> # 7: <Q1Q2> # 8: <I1Q2> # 9: <Q1I2> # 10: <Squeezing> Magnitude # 11: <Squeezing> Phase ''' lags = int(lags) I1 = np.asarray(I1) Q1 = np.asarray(Q1) I2 = np.asarray(I2) Q2 = np.asarray(Q2) CovMat = np.zeros([12, lags*2-1]) start = len(I1*2-1)-lags stop = len(I1*2-1)-1+lags # assume I1 Q1 have the same shape sI1 = np.array(I1.shape) sQ2 = np.array(Q2.shape) complex_result = (np.issubdtype(I1.dtype, np.complex) or np.issubdtype(Q2.dtype, np.complex)) shape = sI1 + sQ2 - 1 HPfilt = (int(sI1/(lags*4))) # smallest features visible is lamda/4 # Speed up FFT by padding to optimal size for FFTPACK fshape = [_next_regular(int(d)) for d in shape] fslice = tuple([slice(0, int(sz)) for sz in shape]) # Pre-1.9 NumPy FFT routines are not threadsafe. For older NumPys, make # sure we only call rfftn/irfftn from one thread at a time. if not complex_result and _rfft_lock.acquire(False): try: fftI1 = rfftn(I1, fshape) fftQ1 = rfftn(Q1, fshape) fftI2 = rfftn(I2, fshape) fftQ2 = rfftn(Q2, fshape) rfftI1 = rfftn(I1[::-1], fshape) rfftQ1 = rfftn(Q1[::-1], fshape) rfftI2 = rfftn(I2[::-1], fshape) rfftQ2 = rfftn(Q2[::-1], fshape) # filter frequencies outside the lags range fftI1 = np.concatenate((np.zeros(HPfilt), fftI1[HPfilt:])) fftQ1 = np.concatenate((np.zeros(HPfilt), fftQ1[HPfilt:])) fftI2 = np.concatenate((np.zeros(HPfilt), fftI2[HPfilt:])) fftQ2 = np.concatenate((np.zeros(HPfilt), fftQ2[HPfilt:])) # filter frequencies outside the lags range rfftI1 = np.concatenate((np.zeros(HPfilt), rfftI1[HPfilt:])) rfftQ1 = np.concatenate((np.zeros(HPfilt), rfftQ1[HPfilt:])) rfftI2 = np.concatenate((np.zeros(HPfilt), rfftI2[HPfilt:])) rfftQ2 = np.concatenate((np.zeros(HPfilt), rfftQ2[HPfilt:])) # 0: <I1I1> CovMat[0, :] = (irfftn((fftI1*rfftI1))[fslice].copy()[start:stop] / len(fftI1)) # 1: <Q1Q1> CovMat[1, :] = (irfftn((fftQ1*rfftQ1))[fslice].copy()[start:stop] / len(fftI1)) # 2: <I2I2> CovMat[2, :] = (irfftn((fftI2*rfftI2))[fslice].copy()[start:stop] / len(fftI1)) # 3: <Q2Q2> CovMat[3, :] = (irfftn((fftQ2*rfftQ2))[fslice].copy()[start:stop] / len(fftI1)) # 4: <I1Q1> CovMat[4, :] = (irfftn((fftI1*rfftQ1))[fslice].copy()[start:stop] / len(fftI1)) # 5: <I2Q2> CovMat[5, :] = (irfftn((fftI2*rfftQ2))[fslice].copy()[start:stop] / len(fftI1)) # 6: <I1I2> CovMat[6, :] = (irfftn((fftI1*rfftI2))[fslice].copy()[start:stop] / len(fftI1)) # 7: <Q1Q2> CovMat[7, :] = (irfftn((fftQ1*rfftQ2))[fslice].copy()[start:stop] / len(fftI1)) # 8: <I1Q2> CovMat[8, :] = (irfftn((fftI1*rfftQ2))[fslice].copy()[start:stop] / len(fftI1)) # 9: <Q1I2> CovMat[9, :] = (irfftn((fftQ1*rfftI2))[fslice].copy()[start:stop] / len(fftI1)) # 10: <Squeezing> Magnitude CovMat[10, :] = (abs(1j*(CovMat[8, :]+CovMat[9, :]) + (CovMat[6, :] - CovMat[7, :]))) # 10: <Squeezing> Angle CovMat[11, :] = np.angle(1j*(CovMat[8, :]+CovMat[9, :]) + (CovMat[6, :] - CovMat[7, :])) return CovMat finally: _rfft_lock.release() else: # If we're here, it's either because we need a complex result, or we # failed to acquire _rfft_lock (meaning rfftn isn't threadsafe and # is already in use by another thread). In either case, use the # (threadsafe but slower) SciPy complex-FFT routines instead. # ret = ifftn(fftn(in1, fshape) * fftn(in2, fshape))[fslice].copy() print 'Abort, reason:complex input or Multithreaded FFT not available' if not complex_result: pass # ret = ret.real return CovMat
def detect_swr_hilbert(csc, fs=2000, lowcut=140.0, highcut=250.0, z_thres=3, power_thres=3, merge_thres=0.02, min_length=0.01): """ Finds sharp-wave ripple (SWR) times and indices. Parameters ---------- csc : dict With time(np.array), data(np.array) as keys fs : int Experiment-specific, something in the range of 2000 is not unexpected. lowcut : float The default is set to 140.0 highcut : float The default is set to 250.0 z_thres : int or float The default is set to 5 power_thres : int or float The default is set to 4 merge_thres : int or float The default is set to 0.0 min_length : float Any sequence less than this amount is not considered a sharp-wave ripple. The default is set to 0.02. Returns ------- swr_times : dict With start(float), stop(float) as keys swr_idx : dict With start(int), stop(int) as keys filtered_butter : np.array Mostly for plotting purposes """ n_samples = len(csc['data']) # Filtering signal with butterworth fitler filtered_butter = butter_bandpass(lowcut, highcut, fs, csc['data']) # Get LFP power (using Hilbert) and z-score the power # Zero padding to nearest regular number to speed up fast fourier transforms (FFT) computed in the hilbert function. # Regular numbers are composites of the prime factors 2, 3, and 5. hilbert_n = _next_regular(n_samples) power_lfp = np.abs(signal.hilbert(filtered_butter, N=hilbert_n)) power_lfp = power_lfp[:n_samples] # removing the zero padding now that the power is computed zpower_lfp = stats.zscore(power_lfp) # Finding locations where the power changes detect = zpower_lfp > z_thres detect = np.hstack([0, detect, 0]) # pad to detect first or last element change signal_change = np.diff(detect.astype(int)) start_swr_idx = np.where(signal_change == 1)[0] stop_swr_idx = np.where(signal_change == -1)[0] - 1 # Getting times associated with these power changes start_time = csc['time'][start_swr_idx] stop_time = csc['time'][stop_swr_idx] # Merging ranges that are closer - in time - than the merge_threshold. no_double = start_time[1:] - stop_time[:-1] merge_idx = np.where(no_double < merge_thres)[0] start_merged = np.delete(start_time, merge_idx + 1) stop_merged = np.delete(stop_time, merge_idx) start_merged_idx = np.delete(start_swr_idx, merge_idx + 1) stop_merged_idx = np.delete(stop_swr_idx, merge_idx) # Removing ranges that are shorter - in time - than the min_length value. swr_len = stop_merged - start_merged short_idx = np.where(swr_len < min_length)[0] start_merged = np.delete(start_merged, short_idx) stop_merged = np.delete(stop_merged, short_idx) start_merged_idx = np.delete(start_merged_idx, short_idx) stop_merged_idx = np.delete(stop_merged_idx, short_idx) # Removing ranges that have powers less than the power_threshold if sufficiently different. if power_thres > z_thres: max_z = [] for start_idx, stop_idx in zip(start_merged_idx, stop_merged_idx): max_z.append(np.max(zpower_lfp[start_idx:stop_idx])) max_z = np.array(max_z) z_idx = np.where(max_z < power_thres)[0] start_merged = np.delete(start_merged, z_idx) stop_merged = np.delete(stop_merged, z_idx) start_merged_idx = np.delete(start_merged_idx, z_idx) stop_merged_idx = np.delete(stop_merged_idx, z_idx) swr_idx = dict() swr_times = dict() swr_times['start'] = start_merged swr_times['stop'] = stop_merged swr_idx['start'] = start_merged_idx swr_idx['stop'] = stop_merged_idx print('Number of SWR events found: ', str(len(swr_idx['start']))) return swr_times, swr_idx