def test_psdmod(): TF = 30 # make a 30 second signal spec = [[20, 50], [1, 1]] sig, sr, t = psd.psd2time( spec, ppc=10, fstart=20, fstop=50, df=1 / TF, winends=dict(portion=10), gettime=True, ) # sr = 500 f, p = signal.welch(sig, sr, nperseg=sr) # 1 second windows, df=1 f2, p2 = psd.psdmod(sig, sr, nperseg=sr, timeslice=4, tsoverlap=0.5) f2b, p2b = psd.psdmod(sig, sr, nperseg=sr, timeslice="2000", tsoverlap=0.5) assert np.allclose(f2b, f2) assert np.allclose(p2b, p2) pv = np.logical_and(f2 > 24, f2 < 47) assert np.all(p2[pv] > p[pv]) # mimic standard welch: f3, p3 = psd.psdmod(sig, sr, nperseg=sr, timeslice=30, tsoverlap=0.5) assert np.allclose(p3, p) # mimic maximax: f4, p4 = psd.psdmod(sig, sr, nperseg=sr) assert np.all(p4[pv] > p2[pv]) # test the map output: f5, p5, pmap, t = psd.psdmod(sig, sr, getmap=1) assert np.allclose(p5, np.max(pmap, axis=1)) tshouldbe = np.arange(0.5, 30.0 - 0.25, 0.5) assert np.allclose(t, tshouldbe)
def test_fdepsd_pvelo(): TF = 60 # make a 60 second signal sp = 1.0 spec = np.array([[20, sp], [50, sp]]) sig, sr, t = psd.psd2time( spec, ppc=10, fstart=20, fstop=50, df=1 / TF, winends=dict(portion=10), gettime=True, ) freq = np.arange(30.0, 50.1) q = 25 fde_auto = fdepsd(sig, sr, freq, q, resp="pvelo") fde_no = fdepsd(sig, sr, freq, q, resp="pvelo", parallel="no", verbose=True) b, a = signal.butter(3, 5 / (sr / 2), "high") sig5 = signal.lfilter(b, a, sig) fde_yes = fdepsd(sig5, sr, freq, q, resp="pvelo", parallel="yes", hpfilter=None) compare(fde_auto, fde_no) compare(fde_auto, fde_yes) pv = np.logical_and(freq > 32, freq < 45) assert abs(np.mean(fde_auto.psd.iloc[pv, :2], axis=0) - sp).max() < 0.22 assert abs(np.mean(fde_auto.psd.iloc[pv, 2:], axis=0) - sp).max() < 0.22 assert np.all(fde_auto.freq == freq) # check the damage indicators: flight_over_test = fde_auto.di_sig.loc[freq[0]] / fde_auto.di_test.loc[ freq[0]] var = fde_auto.var[freq[0]] assert abs(1 - flight_over_test["b=4"]**(1 / 2) / var) < 0.1 assert abs(1 - flight_over_test["b=8"]**(1 / 4) / var) < 0.18 assert abs(1 - flight_over_test["b=12"]**(1 / 6) / var) < 0.28 fde_none = fdepsd(sig, sr, freq, q, resp="pvelo", rolloff=None) fde_pre = fdepsd(sig, sr, freq, q, resp="pvelo", rolloff="prefilter") assert np.all((fde_none.psd <= fde_pre.psd).values) T0 = 120 fde_T0 = fdepsd(sig, sr, freq, q, T0=T0, resp="pvelo") factor = np.log(freq * 60) / np.log(freq * T0) assert np.allclose(fde_T0.psd.iloc[:, :2], fde_auto.psd.iloc[:, :2].multiply(factor, axis=0)) assert np.all((fde_T0.psd.iloc[:, 2:] < fde_auto.psd.iloc[:, 2:]).values)
def test_fdepsd_winends(): TF = 60 # make a 60 second signal sp = 1.0 spec = np.array([[20, sp], [50, sp]]) sig, sr, t = psd.psd2time( spec, ppc=10, fstart=20, fstop=50, df=1 / TF, winends=dict(portion=40), gettime=True, ) sig[0] = 20 freq = np.arange(1.0, 3.1) q = 25 fde = fdepsd(sig, sr, freq, q, hpfilter=None) fde2 = fdepsd(sig, sr, freq, q, hpfilter=None, winends=None) fde3 = fdepsd(sig, sr, freq, q, hpfilter=None, winends=dict(portion=20)) assert np.all((fde2.psd.iloc[:, 0] > 4 * fde.psd.iloc[:, 0]).values) assert np.all((fde2.psd.iloc[:, 0] > 4 * fde3.psd.iloc[:, 0]).values)
def test_psd2time(): spec = np.array([[20, 0.0768], [50, 0.48], [100, 0.48]]) sig, sr = psd.psd2time(spec, ppc=10, fstart=35, fstop=70, df=0.01, winends=dict(portion=0.01)) # ensure that expand_method works: sig2, sr2 = psd.psd2time( spec, ppc=10, fstart=35, fstop=70, df=0.01, winends=dict(portion=0.01), expand_method="rescale", ) f1, p1 = psd.psdmod(sig, sr, timeslice=f"{len(sig)}") f2, p2 = psd.psdmod(sig2, sr2, timeslice=f"{len(sig)}") assert np.trapz(p1, f1) < np.trapz(p2, f2) assert_raises( ValueError, psd.psd2time, spec, ppc=10, fstart=35, fstop=70, df=0.01, winends=dict(portion=0.01), expand_method="bad expand method", ) assert np.allclose(700.0, sr) # 70*10 assert sig.size == 700 * 100 f, p = signal.welch(sig, sr, nperseg=sr) pv = np.logical_and(f >= 37, f <= 68) fi = f[pv] psdi = p[pv] speci = psd.interp(spec, fi).flatten() assert abs(speci - psdi).max() < 0.05 assert abs(np.trapz(psdi, fi) - np.trapz(speci, fi)) < 0.25 spec = ([0.1, 5], [0.1, 0.1]) sig, sr = psd.psd2time(spec, ppc=10, fstart=0.1, fstop=5, df=0.2, winends=dict(portion=0.01)) # df gets internally reset to fstart assert np.allclose(5 * 10.0, sr) assert sig.size == 50 * 10 f, p = signal.welch(sig, sr, nperseg=sr) pv = np.logical_and(f >= 0.5, f <= 3.0) fi = f[pv] psdi = p[pv] speci = psd.interp(spec, fi).flatten() assert abs(speci - psdi).max() < 0.05 assert abs(np.trapz(psdi, fi) - np.trapz(speci, fi)) < 0.065 # ppc gets reset to 2 case: spec = np.array([[0.1, 2.0], [5, 2.0]]) sig, sr = psd.psd2time(spec, ppc=1, fstart=0.1, fstop=5, df=0.2, winends=dict(portion=0.01)) assert (np.sum(np.mean(sig**2)) - 2.0 * 4.9) / (2.0 * 4.9) < 0.1 # odd length FFT case: spec = np.array([[0.1, 2.0], [5, 2.0]]) sig, sr, t = psd.psd2time(spec, ppc=3, fstart=0.2, fstop=5, df=0.2, winends=dict(portion=0.01), gettime=1) assert np.allclose(5 * 3, sr) assert sig.size == 15 * 5 assert (np.sum(np.mean(sig**2)) - 2.0 * 4.8) / (2.0 * 4.8) < 0.1 assert np.allclose(t, np.arange(15 * 5) / sr)