Module libquantum.scales

Construct standardized scales

Expand source code
"""
Construct standardized scales
"""

import numpy as np
from typing import Tuple, Union

""" Smallest number for 64-bit floats. Deploy to avoid division by zero or log zero singularities"""
EPSILON = np.finfo(np.float64).eps
MICROS_TO_S = 1E-6
MICROS_TO_MILLIS = 1E-3
KPA_TO_PA = 1E3
DEGREES_TO_KM = 111.
"""
Standardized scales
"""


class Slice:
    """
    Constants for slice calculations, supersedes inferno/slice
    """
    # Constant Q Base
    G2 = 2.  # Octaves
    G3 = 10. ** 0.3  # Reconciles base2 and base10
    # Time
    T_PLANCK = 5.4E-44  # 2.**(-144)   Planck time in seconds
    T0S = 1E-42  # Universal Scale
    T1S = 1.    # 1 second
    T100S = 100.  # 1 hectosecond, IMS low band edge
    T1000S = 1000.  # 1 kiloseconds = 1 mHz
    T1M = 60.  # 1 minute in seconds
    T1H = T1M*60.  # 1 hour in seconds
    T1D = T1H*24.   # 1 day in seconds
    TU = 2.**58  # Estimated age of the known universe in seconds
    # Frequency
    F1 = 1.  # 1 Hz
    F1000 = 1000.  # 1 kHz
    F0 = 1.E42  # 1/Universal Scale
    FU = 2.**-58  # Estimated age of the universe in Hz
    # Pressure
    PREF_KPA = 101.325  # sea level pressure, kPa
    PREF_PA = 10132500.  # sea level pressure, kPa


def planck_scale_s(scale_order: float) -> Tuple[float, float, float, float]:
    """
    Calculate Planck scale

    :param scale_order: scale order
    :return: center in seconds, minimum in seconds, maximum in seconds, quality factor Q
    """
    # Assumes base 2, Slice.G2
    cycles_M, quality_factor_Q = wavelet_MQ_from_N(scale_order)
    scale_edge = Slice.G2 ** (1.0 / (2.0 * scale_order))
    # # Q = center/bandwidth
    # planck_scale_zero_s = planck_scale_bandwidth_s*quality_factor_Q
    # Must be greater than Planck scale
    planck_scale_center_s = Slice.T0S
    # Smallest scale
    planck_scale_min_s = planck_scale_center_s/scale_edge
    planck_scale_max_s = planck_scale_center_s*scale_edge
    return planck_scale_center_s, planck_scale_min_s, planck_scale_max_s, quality_factor_Q


def musical_scale_hz():
    """
    Returns frequencies for equal tempered scale
    base2, ref = 440 Hz, 12th octaves
    """
    return band_frequencies_nyquist(frequency_order_input=12,
                                    frequency_base_input=2,
                                    frequency_ref_input=440,
                                    frequency_low_input=16.35,
                                    frequency_sample_rate_input=48000)


def band_periods_nyquist(scale_order_input: float,
                         scale_base_input: float,
                         scale_ref_input: float,
                         scale_sample_interval_input: float,
                         scale_high_input: float) -> Tuple[float, float, np.ndarray, float, np.ndarray,
                                                           np.ndarray, np.ndarray, np.ndarray]:
    """Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE SECONDS

    Parameters
    ----------
    scale_order_input: float
        Band order N, for ISO3 use N = 1.0 or 3.0 or 6.0 or 12.0 or 24.0
    scale_base_input: float
        reference base G; i.e. G3 = 10.**0.3 or G2 = 2.0
    scale_ref_input: float
        time reference: in seconds
    scale_sample_interval_input: float
        Sample interval for scale: float
    scale_high_input: float
        Highest scale of interest in seconds

    Returns
    -------
    scale_order: float
        Band order N > 1, defaults to 1.
    scale_base: float
        positive reference Base G > 1, defaults to G3
    scale_ref: float
        positive reference scale
    scale_band_number: numpy ndarray
        Band number n
    scale_center_algebraic: numpy ndarray
        Algebraic center of band scale
    scale_center_geometric: numpy ndarray
        Geometric center of band scale
    scale_start: numpy ndarray
        Lower band edge scale
    scale_end: numpy ndarray
        Upper band edge scale
    """
    scale_nyquist_input = 2*scale_sample_interval_input
    scale_order, scale_base, scale_band_number, scale_ref, scale_center_algebraic, scale_center_geometric, scale_start, \
    scale_end = band_intervals_periods(scale_order_input=scale_order_input,
                                       scale_base_input=scale_base_input,
                                       scale_ref_input=scale_ref_input,
                                       scale_low_input=scale_nyquist_input,
                                       scale_high_input=scale_high_input)

    return scale_order, scale_base, scale_band_number, scale_ref, scale_center_algebraic, scale_center_geometric, \
           scale_start, scale_end


def band_frequencies_nyquist(frequency_order_input: float,
                             frequency_base_input: float,
                             frequency_ref_input: float,
                             frequency_low_input: float,
                             frequency_sample_rate_input: float) -> Tuple[float, float, np.ndarray, float, float,
                                                                          np.ndarray, np.ndarray, np.ndarray]:
    """
    Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE HZ

    :param frequency_order_input: Nth order
    :param frequency_base_input: G2 or G3
    :param frequency_ref_input: reference frequency
    :param frequency_low_input: lowest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :return: scale_order (Band order N > 1, defaults to 1.),
        scale_base (positive reference Base G > 1, defaults to G3),
        scale_band_number (Band number n),
        frequency_ref (reference frequency value),
        frequency_center_algebraic (Algebraic center of frequencies),
        frequency_center_geometric (Geometric center of frequencies),
        frequency_start (first frequency),
        frequency_end (last frequency)

    """

    scale_ref_input = 1/frequency_ref_input
    scale_nyquist_input = 2/frequency_sample_rate_input
    scale_high_input = 1/frequency_low_input

    scale_order, scale_base, scale_band_number, \
    scale_ref, scale_center_algebraic, scale_center_geometric, \
    scale_start, scale_end = \
        band_intervals_periods(frequency_order_input, frequency_base_input,
                               scale_ref_input,
                               scale_nyquist_input, scale_high_input)
    frequency_ref = 1/scale_ref
    frequency_center_geometric = 1/scale_center_geometric
    frequency_end = 1/scale_start
    frequency_start = 1/scale_end
    frequency_center_algebraic = (frequency_end + frequency_start)/2.
    
    # Inherit the order, base, and band number
    return scale_order, scale_base, -scale_band_number, frequency_ref, frequency_center_algebraic, \
           frequency_center_geometric, frequency_start, frequency_end


