Time Series

Filters

Apodization Window

@author: kkappler

Module to manage windowing prior to FFT. Intended to support most apodization windows available via scipy.signal.get_window()

Supported Window types = [‘boxcar’, ‘triang’, ‘blackman’, ‘hamming’, ‘hann’,

‘bartlett’, ‘flattop’, ‘parzen’, ‘bohman’, ‘blackmanharris’, ‘nuttall’, ‘barthann’, ‘kaiser’, ‘gaussian’, ‘general_gaussian’, ‘slepian’, ‘chebwin’]

have_additional_args = {

‘kaiser’ : ‘beta’, ‘gaussian’ : ‘std’, ‘general_gaussian’ : (‘power’, ‘width’), ‘slepian’ : ‘width’, ‘chebwin’ : ‘attenuation’,

}

The Taper Config has 2 possible forms: 1. Standard form for accessing scipy.signal: [“taper_family”, “num_samples_window”, “additional_args”] 2. User-defined : for defining custom tapers

Example 1 : Standard form “taper_family” = “hamming” “num_samples_window” = 128 “additional_args” = {}

Example 2 : Standard form “taper_family” = “kaiser” “num_samples_window” = 64 “additional_args” = {“beta”:8}

Examples 3 : User Defined 2. user-defined: [“array”] In this case num_samples_window is defined by the array. “array” = [1, 2, 3, 4, 5, 4, 3, 2, 1] If “array” is non-empty then assume the user-defined case.

It is a little bit unsatisfying that the args need to be ordered for scipy.signal.get_window(). Probably use OrderedDict() for any windows that have more than one additional args.

For example “taper_family” = ‘general_gaussian’ “additional_args” = OrderedDict(“power”:1.5, “sigma”:7)

class aurora.time_series.apodization_window.ApodizationWindow(**kwargs)[source]

Bases: object

Instantiate an apodization window object. Example usages: apod_window = ApodizationWindow() taper=ApodizationWindow(taper_family=’hanning’, num_samples_window=55 )

Window factors S1, S2, CG, ENBW are modelled after Heinzel et al. p12-14 [1] Spectrum and spectral density estimation by the Discrete Fourier transform (DFT), including a comprehensive list of window functions and some new flat-top windows. G. Heinzel, A. Roudiger and R. Schilling, Max-Planck Institut fur Gravitationsphysik (Albert-Einstein-Institut) Teilinstitut Hannover February 15, 2002 See Also [2] Harris FJ. On the use of windows for harmonic analysis with the discrete Fourier transform. Proceedings of the IEEE. 1978 Jan;66(1):51-83.

Nomenclature from Heinzel et al. ENBW: Effective Noise BandWidth, see Equation (22) NENBW Normalized Equivalent Noise BandWidth, see Equation (21)

Parameters
taper_familystring

Specify the taper type - boxcar, kaiser, hanning, etc

num_samples_windowint

The number of samples in the taper

tapernumpy array

The actual window coefficients themselves. This can be passed if a particular custom window is desired.

additional_args: dictionary

These are any additional requirements scipy needs in order to generate the window.

Attributes
S1

sum of the window coefficients

S2

sum of squares of the window coefficients

apodization_factor
coherent_gain

DC gain of the window normalized by window length

nenbw

NENBW Normalized Equivalent Noise BandWidth, see Equation (21) in

num_samples_window
summary

Returns

taper

Methods

enbw(fs)

Notes that unlike NENBW, CG, S1, S2, this is not a pure property of the window -- but instead this is a property of the window combined with the sample rate.

make()

this is just a wrapper call to scipy.signal Note: see scipy.signal.get_window for a description of what is expected in args[1:].

test_linear_spectral_density_factor()

This is just a test to verify some algebra Claim: The lsd_calibration factors A (1./coherent_gain)*np.sqrt((2*dt)/(nenbw*N)) and B np.sqrt(2/(sample_rate*self.S2)) are identical.

property S1

sum of the window coefficients

property S2

sum of squares of the window coefficients

property apodization_factor
property coherent_gain

DC gain of the window normalized by window length

enbw(fs)[source]

Notes that unlike NENBW, CG, S1, S2, this is not a pure property of the window – but instead this is a property of the window combined with the sample rate. Parameters ———- fs : sampling frequency (1/dt)

Returns
make()[source]

this is just a wrapper call to scipy.signal Note: see scipy.signal.get_window for a description of what is expected in args[1:]. http://docs.scipy.org/doc/scipy/reference/ generated/scipy.signal.get_window.html

note: this is just repackaging the args so that scipy.signal.get_window() accepts all cases.

property nenbw

NENBW Normalized Equivalent Noise BandWidth, see Equation (21) in Heinzel et al 2002

property num_samples_window
property summary
Returns
out_str: str

String comprised of the taper_family, number_of_samples, and True/False if self.taper is not None

property taper
test_linear_spectral_density_factor()[source]

This is just a test to verify some algebra Claim: The lsd_calibration factors A (1./coherent_gain)*np.sqrt((2*dt)/(nenbw*N)) and B np.sqrt(2/(sample_rate*self.S2)) are identical.

Note sqrt(2*dt)==sqrt(2*sample_rate) so we can cancel these terms and A=B IFF (1./coherent_gain) * np.sqrt(1/(nenbw*N)) == 1/np.sqrt(S2) which I show in githib aurora issue #3 via . (CG**2) * NENBW *N = S2

