# Path: pactools/utils/maths.py
# def square(c):
#     """square a complex array"""
#     return np.real(c * np.conjugate(c))
# 
# def is_power2(num):
#     """Test if num is a power of 2. (int -> bool)"""
#     num = int(num)
#     return num != 0 and ((num & (num - 1)) == 0)
# 
# def prime_factors(num):
#     """
#     Decomposition in prime factor.
#     Used to find signal length that speed up Hilbert transform.
# 
#     Parameters
#     ----------
#     num : int
# 
#     Returns
#     -------
#     decomposition : list of int
#         List of prime factors sorted by ascending order
#     """
#     assert num > 0
#     assert isinstance(num, int)
# 
#     decomposition = []
#     for i in chain([2], range(3, int(np.sqrt(num)) + 1, 2)):
#         while num % i == 0:
#             num = num // i
#             decomposition.append(i)
#         if num == 1:
#             break
#     if num != 1:
#         decomposition.append(num)
#     return decomposition
# 
# def compute_n_fft(signals):
#     """
#     Compute the number of element in the FFT to have a good prime
#     decomposition, for hilbert filter.
#     Parameters
#     ----------
#     signals : array
# 
#     Returns
#     -------
#     n_fft: integer >= signals.shape[-1]
#     """
#     n_fft = signals.shape[-1]
#     while prime_factors(n_fft)[-1] > 20:
#         n_fft += 1
#     return n_fft
# 
# def next_power2(num):
#     """Compute the smallest power of 2 >= to num.(float -> int)"""
#     return 2 ** int(np.ceil(np.log2(num)))
# 
# Path: pactools/utils/viz.py
# def compute_vmin_vmax(spec, vmin=None, vmax=None, tick=0.01, percentile=1):
#     """compute automatic scale for plotting `spec`"""
#     if percentile > 100:
#         percentile = 100
#     if percentile < 0:
#         percentile = 0
# 
#     if vmin is None:
#         vmin = np.floor(np.percentile(spec, percentile) / tick) * tick
#     if vmax is None:
#         vmax = np.ceil(np.percentile(spec, 100 - percentile) / tick) * tick
# 
#     return vmin, vmax


import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from scipy.linalg import hankel
from scipy.signal import hilbert
from .maths import square, is_power2, prime_factors, compute_n_fft, next_power2
from .viz import compute_vmin_vmax
    fs : float
        Sampling frequency

    donorm : boolean
        If True, the amplitude is normalized

    """
    def __init__(self, block_length=1024, fft_length=None, step=None,
                 wfunc=np.hamming, fs=1., donorm=True):

        self.block_length = block_length
        self.fft_length = fft_length
        self.step = step
        self.wfunc = wfunc
        self.fs = fs
        self.donorm = donorm
        self.psd = []

    def check_params(self):
        # block_length
        if self.block_length <= 0:
            raise ValueError('Block length is negative: %s' %
                             (self.block_length, ))
        self.block_length = int(self.block_length)

        # fft_length
        if self.fft_length is None:
            fft_length = next_power2(self.block_length)
        else:
            fft_length = int(self.fft_length)

# Path: pactools/utils/maths.py
# def square(c):
#     """square a complex array"""
#     return np.real(c * np.conjugate(c))
# 
# def is_power2(num):
#     """Test if num is a power of 2. (int -> bool)"""
#     num = int(num)
#     return num != 0 and ((num & (num - 1)) == 0)
# 
# def prime_factors(num):
#     """
#     Decomposition in prime factor.
#     Used to find signal length that speed up Hilbert transform.
# 
#     Parameters
#     ----------
#     num : int
# 
#     Returns
#     -------
#     decomposition : list of int
#         List of prime factors sorted by ascending order
#     """
#     assert num > 0
#     assert isinstance(num, int)
# 
#     decomposition = []
#     for i in chain([2], range(3, int(np.sqrt(num)) + 1, 2)):
#         while num % i == 0:
#             num = num // i
#             decomposition.append(i)
#         if num == 1:
#             break
#     if num != 1:
#         decomposition.append(num)
#     return decomposition
# 
# def compute_n_fft(signals):
#     """
#     Compute the number of element in the FFT to have a good prime
#     decomposition, for hilbert filter.
#     Parameters
#     ----------
#     signals : array
# 
#     Returns
#     -------
#     n_fft: integer >= signals.shape[-1]
#     """
#     n_fft = signals.shape[-1]
#     while prime_factors(n_fft)[-1] > 20:
#         n_fft += 1
#     return n_fft
# 
# def next_power2(num):
#     """Compute the smallest power of 2 >= to num.(float -> int)"""
#     return 2 ** int(np.ceil(np.log2(num)))
# 
# Path: pactools/utils/viz.py
# def compute_vmin_vmax(spec, vmin=None, vmax=None, tick=0.01, percentile=1):
#     """compute automatic scale for plotting `spec`"""
#     if percentile > 100:
#         percentile = 100
#     if percentile < 0:
#         percentile = 0
# 
#     if vmin is None:
#         vmin = np.floor(np.percentile(spec, percentile) / tick) * tick
#     if vmax is None:
#         vmax = np.ceil(np.percentile(spec, 100 - percentile) / tick) * tick
# 
#     return vmin, vmax


# Path: pactools/utils/spectrum.py
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from scipy.linalg import hankel
from scipy.signal import hilbert
from .maths import square, is_power2, prime_factors, compute_n_fft, next_power2
from .viz import compute_vmin_vmax

    fs : float
        Sampling frequency

    donorm : boolean
        If True, the amplitude is normalized

    """
    def __init__(self, block_length=1024, fft_length=None, step=None,
                 wfunc=np.hamming, fs=1., donorm=True):

        self.block_length = block_length
        self.fft_length = fft_length
        self.step = step
        self.wfunc = wfunc
        self.fs = fs
        self.donorm = donorm
        self.psd = []

    def check_params(self):
        # block_length
        if self.block_length <= 0:
            raise ValueError('Block length is negative: %s' %
                             (self.block_length, ))
        self.block_length = int(self.block_length)

        # fft_length
        if self.fft_length is None:
            fft_length = next_power2(self.block_length)
        else:
            fft_length = int(self.fft_length)

        if not is_power2(fft_length):