def band_frequencies_low_high(frequency_order_input: float,
                              frequency_base_input: float,
                              frequency_ref_input: float,
                              frequency_low_input: float,
                              frequency_high_input: float,
                              frequency_sample_rate_input: float) -> Tuple[float, float, np.ndarray, float, np.ndarray,
                                                                           np.ndarray, np.ndarray, np.ndarray]:
    """
    Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE HZ

    :param frequency_order_input: Nth order
    :param frequency_base_input: G2 or G3
    :param frequency_ref_input: reference frequency
    :param frequency_low_input: lowest frequency of interest
    :param frequency_high_input: highest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :return:scale_order (Band order N > 1, defaults to 1.),
        scale_base (positive reference Base G > 1, defaults to G3),
        scale_band_number (Band number n),
        frequency_ref (reference frequency value),
        frequency_center_algebraic (Algebraic center of frequencies),
        frequency_center_geometric (Geometric center of frequencies),
        frequency_start (first frequency),
        frequency_end (last frequency)
    """

    scale_ref_input = 1/frequency_ref_input
    scale_nyquist_input = 2/frequency_sample_rate_input
    scale_low_input = 1/frequency_high_input
    if scale_low_input < scale_nyquist_input:
        scale_low_input = scale_nyquist_input
    scale_high_input = 1/frequency_low_input

    scale_order, scale_base, scale_band_number, \
    scale_ref, scale_center_algebraic, scale_center_geometric, \
    scale_start, scale_end = \
        band_intervals_periods(frequency_order_input, frequency_base_input,
                               scale_ref_input,
                               scale_low_input,
                               scale_high_input)
    frequency_ref = 1/scale_ref
    frequency_center_geometric = 1/scale_center_geometric
    frequency_end = 1/scale_start
    frequency_start = 1/scale_end
    frequency_center_algebraic = (frequency_end + frequency_start)/2.

    # Inherit the order, base, and band number
    return scale_order, scale_base, -scale_band_number,  frequency_ref, frequency_center_algebraic, \
           frequency_center_geometric, frequency_start, frequency_end


def band_intervals_periods(scale_order_input: float,
                           scale_base_input: float,
                           scale_ref_input: float,
                           scale_low_input: float,
                           scale_high_input: float) -> Tuple[float, float, np.ndarray, float, np.ndarray,
                                                             np.ndarray, np.ndarray, np.ndarray]:
    """Evaluate Standard Logarithmic Interval Scale Parameters using time scales in seconds
    If scales are provided as frequency, previous computations convert to time.
    Designed to take bappsband to just below Nyquist, within a band edge.
    ALWAYS CONVERT TO SECONDS
    Last updated: 20200905

    Parameters
    ----------
    scale_order_input: float
        Band order N, for ISO3 use N = 1.0 or 3.0 or 6.0 or 12.0 or 24.0
    scale_base_input: float
        reference base G; i.e. G3 = 10.**0.3 or G2 = 2.0
    scale_ref_input: float
        time reference: in seconds
    scale_low_input: float
        Lowest scale. If Nyquist scale, 2 * sample interval in seconds.
    scale_high_input: float
        Highest scale of interest in seconds

    Returns
    -------
    scale_order: float
        Band order N > 1, defaults to 1.
    scale_base: float
        positive reference Base G > 1, defaults to G3
    scale_ref: float
        positive reference scale
    scale_band_number: numpy ndarray
        Band number n
    scale_center_algebraic: numpy ndarray
        Algebraic center band scale
    scale_center_geometric: numpy ndarray
        Geometric center band scale
    scale_start: numpy ndarray
        Lower band edge scale
    scale_end: numpy ndarray
        Upper band edge scale
    """
    # Initiate error handling, all inputs should be numeric, positive, and real
    # Need error check for string inputs
    # If not real and positive, make them so
    [scale_ref, scale_low, scale_high, scale_base, scale_order] = np.absolute(
        [scale_ref_input, scale_low_input, scale_high_input, scale_base_input, scale_order_input])

    # print('\nConstructing standard band intervals')
    # Check for compliance with ISO3 and/or ANSI S1.11 and for scale_order = 1, 3, 6, 12, and 24
    if scale_base == Slice.G3:
        pass
    elif scale_base == Slice.G2:
        pass
    elif scale_base < 1.:
        print('\nWARNING: Base must be greater than unity. Overriding to G = 2')
        scale_base = Slice.G2
    else:
        print('\nWARNING: Base is not ISO3 or ANSI S1.11 compliant')
        print(('Continuing With Non-standard base = ' + repr(scale_base) + ' ...'))

    # Check for compliance with ISO3 for scale_order = 1, 3, 6, 12, and 24
    # and the two 'special' orders 0.75 and 1.5
    valid_scale_orders = (0.75, 1, 1.5, 3, 6, 12, 24, 48)
    if scale_order in valid_scale_orders:
        pass
    elif scale_order < 0.75:
        print('Order must be greater than 0.75. Overriding to Order 1')
        scale_order = 1
    else:
        print(('\nWARNING: Recommend Orders ' + str(valid_scale_orders)))
        print(('Continuing With Non-standard Order = ' + repr(scale_order) + ' ...'))

    # Compute scale edge and width parameters
    scale_edge = scale_base ** (1.0 / (2.0 * scale_order))
    scale_width = scale_edge - 1.0 / scale_edge

    if scale_low < Slice.T0S:
        scale_low = Slice.T0S/scale_edge
    if scale_high < scale_low:
        print('\nWARNING: Upper scale must be larger than the lowest scale')
        print('Overriding to min = max/G  \n')
        scale_low = scale_high / scale_base
    if scale_high == scale_low:
        print('\nWARNING: Upper scale = lowest scale, returning closest band edges')
        scale_high *= scale_edge
        scale_low /= scale_edge

    # Max and min bands are computed relative to the center scale
    n_max = np.round(scale_order * np.log(scale_high / scale_ref) / np.log(scale_base))
    n_min = np.floor(scale_order * np.log(scale_low / scale_ref) / np.log(scale_base))

    # Evaluate min, ensure it stays below Nyquist period
    scale_center_n_min = scale_ref * np.power(scale_base, n_min/scale_order)
    if (scale_center_n_min < scale_low) or (scale_center_n_min/scale_edge < scale_low-EPSILON):
        n_min += 1

    # Check for band number anomalies
    if n_max < n_min:
        print('\nSPECMOD: Insufficient bandwidth for Nth band specification')
        print(('Minimum scaled bandwidth (scale_high - scale_low)/scale_center = ' + repr(scale_width) + '\n'))
        print('Correct scale High/Low input parameters \n')
        print('Apply one order  \n')
        n_max = np.floor(np.log10(scale_high) / np.log10(scale_base))
        n_min = n_max - scale_order

    # Band number array for Nth octave
    scale_band_number = np.arange(n_min, n_max + 1)

    # Compute exact, evenly (log) distributed, constant Q,
    # Nth octave center and band edge frequencies
    scale_band_exponent = scale_band_number / scale_order

    scale_center_geometric = scale_ref * np.power(scale_base * np.ones(scale_band_number.shape), scale_band_exponent)
    scale_start = scale_center_geometric / scale_edge
    scale_end = scale_center_geometric * scale_edge
    # The spectrum is centered on the algebraic center scale
    scale_center_algebraic = (scale_start+scale_end)/2.

    return scale_order, scale_base, scale_band_number,  scale_ref, scale_center_algebraic, scale_center_geometric, \
           scale_start, scale_end