Returns
aurora.time_series.apodization_window.main()[source]
aurora.time_series.apodization_window.test_can_inititalize_apodization_window()[source]
Returns

Decorators

Frequency Band

Frequency Band Helpers

Frequency Domain Helpers

aurora.time_series.frequency_domain_helpers.get_fft_harmonics(samples_per_window, sample_rate, one_sided=True)[source]

Works for odd and even number of points. Does not return Nyquist, does return DC component Could be midified with kwargs to support one_sided, two_sided, ignore_dc ignore_nyquist, and etc. Could actally take FrequencyBands as an argument if we wanted as well.

Parameters
samples_per_window
sample_rate
Returns

Time Axis Helpers

aurora.time_series.time_axis_helpers.decide_time_axis_method(sample_rate)[source]
aurora.time_series.time_axis_helpers.do_some_tests()[source]
aurora.time_series.time_axis_helpers.fast_arange(t0, n_samples, sample_rate)[source]
aurora.time_series.time_axis_helpers.main()[source]
aurora.time_series.time_axis_helpers.make_time_axis(t0, n_samples, sample_rate)[source]
aurora.time_series.time_axis_helpers.slow_comprehension(t0, n_samples, sample_rate)[source]
aurora.time_series.time_axis_helpers.test_generate_time_axis(t0, n_samples, sample_rate)[source]

Two obvious ways to generate an axis of timestanps here. One method is slow and more precise, the other is fast but drops some nanoseconds due to integer roundoff error.

To see this, consider the example of say 3Hz, we are 333333333ns between samples,

which drops 1ns per second if we scale a nanoseconds=np.arange(N)

The issue here is that the nanoseconds granularity forces a roundoff error,

Probably will use logic like: if there_are_integer_ns_per_sample:

time_stamps = do_it_the_fast_way()

else:

time_stamps = do_it_the_slow_way()

return time_stamps

Parameters
t0
n_samples
sample_rate
Returns

Window Helpers

Notes in google doc: https://docs.google.com/document/d/1CsRhSLXsRG8HQxM4lKNqVj-V9KA9iUQAvCOtouVzFs0/edit?usp=sharing

aurora.time_series.window_helpers.apply_fft_to_windowed_array(windowed_array)[source]

This will operate row-wise as well Parameters ———- windowed_array

Returns
aurora.time_series.window_helpers.available_number_of_windows_in_array(n_samples_array, n_samples_window, n_advance)[source]
Parameters
n_samples_array: int

The length of the time series

n_samples_window: int

The length of the window (in samples)

n_advance: int

The number of samples the window advances at each step

Returns
available_number_of_strides: int

The number of windows the time series will yield

aurora.time_series.window_helpers.check_all_sliding_window_functions_are_equivalent()[source]

simple sanity check that runs each sliding window function on a small array and confirms the results are numerically identical. Note that striding window will return int types where others return float. Returns ——-

aurora.time_series.window_helpers.do_some_tests()[source]
aurora.time_series.window_helpers.main()[source]
aurora.time_series.window_helpers.sliding_window_crude(data, num_samples_window, num_samples_advance, num_windows=None)[source]
Parameters
data: np.ndarray

The time series data to be windowed

num_samples_window: int

The length of the window (in samples)

num_samples_advance: int

The number of samples the window advances at each step

num_windows: int

The number of windows to “take”. Must be less or equal to the number of available windows.

Returns
output_array: numpy.ndarray

The windowed time series

aurora.time_series.window_helpers.sliding_window_numba(data, num_samples_window, num_samples_advance, num_windows)[source]
Parameters
data: np.ndarray

The time series data to be windowed

num_samples_window: int

The length of the window (in samples)

num_samples_advance: int

The number of samples the window advances at each step

num_windows: int

The number of windows to “take”.

Returns
output_array: numpy.ndarray

The windowed time series

aurora.time_series.window_helpers.striding_window(data, num_samples_window, num_samples_advance, num_windows=None)[source]

Applies a striding window to an array. We use 1D arrays here. Note that this method is extendable to N-dimensional arrays as was once shown at http://www.johnvinyard.com/blog/?p=268

Karl has an implementation of this code but chose to restict to 1D here. This is becuase of several warnings encountered, on the notes of stride_tricks.py, as well as for example here: https://stackoverflow.com/questions/4936620/using-strides-for-an-efficient-moving-average-filter

While we can possibly setup Aurora so that no copies of the strided window are made downstream, we cannot guarantee that another user may not add methods that require copies. For robustness we will use 1d implementation only for now.

Another clean example of this method can be found in the razorback codes from brgm.

result is 2d: result[i] is the i-th window

>>> sliding_window(np.arange(15), 4, 3, 2)
array([[0, 1, 2],
       [2, 3, 4],
       [4, 5, 6],
       [6, 7, 8]])
Parameters
data: np.ndarray

The time series data to be windowed

num_samples_window: int

The length of the window (in samples)

num_samples_advance: int

The number of samples the window advances at each step

num_windows: int

The number of windows to “take”. Must be less or equal to the number of available windows.

Returns
strided_window: numpy.ndarray

The windowed time series

aurora.time_series.window_helpers.test_apply_taper()[source]

Windowed Time Series

Windowing Scheme