@@ -426,31 +426,44 @@ def zero_crossings(y, x=None, direction=None, bouncingZero=False):
426
426
# --------------------------------------------------------------------------------}
427
427
# --- Correlation
428
428
# --------------------------------------------------------------------------------{
429
- def autoCorrCoeff (x , nMax = None ):
430
- if nMax is None :
431
- nMax = len (x )
432
- return np .array ([1 ]+ [np .corrcoef (x [:- i ], x [i :])[0 ,1 ] for i in range (1 , nMax )])
433
-
434
- def correlation (x , nMax = 80 , dt = 1 , method = 'numpy' ):
429
+ def autoCorrCoeff (x , nMax = None , dt = 1 , method = 'corrcoef' ):
435
430
"""
436
431
Compute auto correlation of a signal
432
+ - nMax: number of values to return
437
433
"""
438
- nvec = np .arange (0 ,nMax )
434
+ x = x .copy () - np .mean (x )
435
+ var = np .var (x )
436
+ n = len (x )
437
+ if nMax is None :
438
+ nMax = n
439
+ rvec = np .arange (0 ,nMax )
439
440
if method == 'manual' :
440
- sigma2 = np .var (x )
441
- R = np .zeros (nMax )
442
- R [0 ] = 1
443
- for i ,nDelay in enumerate (nvec [1 :]):
444
- R [i + 1 ] = np .mean ( x [0 :- nDelay ] * x [nDelay :] ) / sigma2
445
- #R[i+1] = np.corrcoef(x[:-nDelay], x[nDelay:])[0,1]
446
-
447
- elif method == 'numpy' :
448
- R = autoCorrCoeff (x , nMax = nMax )
441
+ rho = np .zeros (nMax )
442
+ rho [0 ] = 1
443
+ for i ,nDelay in enumerate (rvec [1 :]):
444
+ rho [i + 1 ] = np .mean ( x [0 :- nDelay ] * x [nDelay :] ) / var
445
+
446
+ elif method == 'manual-roll' :
447
+ rho = np .zeros (len (rvec ))
448
+ for i ,r in enumerate (rvec ):
449
+ shifted_x = np .roll (x , int (r )) #Shift x by tau
450
+ rho [i ] = np .mean (x * shifted_x ) / var
451
+
452
+ elif method == 'corrcoef' :
453
+ rho = np .array ([1 ]+ [np .corrcoef (x [:- i ], x [i :])[0 ,1 ] for i in range (1 , nMax )])
454
+
455
+ elif method == 'correlate' :
456
+ rho = np .correlate (x , x , mode = 'full' )[- n :] / (var * n )
457
+ rho = rho [:nMax ]
449
458
else :
450
- raise NotImplementedError ()
459
+ raise NotImplementedError (method )
451
460
452
- tau = nvec * dt
453
- return R , tau
461
+ tau = rvec * dt
462
+ return rho , tau
463
+
464
+ def correlation (* args , ** kwargs ):
465
+ print ('[WARN] welib.tools.signal_analysis.correlation will be deprecated use autoCorrCoeff' )
466
+ return autoCorrCoeff (* args , ** kwargs )
454
467
# Auto-correlation comes in two versions: statistical and convolution. They both do the same, except for a little detail: The statistical version is normalized to be on the interval [-1,1]. Here is an example of how you do the statistical one:
455
468
#
456
469
#
@@ -459,48 +472,56 @@ def correlation(x, nMax=80, dt=1, method='numpy'):
459
472
# return result[result.size/2:]
460
473
461
474
462
- def xCorrCoeff (x , y , dt = None , mode = 'same' , return_lags = False , method = 'numpy ' ):
475
+ def xCorrCoeff (x1 , x2 , t = None , nMax = None , method = 'manual ' ):
463
476
"""
464
- Compute and plot the cross-correlation coefficient between two signals.
465
-
466
- Parameters:
467
- - x: array-like, first signal values
468
- - y: array-like, second signal values
477
+ Compute cross-correlation coefficient between two signals.
469
478
"""
470
- from scipy .signal import correlate
471
- # Compute cross-correlation
472
-
473
- sigma1 = np .std (x )
474
- sigma2 = np .std (y )
475
- N = len (x )// 2
476
- N3 = len (x )// 3
477
- if method == 'manual' :
478
- nMax = len (x )
479
- R = np .zeros (nMax )
480
- R [0 ] = 1
481
- nvec = np .arange (0 ,nMax )
482
- for i ,nDelay in enumerate (nvec [1 :]):
483
- R [i + 1 ] = np .mean ( x [0 :- nDelay ] * y [nDelay :] ) / (sigma1 * sigma2 )
484
- #R[i+1] = np.corrcoef(x[:-nDelay], x[nDelay:])[0,1]
485
- cross_corr = R
479
+ x1 = x1 .copy ()- np .mean (x1 )
480
+ x2 = x2 .copy ()- np .mean (x2 )
481
+ sigma1 = np .std (x1 )
482
+ sigma2 = np .std (x2 )
483
+ # Only if x1 and x2 have the same length for now
484
+ N1 = min (len (x1 ), len (x2 ))
485
+ if nMax is None :
486
+ nMax = len (x1 )
487
+ if t is None :
488
+ t = np .array (range (N1 ))
489
+ if method == 'subset-tauPos' :
490
+ # Only if x1 and x2 have the same length
491
+ rho = np .zeros (nMax )
492
+ rvec = np .arange (0 ,nMax )
493
+ for i ,r in enumerate (rvec ):
494
+ rho [i ] = np .mean ( x1 [:N1 - r ] * x2 [r :] ) / (sigma1 * sigma2 )
495
+ elif method == 'manual' :
496
+ rvec = np .array (range (- nMax + 1 ,nMax ))
497
+ rho = np .zeros (len (rvec ))
498
+ # TODO two for loops for pos and neg..
499
+ for i ,r in enumerate (rvec ):
500
+ if r >= 0 :
501
+ t11 , x11 = t [0 :N1 - r ], x1 [0 :N1 - r ]
502
+ t22 , x22 = t [r :] , x2 [r :]
503
+ else :
504
+ r = abs (r )
505
+ t22 , x22 = t [0 :N1 - r ], x2 [0 :N1 - r ]
506
+ t11 , x11 = t [r :] , x1 [r :]
507
+ rho [i ] = np .mean (x11 * x22 ) / (sigma1 * sigma2 )
486
508
else :
509
+ raise NotImplementedError (method )
487
510
cross_corr = correlate (x , y , mode = mode )/ min (len (x ), len (y )) / (sigma1 * sigma2 )
488
511
if mode == 'same' :
489
512
cross_corr = np .concatenate ( [ cross_corr [N :], cross_corr [:N ] ] )
490
513
cross_corr [N3 :2 * N3 ]= 0
491
-
492
- if return_lags :
493
- # --- Compute lags
494
514
if mode == 'full' :
495
515
lags = np .arange (- len (x ) + 1 , len (x )) * dt
496
516
elif mode == 'same' :
497
517
lags = (np .arange (len (x )) - N ) * dt
498
518
lags = np .concatenate ( [ lags [N :], lags [:N ] ] )
499
519
else :
500
520
raise NotImplementedError (mode )
501
- return cross_corr , lags
502
- else :
503
- return cross_corr
521
+
522
+
523
+ tau = rvec * (t [1 ]- t [0 ])
524
+ return rho , tau
504
525
505
526
506
527
def correlated_signal (coeff , n = 1000 , seed = None ):
@@ -522,63 +543,6 @@ def correlated_signal(coeff, n=1000, seed=None):
522
543
return x
523
544
524
545
525
- # --------------------------------------------------------------------------------}
526
- # ---
527
- # --------------------------------------------------------------------------------{
528
- # def crosscorr_2(ts, iy0=None, iz0=None):
529
- # """ Cross correlation along y
530
- # If no index is provided, computed at mid box
531
- # """
532
- # y = ts['y']
533
- # if iy0 is None:
534
- # iy0,iz0 = ts.iMid
535
- # u, v, w = ts._longiline(iy0=iy0, iz0=iz0, removeMean=True)
536
- # rho_uu_y=np.zeros(len(y))
537
- # for iy,_ in enumerate(y):
538
- # ud, vd, wd = ts._longiline(iy0=iy, iz0=iz0, removeMean=True)
539
- # rho_uu_y[iy] = np.mean(u*ud)/(np.std(u)*np.std(ud))
540
- # return y, rho_uu_y
541
- #
542
- # def csd_longi(ts, iy0=None, iz0=None):
543
- # """ Compute cross spectral density
544
- # If no index is provided, computed at mid box
545
- # """
546
- # import scipy.signal as sig
547
- # u, v, w = ts._longiline(iy0=iy0, iz0=iz0, removeMean=True)
548
- # t = ts['t']
549
- # dt = t[1]-t[0]
550
- # fs = 1/dt
551
- # fc, chi_uu = sig.csd(u, u, fs=fs, scaling='density') #nperseg=4096, noverlap=2048, detrend='constant')
552
- # fc, chi_vv = sig.csd(v, v, fs=fs, scaling='density') #nperseg=4096, noverlap=2048, detrend='constant')
553
- # fc, chi_ww = sig.csd(w, w, fs=fs, scaling='density') #nperseg=4096, noverlap=2048, detrend='constant')
554
- # return fc, chi_uu, chi_vv, chi_ww
555
- #
556
- # def coherence_longi(ts, iy0=None, iz0=None):
557
- # """ Coherence on a longitudinal line for different delta y and delta z
558
- # compared to a given point with index iy0,iz0
559
- # """
560
- # try:
561
- # import scipy.signal as sig
562
- # except:
563
- # import pydatview.tools.spectral as sig
564
- # if iy0 is None:
565
- # iy0,iz0 = ts.iMid
566
- # u, v, w = ts._longiline(iy0=iy0, iz0=iz0, removeMean=True)
567
- # y = ts['y']
568
- # z = ts['z']
569
- # diy=1
570
- # dy=y[iy]-y[iy0]
571
- # # TODO
572
- # iy = iy0+diy
573
- # ud, vd, wd = ts._longiline(iy0=iy, iz0=iz0, removeMean=True)
574
- # fc, coh_uu_y1 = sig.coherence(u,ud, fs=fs)
575
-
576
-
577
-
578
-
579
- # --------------------------------------------------------------------------------}
580
- # ---
581
- # --------------------------------------------------------------------------------{
582
546
def find_time_offset (t , f , g , outputAll = False ):
583
547
"""
584
548
Find time offset between two signals (may be negative)
0 commit comments