"""
Quantum wavelet specifications
"""


def wavelet_MQ_from_N(band_order_Nth: float) -> Tuple[float, float]:
    """
    Compute the quality factor Q and multiplier M for a specified band order N
    N is THE quantization parameter for the binary constant Q wavelet filters

    :param band_order_Nth: Band order, must be > 0.75 or reverts to N=3
    :return: float, float
    """
    if band_order_Nth < 0.7:
        print('N<0.7 specified, using N = ', 3)
        band_order_Nth = 3.
    order_bandedge = 2 ** (1. / 2. / band_order_Nth)  # kN in Garces 2013
    order_scaled_bandwidth = order_bandedge - 1. / order_bandedge
    quality_factor_Q = 1./order_scaled_bandwidth  # Exact for Nth octave bands
    cycles_M = quality_factor_Q*2*np.sqrt(np.log(2))  # Exact, from -3dB points
    return cycles_M, quality_factor_Q


def wavelet_NMQ_from_Q(quality_factor_Q: float) -> Tuple[float, float, float]:
    """
    For a specified Q, estimate order N and recompute exact Q and number of cycles M from N

    :param quality_factor_Q: number of oscillations with significant amplitude in the frame
    :return: band order Nth (float), number of cycles M (float), quality factor Q (float)
    """
    band_order_Nth = quality_factor_Q/np.sqrt(2)  # Approximate
    cycles_M, quality_factor_Q = wavelet_MQ_from_N(band_order_Nth)
    return band_order_Nth, cycles_M, quality_factor_Q


def wavelet_NMQ_from_M(cycles_M: float) -> Tuple[float, float, float]:
    """
    For a specified M, estimate order N and recompute exact Q and number of cycles M from N

    :param quality_factor_Q: number of oscillations with significant amplitude in the frame
    :return: band order Nth (float), number of cycles M (float), quality factor Q (float)
    """
    quality_factor_Q = cycles_M/(2*np.sqrt(np.log(2)))  # Exact, from -3dB/half bit points
    band_order_Nth, cycles_M, quality_factor_Q = wavelet_NMQ_from_Q(quality_factor_Q)
    return band_order_Nth, cycles_M, quality_factor_Q


def wavelet_support(band_order_Nth : float,
                    scale_frequency_center_hz: float,
                    frequency_sample_rate_hz: float,
                    is_power_2: bool = True) -> Tuple[int, float, float]:
    """
    Compact support for Gabor wavelet

    :param band_order_Nth: Nth order of constant Q bands
    :param scale_frequency_center_hz: scale frequency in hz
    :param is_power_2: power of two approximation
    :return: number of points of duration (int), scale frame in seconds (float), scale of atom (float)
    """
    cycles_M, _ = wavelet_MQ_from_N(band_order_Nth)
    scale_frame_T_s = cycles_M / scale_frequency_center_hz   # Lifetime Tn, in seconds, M/fc
    scale_atom = frequency_sample_rate_hz*scale_frame_T_s / (2. * np.pi)  # Canonical Gabor atom scale
    nominal_points = np.floor(scale_frame_T_s*frequency_sample_rate_hz)

    floor_switch = 0.8  # Theoretical foundation, empirical implementation
    if is_power_2:
        duration_points_floor = 2**(np.floor(np.log2(nominal_points)))
        duration_points_ceil = 2**(np.ceil(np.log2(nominal_points)))
        if duration_points_floor < floor_switch*nominal_points:
            duration_points = int(duration_points_ceil)
        else:
            duration_points = int(duration_points_floor)
    else:
        duration_points = int(nominal_points)
    return duration_points, scale_frame_T_s, scale_atom


def from_duration(band_order_Nth : float,
                  sig_duration_s: float) -> Tuple[float, float]:
    """
    Calculate scale factor for time and frequency from signal duration

    :param band_order_Nth: Nth order of constant Q bands
    :param sig_duration_s: total signal duration in seconds
    :return: scale time in seconds, scale frequency in Hz
    """
    cycles_M, _ = wavelet_MQ_from_N(band_order_Nth)
    scale_time_s = sig_duration_s/cycles_M
    scale_frequency_hz = 1/scale_time_s
    return scale_time_s, scale_frequency_hz


def frequency_bands_g2f1(scale_order_input: float,
                         frequency_low_input: float,
                         frequency_sample_rate_input: float) -> Tuple[float, float, float, np.ndarray, np.ndarray,
                                                                      np.ndarray]:
    """
    As with band intervals, takes it all the way to Nyquist

    :param scale_order_input: Nth order specification
    :param frequency_low_input: lowest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :return: band order Nth, number of cycles M, quality factor, geometric center frequency, start frequency,
        end frequency
    """

    order_Nth, scale_base, scale_band_number, \
    frequency_ref, frequency_center_algebraic, frequency_center_geometric, \
    frequency_start, frequency_end = \
        band_frequencies_nyquist(frequency_order_input=scale_order_input,
                                 frequency_base_input=Slice.G2,
                                 frequency_ref_input=Slice.F1,
                                 frequency_low_input=frequency_low_input,
                                 frequency_sample_rate_input=frequency_sample_rate_input)
    cycles_M, quality_Q = wavelet_MQ_from_N(order_Nth)

    return order_Nth, cycles_M, quality_Q, frequency_center_geometric, frequency_start, frequency_end


def cqt_frequency_bands_g2f1(scale_order_input: float,
                             frequency_low_input: float,
                             frequency_sample_rate_input: float,
                             is_power_2: bool = True) -> Tuple[float, float, float, float, float]:
    """
    CQT frequency bands G2 - F1

    :param scale_order_input: Nth order specification
    :param frequency_low_input: lowest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :param is_power_2: power of two approximation
    :return: CQT points hop minimum value, frequency center minimum value in Hz, number of bins for scale,
        band order Nth, CQT maximum points per segment
    """
    order_Nth, cycles_M, quality_Q, frequency_hz_center, frequency_hz_start, frequency_hz_end = \
        frequency_bands_g2f1(scale_order_input, frequency_low_input, frequency_sample_rate_input)

    scale_number_bins_0 = int(len(frequency_hz_center))

    hann_bandwidth = 1.50018310546875
    _, q_gabor = wavelet_MQ_from_N(order_Nth)
    threshold = frequency_hz_center * (1 + 0.5 * hann_bandwidth / q_gabor)  # > frequency_sample_rate_hz / 2.0:

    # Remember frequency order is inverted because solution is in periods.
    idn = np.argmax(threshold < 0.9*frequency_sample_rate_input/2.0)
    scale_number_bins = int(len(frequency_hz_center[idn:]))

    frequency_hz_center_min = np.min(frequency_hz_center)
    cqt_points_hop_min = int(2**(np.floor(scale_number_bins/order_Nth)-1.))
    cqt_points_per_seg_max, _, _ = wavelet_support(order_Nth,
                                                   frequency_hz_center_min,
                                                   frequency_sample_rate_input,
                                                   is_power_2)
    return cqt_points_hop_min, frequency_hz_center_min, scale_number_bins, order_Nth, cqt_points_per_seg_max


