pre-processing of the tau-list given by the user (Helper function)

    Does sanity checks, sorts data, removes duplicates and invalid values.
    Generates a tau-list based on keywords 'all', 'decade', 'octave'.
    Uses 'octave' by default if no taus= argument is given.

    Parameters
    ----------
    data: np.array
        data array
    rate: float
        Sample rate of data in Hz. Time interval between measurements
        is 1/rate seconds.
    taus: np.array
        Array of tau values for which to compute measurement.
        Alternatively one of the keywords: "all", "octave", "decade".
        Defaults to "octave" if omitted.
    v:
        verbose output if True
    even:
        require even m, where tau=m*tau0, for Theo1 statistic
    maximum_m:
        limit m, where tau=m*tau0, to this value.
        used by mtotdev() and htotdev() to limit maximum tau.

    Returns
    -------
    (data, m, taus): tuple
        List of computed values
    data: np.array
        Data
    m: np.array
        Tau in units of data points
    taus: np.array
        Cleaned up list of tau values

def tau_generator(data, rate, taus=None, v=False, even=False, maximum_m=-1):
    """ pre-processing of the tau-list given by the user (Helper function)

    Does sanity checks, sorts data, removes duplicates and invalid values.
    Generates a tau-list based on keywords 'all', 'decade', 'octave'.
    Uses 'octave' by default if no taus= argument is given.

    Parameters
    ----------
    data: np.array
        data array
    rate: float
        Sample rate of data in Hz. Time interval between measurements
        is 1/rate seconds.
    taus: np.array
        Array of tau values for which to compute measurement.
        Alternatively one of the keywords: "all", "octave", "decade".
        Defaults to "octave" if omitted.
    v:
        verbose output if True
    even:
        require even m, where tau=m*tau0, for Theo1 statistic
    maximum_m:
        limit m, where tau=m*tau0, to this value.
        used by mtotdev() and htotdev() to limit maximum tau.

    Returns
    -------
    (data, m, taus): tuple
        List of computed values
    data: np.array
        Data
    m: np.array
        Tau in units of data points
    taus: np.array
        Cleaned up list of tau values
    """


    if rate == 0:
        raise RuntimeError("Warning! rate==0")

    if taus is None: # empty or no tau-list supplied
        taus = "octave" # default to octave
    elif isinstance(taus, list) and taus == []:
        taus = "octave"

    if taus is "all":
        taus = (1.0/rate)*np.linspace(1.0, len(data), len(data))
    elif taus is "octave":
        maxn = np.floor(np.log2(len(data)))
        taus = (1.0/rate)*np.logspace(0, maxn, maxn+1, base=2.0)
    elif taus is "decade": # 1, 2, 4, 10, 20, 40, spacing similar to Stable32
        maxn = np.floor(np.log10(len(data)))
        taus = []
        for k in range(int(maxn+1)):
            taus.append(1.0*(1.0/rate)*pow(10.0, k))
            taus.append(2.0*(1.0/rate)*pow(10.0, k))
            taus.append(4.0*(1.0/rate)*pow(10.0, k))

    data, taus = np.array(data), np.array(taus)
    rate = float(rate)
    m = [] # integer averaging factor. tau = m*tau0

    if maximum_m == -1: # if no limit given
        maximum_m = len(data)
    # FIXME: should we use a "stop-ratio" like Stable32
    # found in Table III, page 9 of "Evolution of frequency stability analysis software"
    # max(AF) = len(phase)/stop_ratio, where 
    # function  stop_ratio
    # adev      5
    # oadev     4
    # mdev      4
    # tdev      4
    # hdev      5
    # ohdev     4
    # totdev    2
    # tierms    4
    # htotdev   3
    # mtie      2
    # theo1     1
    # theoH     1
    # mtotdev   2
    # ttotdev   2

    taus_valid1 = taus < (1 / float(rate)) * float(len(data))
    taus_valid2 = taus > 0
    taus_valid3 = taus <= (1 / float(rate)) * float(maximum_m)
    taus_valid = taus_valid1 & taus_valid2 & taus_valid3
    m = np.floor(taus[taus_valid] * rate)
    m = m[m != 0]       # m is tau in units of datapoints
    m = np.unique(m)    # remove duplicates and sort

    if v:
        print("tau_generator: ", m)

    if len(m) == 0:
        print("Warning: sanity-check on tau failed!")
        print("   len(data)=", len(data), " rate=", rate, "taus= ", taus)

    taus2 = m / float(rate)

    if even: # used by Theo1
        m_even_mask = ((m % 2) == 0)
        m = m[m_even_mask]
        taus2 = taus2[m_even_mask]

    return data, m, taus2