diff --git a/.gitignore b/.gitignore index 0c173c4..66cf48f 100644 --- a/.gitignore +++ b/.gitignore @@ -150,4 +150,6 @@ Code_MatLab/ # Docs directory Docs/ + +# Data directory data/ diff --git a/Code_Python/filters.py b/Code_Python/filters.py index f17f996..6a91acc 100644 --- a/Code_Python/filters.py +++ b/Code_Python/filters.py @@ -649,7 +649,7 @@ class Filter: plt.ylabel('$h$ [db]') legend = ['Filter', '-3dB'] plt.legend(legend) - plt.title('Frequency Response', fontweight="bold") + plt.title('Frequency Response') # Plot and format lag/group delay plt.subplot(1, 2, 2) @@ -658,7 +658,8 @@ class Filter: plt.xlim(np.amin(wf), np.amax(wf)) plt.xlabel(r'$\omega$ [rad/sample]') plt.ylabel('$gd$ [samples]') - plt.title('Lag / Group Delay', fontweight="bold") + plt.title('Lag / Group Delay') # Show plots + plt.suptitle('Example "Response"') plt.show() diff --git a/Code_Python/test.py b/Code_Python/test.py index 7d043fd..79ba5c9 100644 --- a/Code_Python/test.py +++ b/Code_Python/test.py @@ -3,19 +3,112 @@ Signal Filtering and Generation of Synthetic Time-Series. Copyright (c) 2020 Gabriele Gilardi + +References +---------- + +- John F. Ehlers, "Cycle Analytics for Traders: Advanced Technical Trading + Concepts", @ http://www.mesasoftware.com/ehlers_books.htm. + +- D. Prichard and J. Theiler, "Generating surrogate data for time series with + several simultaneously measured variables", + @ https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.73.951. + +- H. Vinod and J. Lopez-de-Lacalle, "Maximum entropy bootstrap for time series: + the meboot R package, @ https://www.jstatsoft.org/article/view/v029i05. + +Characteristics +--------------- +- The code has been written and tested in Python 3.7.7. +- Implementation of several digital signal filters and functions for the + generation of synthetic (surrogate) time-series. +- Filter list (file ): + Generic Generic filter + SMA Simple moving average + EMA Exponential moving average + WMA Weighted moving average + MSMA Modified simple moving average + MLSQ Modified least-squares quadratic + ButterOrig Butterworth original filter + ButterMod Butterworth modified filter + SuperSmooth Supersmoother filter + GaussLow Gauss low pass filter + GaussHigh Gauss high pass filter + BandPass Band-pass filter + BandStop Band-stop filter + ZEMA1 Zero-lag EMA (type 1) + ZEMA2 Zero-lag EMA (type 2) + InstTrend Instantaneous trendline + SincFilter Sinc function filter + Decycler De-cycler filter + DecyclerOsc De-cycle oscillator + ABG Alpha-beta-gamma filter + Kalman One-dimensional steady-state Kalman filter +- Synthetic time-series (file ): + synthetic_wave Generates multi-sine wave given periods, + amplitudes, and phases. + synthetic_sampling Generates surrogates using randomized-sampling + (bootstrap) with or without replacement. + synthetic_FFT Generates surrogates using the phase-randomized + Fourier transform algorithm. + synthetic_MEboot Generates surrogates using the maximum entropy + bootstrap algorithm. +- File includes also functions to plot the filter signal, + frequency response, and group delay. +- File includes also functions to differentiate, integrate, + normalize, and scale the discrete time-series. +- Usage: python test.py . + +Parameters +---------- +example + Name of the example to run (Filters, Kalman, FFT_boot, ME_boot, Response). +data_file + File with the dataset (csv format). The extension is added automatically. +X + Dataset to filter/time-series (input). It must be a 1D array, i.e. of shape + (:, ) or (:, 1) or (1, :). +b + Transfer response coefficients (numerator). +a + Transfer response coefficients (denominator). +Y + Filtered dataset (output). +X_synt + Surrogate/synthetic generated time-series (output) +n_reps + Number of surrogates/synthetic time-series to generate. + +Examples +-------- +There are five examples (all of them use the dataset in *spx.csv*). The +results are shown in file . + +- Filter: example showing filtering using an EMA, a Butterworth modified + filter, and a type 2 Zero-lag EMA. + +- Kalman: example showing filtering using the three types of Kalman filter, + alpha, alpha-beta, and alpha-beta-gamma. + +- FFT_boot: example showing the generation of surrogates time-series using + the Fourier-transform algorithm and the discrete differences. + +- ME_boot: example showing the generation of surrogates time-series using the + using maximum entropy bootstrap algorithm and the discrete differences. + +- Response: example showing the frequency response and lag/group delay for a + band-pass filter. """ import sys import warnings import numpy as np -import matplotlib.pyplot as plt import filters as flt import synthetic as syn # Added to avoid message warning "The group delay is singular at frequencies -# [....], setting to 0" when plotting the lag for SMA filters. -# np.seterr(all='ignore') +# [....], setting to 0" when plotting the lag for SMA filters. warnings.filterwarnings('ignore') np.random.seed(1294404794) @@ -29,7 +122,7 @@ example = sys.argv[1] data_file = 'spx' data = np.loadtxt(data_file + '.csv', delimiter=',') -# Example with a few filters +# Example with an EMA, a Butterworth modified filter, and a type 2 Zero-lag EMA if (example == 'Filters'): spx = flt.Filter(data) ema = spx.EMA(N=10) @@ -49,38 +142,53 @@ elif (example == 'Kalman'): names = ['SPX', 'a-type', 'ab-type', 'abg-type'] flt.plot_signals(signals, names=names, start=0, end=200) -# Example of filter frequency and lag +# Example of surrogates time-series using the Fourier-transform algorithm +elif (example == 'FFT_boot'): + n_reps = 4 + n_samples = len(data) + + # Generated the surrogates using the 1st discrete differences (in percent) + dX = syn.value2diff(data, percent=True) + dX_synt = syn.synthetic_FFT(dX, n_reps=n_reps) # (n_reps, n_samples) + + # Rebuild the actual surrogate time-series + signals = [data] + names = ['SPX'] + for i in range(n_reps): + X_synt = syn.diff2value(dX_synt[i, :], data[0], percent=True) + signals.append(X_synt) + names.append('Synth. #' + str(i+1)) + + # Plot all + flt.plot_signals(signals, names=names, start=0, end=200) + +# Example of surrogates time-series using the maximum entropy bootstrap algorithm +elif (example == 'ME_boot'): + n_reps = 4 + n_samples = len(data) + + # Generated the surrogates using the 1st discrete differences (in value) + dX = syn.value2diff(data, percent=False) + dX_synt = syn.synthetic_MEboot(dX, n_reps=n_reps, alpha=0.1, bounds=False, + scale=False) # (n_reps, n_samples) + + # Rebuild the actual surrogate time-series + signals = [data] + names = ['SPX'] + for i in range(n_reps): + X_synt = syn.diff2value(dX_synt[i, :], data[0], percent=False) + signals.append(X_synt) + names.append('Synth. #' + str(i+1)) + + # Plot all + flt.plot_signals(signals, names=names, start=0, end=499) + +# Example of frequency response and lag/group delay for a band-pass filter elif (example == 'Response'): spx = flt.Filter(data) band = spx.BandPass(P=10, delta=0.3) spx.plot_response() -# Example of surrogates time-series using the Fourier-transform algorithm -elif (example == 'FFT_boot'): - pass - -# Example of surrogates time-series using maximum entropy bootstrap algorithm -elif (example == 'ME_boot'): - pass - else: print("Example not found") sys.exit(1) - - -# dX = syn.value2diff(data, percent=True) -# # X = syn.diff2value(dX, data[0], percent=True) -# signals = [data, X] -# flt.plot_signals(signals, start=0, end=200) - -# dX = syn.value2diff(data, percent=False) -# dX_synt = syn.synthetic_sampling(dX, n_reps=1, replace=True) -# dX_synt = syn.synthetic_FFT(dX, n_reps=2) -# dX_synt = syn.synthetic_MEboot(dX, n_reps=4, alpha=0.1, bounds=False, scale=False) -# for i in range(dX_synt.shape[0]): -# # aa = dX_synt[:, i] -# aa = syn.diff2value(dX_synt[i, :], data[0], percent=False) -# plt.plot(aa) -# plt.xlim(0, 200) -# plt.plot(data) -# plt.show() diff --git a/README.md b/README.md index a0f0e62..414a745 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,9 @@ ## Main Parameters -`example` Name of the example to run. +`example` Name of the example to run (Filters, Kalman, FFT_boot, ME_boot, Response). -`data_file` File name with the dataset (csv format). The extension is added automatically. +`data_file` File with the dataset (csv format). The extension is added automatically. `X` Dataset to filter/time-series (input). It must be a 1D array, i.e. of shape `(:, )` or `(:, 1)` or `(1, :)`. @@ -57,10 +57,20 @@ `Y` Filtered dataset (output). -`X_synt` Synthetic time-series (output) +`X_synt` Surrogate/synthetic generated time-series (output) `n_reps` Number of surrogates/synthetic time-series to generate. ## Examples -There are five examples: **Filters**, **Kalman**, **Response**, **FFT_boot**, **ME_boot**. For all, the dataset in *spx.csv* is used. +There are five examples (all of them use the dataset in *spx.csv*). The results are shown [here](Results_Examples.pdf). + +- **Filter** Example showing filtering using an EMA, a Butterworth modified filter, and a type 2 Zero-lag EMA. + +- **Kalman** Example showing filtering using the three types of Kalman filter, alpha, alpha-beta, and alpha-beta-gamma. + +- **FFT_boot** Example showing the generation of surrogates time-series using the Fourier-transform algorithm and the discrete differences. + +- **ME_boot** Example showing the generation of surrogates time-series using the using maximum entropy bootstrap algorithm and the discrete differences. + +- **Response** Example showing the frequency response and lag/group delay for a band-pass filter. diff --git a/Result_Examples.pdf b/Result_Examples.pdf new file mode 100644 index 0000000..de618a3 Binary files /dev/null and b/Result_Examples.pdf differ