def wavelet_scale_morlet2(band_order_Nth: float,
                          scale_frequency_center_hz: float,
                          frequency_sample_rate_hz: float) -> Tuple[Union[float, np.ndarray], Union[float, np.ndarray]]:
    """
    Nondimensional scale for canonical Morlet wavelet

    :param band_order_Nth: Nth order of constant Q bands
    :param scale_frequency_center_hz: scale frequency in hz
    :param frequency_sample_rate_hz: sample rate in hz
    :return: floats or np.ndarray
    """
    cycles_M, _ = wavelet_MQ_from_N(band_order_Nth)
    scale_atom = cycles_M*frequency_sample_rate_hz/scale_frequency_center_hz/(2. * np.pi)
    return scale_atom, cycles_M


def wavelet_inputs_morlet2(band_order_Nth: float,
                           time_s: np.ndarray,
                           offset_time_s: float,
                           scale_frequency_center_hz: float,
                           frequency_sample_rate_hz: float) -> Tuple[float, float, float]:
    """
    Adds scaled time-shifted time

    :param band_order_Nth: Nth order of constant Q bands
    :param time_s: array with timestamps of signal in seconds
    :param offset_time_s: offset time in seconds
    :param scale_frequency_center_hz: center frequency fc in Hz
    :param frequency_sample_rate_hz: sample rate of frequency in Hz
    :return: time shifted value (float), molet2 scale (float), cycles of M (float)
    """

    xtime_shifted = frequency_sample_rate_hz*(time_s-offset_time_s)
    scale_morlet2, cycles_M = wavelet_scale_morlet2(band_order_Nth, scale_frequency_center_hz, frequency_sample_rate_hz)

    return xtime_shifted, scale_morlet2, cycles_M

Global variables

var DEGREES_TO_KM

Standardized scales

Functions

def band_frequencies_low_high(frequency_order_input: float, frequency_base_input: float, frequency_ref_input: float, frequency_low_input: float, frequency_high_input: float, frequency_sample_rate_input: float) ‑> Tuple[float, float, numpy.ndarray, float, numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]

Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE HZ

:param frequency_order_input: Nth order :param frequency_base_input: G2 or G3 :param frequency_ref_input: reference frequency :param frequency_low_input: lowest frequency of interest :param frequency_high_input: highest frequency of interest :param frequency_sample_rate_input: sample rate :return:scale_order (Band order N > 1, defaults to 1.), scale_base (positive reference Base G > 1, defaults to G3), scale_band_number (Band number n), frequency_ref (reference frequency value), frequency_center_algebraic (Algebraic center of frequencies), frequency_center_geometric (Geometric center of frequencies), frequency_start (first frequency), frequency_end (last frequency)

Expand source code
def band_frequencies_low_high(frequency_order_input: float,
                              frequency_base_input: float,
                              frequency_ref_input: float,
                              frequency_low_input: float,
                              frequency_high_input: float,
                              frequency_sample_rate_input: float) -> Tuple[float, float, np.ndarray, float, np.ndarray,
                                                                           np.ndarray, np.ndarray, np.ndarray]:
    """
    Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE HZ

    :param frequency_order_input: Nth order
    :param frequency_base_input: G2 or G3
    :param frequency_ref_input: reference frequency
    :param frequency_low_input: lowest frequency of interest
    :param frequency_high_input: highest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :return:scale_order (Band order N > 1, defaults to 1.),
        scale_base (positive reference Base G > 1, defaults to G3),
        scale_band_number (Band number n),
        frequency_ref (reference frequency value),
        frequency_center_algebraic (Algebraic center of frequencies),
        frequency_center_geometric (Geometric center of frequencies),
        frequency_start (first frequency),
        frequency_end (last frequency)
    """

    scale_ref_input = 1/frequency_ref_input
    scale_nyquist_input = 2/frequency_sample_rate_input
    scale_low_input = 1/frequency_high_input
    if scale_low_input < scale_nyquist_input:
        scale_low_input = scale_nyquist_input
    scale_high_input = 1/frequency_low_input

    scale_order, scale_base, scale_band_number, \
    scale_ref, scale_center_algebraic, scale_center_geometric, \
    scale_start, scale_end = \
        band_intervals_periods(frequency_order_input, frequency_base_input,
                               scale_ref_input,
                               scale_low_input,
                               scale_high_input)
    frequency_ref = 1/scale_ref
    frequency_center_geometric = 1/scale_center_geometric
    frequency_end = 1/scale_start
    frequency_start = 1/scale_end
    frequency_center_algebraic = (frequency_end + frequency_start)/2.

    # Inherit the order, base, and band number
    return scale_order, scale_base, -scale_band_number,  frequency_ref, frequency_center_algebraic, \
           frequency_center_geometric, frequency_start, frequency_end
def band_frequencies_nyquist(frequency_order_input: float, frequency_base_input: float, frequency_ref_input: float, frequency_low_input: float, frequency_sample_rate_input: float) ‑> Tuple[float, float, numpy.ndarray, float, float, numpy.ndarray, numpy.ndarray, numpy.ndarray]

Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE HZ

:param frequency_order_input: Nth order :param frequency_base_input: G2 or G3 :param frequency_ref_input: reference frequency :param frequency_low_input: lowest frequency of interest :param frequency_sample_rate_input: sample rate :return: scale_order (Band order N > 1, defaults to 1.), scale_base (positive reference Base G > 1, defaults to G3), scale_band_number (Band number n), frequency_ref (reference frequency value), frequency_center_algebraic (Algebraic center of frequencies), frequency_center_geometric (Geometric center of frequencies), frequency_start (first frequency), frequency_end (last frequency)

Expand source code
def band_frequencies_nyquist(frequency_order_input: float,
                             frequency_base_input: float,
                             frequency_ref_input: float,
                             frequency_low_input: float,
                             frequency_sample_rate_input: float) -> Tuple[float, float, np.ndarray, float, float,
                                                                          np.ndarray, np.ndarray, np.ndarray]:
    """
    Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE HZ

    :param frequency_order_input: Nth order
    :param frequency_base_input: G2 or G3
    :param frequency_ref_input: reference frequency
    :param frequency_low_input: lowest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :return: scale_order (Band order N > 1, defaults to 1.),
        scale_base (positive reference Base G > 1, defaults to G3),
        scale_band_number (Band number n),
        frequency_ref (reference frequency value),
        frequency_center_algebraic (Algebraic center of frequencies),
        frequency_center_geometric (Geometric center of frequencies),
        frequency_start (first frequency),
        frequency_end (last frequency)

    """

    scale_ref_input = 1/frequency_ref_input
    scale_nyquist_input = 2/frequency_sample_rate_input
    scale_high_input = 1/frequency_low_input

    scale_order, scale_base, scale_band_number, \
    scale_ref, scale_center_algebraic, scale_center_geometric, \
    scale_start, scale_end = \
        band_intervals_periods(frequency_order_input, frequency_base_input,
                               scale_ref_input,
                               scale_nyquist_input, scale_high_input)
    frequency_ref = 1/scale_ref
    frequency_center_geometric = 1/scale_center_geometric
    frequency_end = 1/scale_start
    frequency_start = 1/scale_end
    frequency_center_algebraic = (frequency_end + frequency_start)/2.
    
    # Inherit the order, base, and band number
    return scale_order, scale_base, -scale_band_number, frequency_ref, frequency_center_algebraic, \
           frequency_center_geometric, frequency_start, frequency_end
def band_intervals_periods(scale_order_input: float, scale_base_input: float, scale_ref_input: float, scale_low_input: float, scale_high_input: float) ‑> Tuple[float, float, numpy.ndarray, float, numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]

Evaluate Standard Logarithmic Interval Scale Parameters using time scales in seconds If scales are provided as frequency, previous computations convert to time. Designed to take bappsband to just below Nyquist, within a band edge. ALWAYS CONVERT TO SECONDS Last updated: 20200905

Parameters

scale_order_input : float
Band order N, for ISO3 use N = 1.0 or 3.0 or 6.0 or 12.0 or 24.0
scale_base_input : float
reference base G; i.e. G3 = 10.**0.3 or G2 = 2.0
scale_ref_input : float
time reference: in seconds
scale_low_input : float
Lowest scale. If Nyquist scale, 2 * sample interval in seconds.
scale_high_input : float
Highest scale of interest in seconds

Returns

scale_order : float
Band order N > 1, defaults to 1.
scale_base : float
positive reference Base G > 1, defaults to G3
scale_ref : float
positive reference scale
scale_band_number : numpy ndarray
Band number n
scale_center_algebraic : numpy ndarray
Algebraic center band scale
scale_center_geometric : numpy ndarray
Geometric center band scale
scale_start : numpy ndarray
Lower band edge scale
scale_end : numpy ndarray
Upper band edge scale
Expand source code
def band_intervals_periods(scale_order_input: float,
                           scale_base_input: float,
                           scale_ref_input: float,
                           scale_low_input: float,
                           scale_high_input: float) -> Tuple[float, float, np.ndarray, float, np.ndarray,
                                                             np.ndarray, np.ndarray, np.ndarray]:
    """Evaluate Standard Logarithmic Interval Scale Parameters using time scales in seconds
    If scales are provided as frequency, previous computations convert to time.
    Designed to take bappsband to just below Nyquist, within a band edge.
    ALWAYS CONVERT TO SECONDS
    Last updated: 20200905

    Parameters
    ----------
    scale_order_input: float
        Band order N, for ISO3 use N = 1.0 or 3.0 or 6.0 or 12.0 or 24.0
    scale_base_input: float
        reference base G; i.e. G3 = 10.**0.3 or G2 = 2.0
    scale_ref_input: float
        time reference: in seconds
    scale_low_input: float
        Lowest scale. If Nyquist scale, 2 * sample interval in seconds.
    scale_high_input: float
        Highest scale of interest in seconds

    Returns
    -------
    scale_order: float
        Band order N > 1, defaults to 1.
    scale_base: float
        positive reference Base G > 1, defaults to G3
    scale_ref: float
        positive reference scale
    scale_band_number: numpy ndarray
        Band number n
    scale_center_algebraic: numpy ndarray
        Algebraic center band scale
    scale_center_geometric: numpy ndarray
        Geometric center band scale
    scale_start: numpy ndarray
        Lower band edge scale
    scale_end: numpy ndarray
        Upper band edge scale
    """
    # Initiate error handling, all inputs should be numeric, positive, and real
    # Need error check for string inputs
    # If not real and positive, make them so
    [scale_ref, scale_low, scale_high, scale_base, scale_order] = np.absolute(
        [scale_ref_input, scale_low_input, scale_high_input, scale_base_input, scale_order_input])

    # print('\nConstructing standard band intervals')
    # Check for compliance with ISO3 and/or ANSI S1.11 and for scale_order = 1, 3, 6, 12, and 24
    if scale_base == Slice.G3:
        pass
    elif scale_base == Slice.G2:
        pass
    elif scale_base < 1.:
        print('\nWARNING: Base must be greater than unity. Overriding to G = 2')
        scale_base = Slice.G2
    else:
        print('\nWARNING: Base is not ISO3 or ANSI S1.11 compliant')
        print(('Continuing With Non-standard base = ' + repr(scale_base) + ' ...'))

    # Check for compliance with ISO3 for scale_order = 1, 3, 6, 12, and 24
    # and the two 'special' orders 0.75 and 1.5
    valid_scale_orders = (0.75, 1, 1.5, 3, 6, 12, 24, 48)
    if scale_order in valid_scale_orders:
        pass
    elif scale_order < 0.75:
        print('Order must be greater than 0.75. Overriding to Order 1')
        scale_order = 1
    else:
        print(('\nWARNING: Recommend Orders ' + str(valid_scale_orders)))
        print(('Continuing With Non-standard Order = ' + repr(scale_order) + ' ...'))

    # Compute scale edge and width parameters
    scale_edge = scale_base ** (1.0 / (2.0 * scale_order))
    scale_width = scale_edge - 1.0 / scale_edge

    if scale_low < Slice.T0S:
        scale_low = Slice.T0S/scale_edge
    if scale_high < scale_low:
        print('\nWARNING: Upper scale must be larger than the lowest scale')
        print('Overriding to min = max/G  \n')
        scale_low = scale_high / scale_base
    if scale_high == scale_low:
        print('\nWARNING: Upper scale = lowest scale, returning closest band edges')
        scale_high *= scale_edge
        scale_low /= scale_edge

    # Max and min bands are computed relative to the center scale
    n_max = np.round(scale_order * np.log(scale_high / scale_ref) / np.log(scale_base))
    n_min = np.floor(scale_order * np.log(scale_low / scale_ref) / np.log(scale_base))

    # Evaluate min, ensure it stays below Nyquist period
    scale_center_n_min = scale_ref * np.power(scale_base, n_min/scale_order)
    if (scale_center_n_min < scale_low) or (scale_center_n_min/scale_edge < scale_low-EPSILON):
        n_min += 1

    # Check for band number anomalies
    if n_max < n_min:
        print('\nSPECMOD: Insufficient bandwidth for Nth band specification')
        print(('Minimum scaled bandwidth (scale_high - scale_low)/scale_center = ' + repr(scale_width) + '\n'))
        print('Correct scale High/Low input parameters \n')
        print('Apply one order  \n')
        n_max = np.floor(np.log10(scale_high) / np.log10(scale_base))
        n_min = n_max - scale_order

    # Band number array for Nth octave
    scale_band_number = np.arange(n_min, n_max + 1)

    # Compute exact, evenly (log) distributed, constant Q,
    # Nth octave center and band edge frequencies
    scale_band_exponent = scale_band_number / scale_order

    scale_center_geometric = scale_ref * np.power(scale_base * np.ones(scale_band_number.shape), scale_band_exponent)
    scale_start = scale_center_geometric / scale_edge
    scale_end = scale_center_geometric * scale_edge
    # The spectrum is centered on the algebraic center scale
    scale_center_algebraic = (scale_start+scale_end)/2.

    return scale_order, scale_base, scale_band_number,  scale_ref, scale_center_algebraic, scale_center_geometric, \
           scale_start, scale_end
def band_periods_nyquist(scale_order_input: float, scale_base_input: float, scale_ref_input: float, scale_sample_interval_input: float, scale_high_input: float) ‑> Tuple[float, float, numpy.ndarray, float, numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]

Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE SECONDS

Parameters

scale_order_input : float
Band order N, for ISO3 use N = 1.0 or 3.0 or 6.0 or 12.0 or 24.0
scale_base_input : float
reference base G; i.e. G3 = 10.**0.3 or G2 = 2.0
scale_ref_input : float
time reference: in seconds
scale_sample_interval_input : float
Sample interval for scale: float
scale_high_input : float
Highest scale of interest in seconds

Returns

scale_order : float
Band order N > 1, defaults to 1.
scale_base : float
positive reference Base G > 1, defaults to G3
scale_ref : float
positive reference scale
scale_band_number : numpy ndarray
Band number n
scale_center_algebraic : numpy ndarray
Algebraic center of band scale
scale_center_geometric : numpy ndarray
Geometric center of band scale
scale_start : numpy ndarray
Lower band edge scale
scale_end : numpy ndarray
Upper band edge scale
Expand source code
def band_periods_nyquist(scale_order_input: float,
                         scale_base_input: float,
                         scale_ref_input: float,
                         scale_sample_interval_input: float,
                         scale_high_input: float) -> Tuple[float, float, np.ndarray, float, np.ndarray,
                                                           np.ndarray, np.ndarray, np.ndarray]:
    """Evaluate Standard Logarithmic Interval Time Parameters: ALWAYS USE SECONDS

    Parameters
    ----------
    scale_order_input: float
        Band order N, for ISO3 use N = 1.0 or 3.0 or 6.0 or 12.0 or 24.0
    scale_base_input: float
        reference base G; i.e. G3 = 10.**0.3 or G2 = 2.0
    scale_ref_input: float
        time reference: in seconds
    scale_sample_interval_input: float
        Sample interval for scale: float
    scale_high_input: float
        Highest scale of interest in seconds

    Returns
    -------
    scale_order: float
        Band order N > 1, defaults to 1.
    scale_base: float
        positive reference Base G > 1, defaults to G3
    scale_ref: float
        positive reference scale
    scale_band_number: numpy ndarray
        Band number n
    scale_center_algebraic: numpy ndarray
        Algebraic center of band scale
    scale_center_geometric: numpy ndarray
        Geometric center of band scale
    scale_start: numpy ndarray
        Lower band edge scale
    scale_end: numpy ndarray
        Upper band edge scale
    """
    scale_nyquist_input = 2*scale_sample_interval_input
    scale_order, scale_base, scale_band_number, scale_ref, scale_center_algebraic, scale_center_geometric, scale_start, \
    scale_end = band_intervals_periods(scale_order_input=scale_order_input,
                                       scale_base_input=scale_base_input,
                                       scale_ref_input=scale_ref_input,
                                       scale_low_input=scale_nyquist_input,
                                       scale_high_input=scale_high_input)

    return scale_order, scale_base, scale_band_number, scale_ref, scale_center_algebraic, scale_center_geometric, \
           scale_start, scale_end
def cqt_frequency_bands_g2f1(scale_order_input: float, frequency_low_input: float, frequency_sample_rate_input: float, is_power_2: bool = True) ‑> Tuple[float, float, float, float, float]

CQT frequency bands G2 - F1

:param scale_order_input: Nth order specification :param frequency_low_input: lowest frequency of interest :param frequency_sample_rate_input: sample rate :param is_power_2: power of two approximation :return: CQT points hop minimum value, frequency center minimum value in Hz, number of bins for scale, band order Nth, CQT maximum points per segment

Expand source code
def cqt_frequency_bands_g2f1(scale_order_input: float,
                             frequency_low_input: float,
                             frequency_sample_rate_input: float,
                             is_power_2: bool = True) -> Tuple[float, float, float, float, float]:
    """
    CQT frequency bands G2 - F1

    :param scale_order_input: Nth order specification
    :param frequency_low_input: lowest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :param is_power_2: power of two approximation
    :return: CQT points hop minimum value, frequency center minimum value in Hz, number of bins for scale,
        band order Nth, CQT maximum points per segment
    """
    order_Nth, cycles_M, quality_Q, frequency_hz_center, frequency_hz_start, frequency_hz_end = \
        frequency_bands_g2f1(scale_order_input, frequency_low_input, frequency_sample_rate_input)

    scale_number_bins_0 = int(len(frequency_hz_center))

    hann_bandwidth = 1.50018310546875
    _, q_gabor = wavelet_MQ_from_N(order_Nth)
    threshold = frequency_hz_center * (1 + 0.5 * hann_bandwidth / q_gabor)  # > frequency_sample_rate_hz / 2.0:

    # Remember frequency order is inverted because solution is in periods.
    idn = np.argmax(threshold < 0.9*frequency_sample_rate_input/2.0)
    scale_number_bins = int(len(frequency_hz_center[idn:]))

    frequency_hz_center_min = np.min(frequency_hz_center)
    cqt_points_hop_min = int(2**(np.floor(scale_number_bins/order_Nth)-1.))
    cqt_points_per_seg_max, _, _ = wavelet_support(order_Nth,
                                                   frequency_hz_center_min,
                                                   frequency_sample_rate_input,
                                                   is_power_2)
    return cqt_points_hop_min, frequency_hz_center_min, scale_number_bins, order_Nth, cqt_points_per_seg_max
def frequency_bands_g2f1(scale_order_input: float, frequency_low_input: float, frequency_sample_rate_input: float) ‑> Tuple[float, float, float, numpy.ndarray, numpy.ndarray, numpy.ndarray]

As with band intervals, takes it all the way to Nyquist

:param scale_order_input: Nth order specification :param frequency_low_input: lowest frequency of interest :param frequency_sample_rate_input: sample rate :return: band order Nth, number of cycles M, quality factor, geometric center frequency, start frequency, end frequency

Expand source code
def frequency_bands_g2f1(scale_order_input: float,
                         frequency_low_input: float,
                         frequency_sample_rate_input: float) -> Tuple[float, float, float, np.ndarray, np.ndarray,
                                                                      np.ndarray]:
    """
    As with band intervals, takes it all the way to Nyquist

    :param scale_order_input: Nth order specification
    :param frequency_low_input: lowest frequency of interest
    :param frequency_sample_rate_input: sample rate
    :return: band order Nth, number of cycles M, quality factor, geometric center frequency, start frequency,
        end frequency
    """

    order_Nth, scale_base, scale_band_number, \
    frequency_ref, frequency_center_algebraic, frequency_center_geometric, \
    frequency_start, frequency_end = \
        band_frequencies_nyquist(frequency_order_input=scale_order_input,
                                 frequency_base_input=Slice.G2,
                                 frequency_ref_input=Slice.F1,
                                 frequency_low_input=frequency_low_input,
                                 frequency_sample_rate_input=frequency_sample_rate_input)
    cycles_M, quality_Q = wavelet_MQ_from_N(order_Nth)

    return order_Nth, cycles_M, quality_Q, frequency_center_geometric, frequency_start, frequency_end
def from_duration(band_order_Nth: float, sig_duration_s: float) ‑> Tuple[float, float]

Calculate scale factor for time and frequency from signal duration

:param band_order_Nth: Nth order of constant Q bands :param sig_duration_s: total signal duration in seconds :return: scale time in seconds, scale frequency in Hz

Expand source code
def from_duration(band_order_Nth : float,
                  sig_duration_s: float) -> Tuple[float, float]:
    """
    Calculate scale factor for time and frequency from signal duration

    :param band_order_Nth: Nth order of constant Q bands
    :param sig_duration_s: total signal duration in seconds
    :return: scale time in seconds, scale frequency in Hz
    """
    cycles_M, _ = wavelet_MQ_from_N(band_order_Nth)
    scale_time_s = sig_duration_s/cycles_M
    scale_frequency_hz = 1/scale_time_s
    return scale_time_s, scale_frequency_hz
def musical_scale_hz()

Returns frequencies for equal tempered scale base2, ref = 440 Hz, 12th octaves

Expand source code
def musical_scale_hz():
    """
    Returns frequencies for equal tempered scale
    base2, ref = 440 Hz, 12th octaves
    """
    return band_frequencies_nyquist(frequency_order_input=12,
                                    frequency_base_input=2,
                                    frequency_ref_input=440,
                                    frequency_low_input=16.35,
                                    frequency_sample_rate_input=48000)
def planck_scale_s(scale_order: float) ‑> Tuple[float, float, float, float]

Calculate Planck scale

:param scale_order: scale order :return: center in seconds, minimum in seconds, maximum in seconds, quality factor Q

Expand source code
def planck_scale_s(scale_order: float) -> Tuple[float, float, float, float]:
    """
    Calculate Planck scale

    :param scale_order: scale order
    :return: center in seconds, minimum in seconds, maximum in seconds, quality factor Q
    """
    # Assumes base 2, Slice.G2
    cycles_M, quality_factor_Q = wavelet_MQ_from_N(scale_order)
    scale_edge = Slice.G2 ** (1.0 / (2.0 * scale_order))
    # # Q = center/bandwidth
    # planck_scale_zero_s = planck_scale_bandwidth_s*quality_factor_Q
    # Must be greater than Planck scale
    planck_scale_center_s = Slice.T0S
    # Smallest scale
    planck_scale_min_s = planck_scale_center_s/scale_edge
    planck_scale_max_s = planck_scale_center_s*scale_edge
    return planck_scale_center_s, planck_scale_min_s, planck_scale_max_s, quality_factor_Q
def wavelet_MQ_from_N(band_order_Nth: float) ‑> Tuple[float, float]

Compute the quality factor Q and multiplier M for a specified band order N N is THE quantization parameter for the binary constant Q wavelet filters

:param band_order_Nth: Band order, must be > 0.75 or reverts to N=3 :return: float, float

Expand source code
def wavelet_MQ_from_N(band_order_Nth: float) -> Tuple[float, float]:
    """
    Compute the quality factor Q and multiplier M for a specified band order N
    N is THE quantization parameter for the binary constant Q wavelet filters

    :param band_order_Nth: Band order, must be > 0.75 or reverts to N=3
    :return: float, float
    """
    if band_order_Nth < 0.7:
        print('N<0.7 specified, using N = ', 3)
        band_order_Nth = 3.
    order_bandedge = 2 ** (1. / 2. / band_order_Nth)  # kN in Garces 2013
    order_scaled_bandwidth = order_bandedge - 1. / order_bandedge
    quality_factor_Q = 1./order_scaled_bandwidth  # Exact for Nth octave bands
    cycles_M = quality_factor_Q*2*np.sqrt(np.log(2))  # Exact, from -3dB points
    return cycles_M, quality_factor_Q
def wavelet_NMQ_from_M(cycles_M: float) ‑> Tuple[float, float, float]

For a specified M, estimate order N and recompute exact Q and number of cycles M from N

:param quality_factor_Q: number of oscillations with significant amplitude in the frame :return: band order Nth (float), number of cycles M (float), quality factor Q (float)

Expand source code
def wavelet_NMQ_from_M(cycles_M: float) -> Tuple[float, float, float]:
    """
    For a specified M, estimate order N and recompute exact Q and number of cycles M from N

    :param quality_factor_Q: number of oscillations with significant amplitude in the frame
    :return: band order Nth (float), number of cycles M (float), quality factor Q (float)
    """
    quality_factor_Q = cycles_M/(2*np.sqrt(np.log(2)))  # Exact, from -3dB/half bit points
    band_order_Nth, cycles_M, quality_factor_Q = wavelet_NMQ_from_Q(quality_factor_Q)
    return band_order_Nth, cycles_M, quality_factor_Q
def wavelet_NMQ_from_Q(quality_factor_Q: float) ‑> Tuple[float, float, float]

For a specified Q, estimate order N and recompute exact Q and number of cycles M from N

:param quality_factor_Q: number of oscillations with significant amplitude in the frame :return: band order Nth (float), number of cycles M (float), quality factor Q (float)

Expand source code
def wavelet_NMQ_from_Q(quality_factor_Q: float) -> Tuple[float, float, float]:
    """
    For a specified Q, estimate order N and recompute exact Q and number of cycles M from N

    :param quality_factor_Q: number of oscillations with significant amplitude in the frame
    :return: band order Nth (float), number of cycles M (float), quality factor Q (float)
    """
    band_order_Nth = quality_factor_Q/np.sqrt(2)  # Approximate
    cycles_M, quality_factor_Q = wavelet_MQ_from_N(band_order_Nth)
    return band_order_Nth, cycles_M, quality_factor_Q
def wavelet_inputs_morlet2(band_order_Nth: float, time_s: numpy.ndarray, offset_time_s: float, scale_frequency_center_hz: float, frequency_sample_rate_hz: float) ‑> Tuple[float, float, float]

Adds scaled time-shifted time

:param band_order_Nth: Nth order of constant Q bands :param time_s: array with timestamps of signal in seconds :param offset_time_s: offset time in seconds :param scale_frequency_center_hz: center frequency fc in Hz :param frequency_sample_rate_hz: sample rate of frequency in Hz :return: time shifted value (float), molet2 scale (float), cycles of M (float)

Expand source code
def wavelet_inputs_morlet2(band_order_Nth: float,
                           time_s: np.ndarray,
                           offset_time_s: float,
                           scale_frequency_center_hz: float,
                           frequency_sample_rate_hz: float) -> Tuple[float, float, float]:
    """
    Adds scaled time-shifted time

    :param band_order_Nth: Nth order of constant Q bands
    :param time_s: array with timestamps of signal in seconds
    :param offset_time_s: offset time in seconds
    :param scale_frequency_center_hz: center frequency fc in Hz
    :param frequency_sample_rate_hz: sample rate of frequency in Hz
    :return: time shifted value (float), molet2 scale (float), cycles of M (float)
    """

    xtime_shifted = frequency_sample_rate_hz*(time_s-offset_time_s)
    scale_morlet2, cycles_M = wavelet_scale_morlet2(band_order_Nth, scale_frequency_center_hz, frequency_sample_rate_hz)

    return xtime_shifted, scale_morlet2, cycles_M
def wavelet_scale_morlet2(band_order_Nth: float, scale_frequency_center_hz: float, frequency_sample_rate_hz: float) ‑> Tuple[Union[float, numpy.ndarray], Union[float, numpy.ndarray]]

Nondimensional scale for canonical Morlet wavelet

:param band_order_Nth: Nth order of constant Q bands :param scale_frequency_center_hz: scale frequency in hz :param frequency_sample_rate_hz: sample rate in hz :return: floats or np.ndarray

Expand source code
def wavelet_scale_morlet2(band_order_Nth: float,
                          scale_frequency_center_hz: float,
                          frequency_sample_rate_hz: float) -> Tuple[Union[float, np.ndarray], Union[float, np.ndarray]]:
    """
    Nondimensional scale for canonical Morlet wavelet

    :param band_order_Nth: Nth order of constant Q bands
    :param scale_frequency_center_hz: scale frequency in hz
    :param frequency_sample_rate_hz: sample rate in hz
    :return: floats or np.ndarray
    """
    cycles_M, _ = wavelet_MQ_from_N(band_order_Nth)
    scale_atom = cycles_M*frequency_sample_rate_hz/scale_frequency_center_hz/(2. * np.pi)
    return scale_atom, cycles_M
def wavelet_support(band_order_Nth: float, scale_frequency_center_hz: float, frequency_sample_rate_hz: float, is_power_2: bool = True) ‑> Tuple[int, float, float]

Compact support for Gabor wavelet

:param band_order_Nth: Nth order of constant Q bands :param scale_frequency_center_hz: scale frequency in hz :param is_power_2: power of two approximation :return: number of points of duration (int), scale frame in seconds (float), scale of atom (float)

Expand source code
def wavelet_support(band_order_Nth : float,
                    scale_frequency_center_hz: float,
                    frequency_sample_rate_hz: float,
                    is_power_2: bool = True) -> Tuple[int, float, float]:
    """
    Compact support for Gabor wavelet

    :param band_order_Nth: Nth order of constant Q bands
    :param scale_frequency_center_hz: scale frequency in hz
    :param is_power_2: power of two approximation
    :return: number of points of duration (int), scale frame in seconds (float), scale of atom (float)
    """
    cycles_M, _ = wavelet_MQ_from_N(band_order_Nth)
    scale_frame_T_s = cycles_M / scale_frequency_center_hz   # Lifetime Tn, in seconds, M/fc
    scale_atom = frequency_sample_rate_hz*scale_frame_T_s / (2. * np.pi)  # Canonical Gabor atom scale
    nominal_points = np.floor(scale_frame_T_s*frequency_sample_rate_hz)

    floor_switch = 0.8  # Theoretical foundation, empirical implementation
    if is_power_2:
        duration_points_floor = 2**(np.floor(np.log2(nominal_points)))
        duration_points_ceil = 2**(np.ceil(np.log2(nominal_points)))
        if duration_points_floor < floor_switch*nominal_points:
            duration_points = int(duration_points_ceil)
        else:
            duration_points = int(duration_points_floor)
    else:
        duration_points = int(nominal_points)
    return duration_points, scale_frame_T_s, scale_atom

Classes

class Slice

Constants for slice calculations, supersedes inferno/slice

Expand source code
class Slice:
    """
    Constants for slice calculations, supersedes inferno/slice
    """
    # Constant Q Base
    G2 = 2.  # Octaves
    G3 = 10. ** 0.3  # Reconciles base2 and base10
    # Time
    T_PLANCK = 5.4E-44  # 2.**(-144)   Planck time in seconds
    T0S = 1E-42  # Universal Scale
    T1S = 1.    # 1 second
    T100S = 100.  # 1 hectosecond, IMS low band edge
    T1000S = 1000.  # 1 kiloseconds = 1 mHz
    T1M = 60.  # 1 minute in seconds
    T1H = T1M*60.  # 1 hour in seconds
    T1D = T1H*24.   # 1 day in seconds
    TU = 2.**58  # Estimated age of the known universe in seconds
    # Frequency
    F1 = 1.  # 1 Hz
    F1000 = 1000.  # 1 kHz
    F0 = 1.E42  # 1/Universal Scale
    FU = 2.**-58  # Estimated age of the universe in Hz
    # Pressure
    PREF_KPA = 101.325  # sea level pressure, kPa
    PREF_PA = 10132500.  # sea level pressure, kPa

Class variables

var F0
var F1
var F1000
var FU
var G2
var G3
var PREF_KPA
var PREF_PA
var T0S
var T1000S
var T100S
var T1D
var T1H
var T1M
var T1S
var TU
var T_PLANCK