@cache(level=<NUM_LIT:30>)<EOL>def pcen(S, sr=<NUM_LIT>, hop_length=<NUM_LIT>, gain=<NUM_LIT>, bias=<NUM_LIT:2>, power=<NUM_LIT:0.5>,<EOL>time_constant=<NUM_LIT>, eps=<NUM_LIT>, b=None, max_size=<NUM_LIT:1>, ref=None,<EOL>axis=-<NUM_LIT:1>, max_axis=None, zi=None, return_zf=False):
if power <= <NUM_LIT:0>:<EOL><INDENT>raise ParameterError('<STR_LIT>'.format(power))<EOL><DEDENT>if gain < <NUM_LIT:0>:<EOL><INDENT>raise ParameterError('<STR_LIT>'.format(gain))<EOL><DEDENT>if bias < <NUM_LIT:0>:<EOL><INDENT>raise ParameterError('<STR_LIT>'.format(bias))<EOL><DEDENT>if eps <= <NUM_LIT:0>:<EOL><INDENT>raise ParameterError('<STR_LIT>'.format(eps))<EOL><DEDENT>if time_constant <= <NUM_LIT:0>:<EOL><INDENT>raise ParameterError('<STR_LIT>'.format(time_constant))<EOL><DEDENT>if max_size < <NUM_LIT:1> or not isinstance(max_size, int):<EOL><INDENT>raise ParameterError('<STR_LIT>'.format(max_size))<EOL><DEDENT>if b is None:<EOL><INDENT>t_frames = time_constant * sr / float(hop_length)<EOL>b = (np.sqrt(<NUM_LIT:1> + <NUM_LIT:4> * t_frames**<NUM_LIT:2>) - <NUM_LIT:1>) / (<NUM_LIT:2> * t_frames**<NUM_LIT:2>)<EOL><DEDENT>if not <NUM_LIT:0> <= b <= <NUM_LIT:1>:<EOL><INDENT>raise ParameterError('<STR_LIT>'.format(b))<EOL><DEDENT>if np.issubdtype(S.dtype, np.complexfloating):<EOL><INDENT>warnings.warn('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>S = np.abs(S)<EOL><DEDENT>if ref is None:<EOL><INDENT>if max_size == <NUM_LIT:1>:<EOL><INDENT>ref = S<EOL><DEDENT>elif S.ndim == <NUM_LIT:1>:<EOL><INDENT>raise ParameterError('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>if max_axis is None:<EOL><INDENT>if S.ndim != <NUM_LIT:2>:<EOL><INDENT>raise ParameterError('<STR_LIT>'<EOL>'<STR_LIT>'.format(S.ndim))<EOL><DEDENT>max_axis = np.mod(<NUM_LIT:1> - axis, <NUM_LIT:2>)<EOL><DEDENT>ref = scipy.ndimage.maximum_filter1d(S, max_size, axis=max_axis)<EOL><DEDENT><DEDENT>if zi is None:<EOL><INDENT>shape = tuple([<NUM_LIT:1>] * ref.ndim)<EOL>zi = np.empty(shape)<EOL>zi[:] = scipy.signal.lfilter_zi([b], [<NUM_LIT:1>, b - <NUM_LIT:1>])[:]<EOL><DEDENT>S_smooth, zf = scipy.signal.lfilter([b], [<NUM_LIT:1>, b - <NUM_LIT:1>], ref, zi=zi,<EOL>axis=axis)<EOL>smooth = np.exp(-gain * (np.log(eps) + np.log1p(S_smooth / eps)))<EOL>S_out = (S * smooth + bias)**power - bias**power<EOL>if return_zf:<EOL><INDENT>return S_out, zf<EOL><DEDENT>else:<EOL><INDENT>return S_out<EOL><DEDENT>
Per-channel energy normalization (PCEN) [1]_

    This function normalizes a time-frequency representation `S` by
    performing automatic gain control, followed by nonlinear compression:

        P[f, t] = (S / (eps + M[f, t])**gain + bias)**power - bias**power

    where `M` is the result of applying a low-pass, temporal IIR filter
    to `S`:

        M[f, t] = (1 - b) * M[f, t - 1] + b * S[f, t]

    If `b` is not provided, it is calculated as:

        b = (sqrt(1 + 4* T**2) - 1) / (2 * T**2)

    where `T = time_constant * sr / hop_length`.

    This normalization is designed to suppress background noise and
    emphasize foreground signals, and can be used as an alternative to
    decibel scaling (`amplitude_to_db`).

    This implementation also supports smoothing across frequency bins
    by specifying `max_size > 1`.  If this option is used, the filtered
    spectrogram `M` is computed as

        M[f, t] = (1 - b) * M[f, t - 1] + b * R[f, t]

    where `R` has been max-filtered along the frequency axis, similar to
    the SuperFlux algorithm implemented in `onset.onset_strength`:

        R[f, t] = max(S[f - max_size//2: f + max_size//2, t])

    This can be used to perform automatic gain control on signals that cross
    or span multiple frequency bans, which may be desirable for spectrograms
    with high frequency resolution.

    .. [1] Wang, Y., Getreuer, P., Hughes, T., Lyon, R. F., & Saurous, R. A.
       (2017, March). Trainable frontend for robust and far-field keyword spotting.
       In Acoustics, Speech and Signal Processing (ICASSP), 2017
       IEEE International Conference on (pp. 5670-5674). IEEE.

    Parameters
    ----------
    S : np.ndarray (non-negative)
        The input (magnitude) spectrogram

    sr : number > 0 [scalar]
        The audio sampling rate

    hop_length : int > 0 [scalar]
        The hop length of `S`, expressed in samples

    gain : number >= 0 [scalar]
        The gain factor.  Typical values should be slightly less than 1.

    bias : number >= 0 [scalar]
        The bias point of the nonlinear compression (default: 2)

    power : number > 0 [scalar]
        The compression exponent.  Typical values should be between 0 and 1.
        Smaller values of `power` result in stronger compression.

    time_constant : number > 0 [scalar]
        The time constant for IIR filtering, measured in seconds.

    eps : number > 0 [scalar]
        A small constant used to ensure numerical stability of the filter.

    b : number in [0, 1]  [scalar]
        The filter coefficient for the low-pass filter.
        If not provided, it will be inferred from `time_constant`.

    max_size : int > 0 [scalar]
        The width of the max filter applied to the frequency axis.
        If left as `1`, no filtering is performed.

    ref : None or np.ndarray (shape=S.shape)
        An optional pre-computed reference spectrum (`R` in the above).
        If not provided it will be computed from `S`.

    axis : int [scalar]
        The (time) axis of the input spectrogram.

    max_axis : None or int [scalar]
        The frequency axis of the input spectrogram.
        If `None`, and `S` is two-dimensional, it will be inferred
        as the opposite from `axis`.
        If `S` is not two-dimensional, and `max_size > 1`, an error
        will be raised.

    zi : np.ndarray
        The initial filter delay values.

        This may be the `zf` (final delay values) of a previous call to `pcen`, or
        computed by `scipy.signal.lfilter_zi`.

    return_zf : bool
        If `True`, return the final filter delay values along with the PCEN output `P`.
        This is primarily useful in streaming contexts, where the final state of one
        block of processing should be used to initialize the next block.

        If `False` (default) only the PCEN values `P` are returned.


    Returns
    -------
    P : np.ndarray, non-negative [shape=(n, m)]
        The per-channel energy normalized version of `S`.

    zf : np.ndarray (optional)
        The final filter delay values.  Only returned if `return_zf=True`.

    See Also
    --------
    amplitude_to_db
    librosa.onset.onset_strength

    Examples
    --------

    Compare PCEN to log amplitude (dB) scaling on Mel spectra

    >>> import matplotlib.pyplot as plt
    >>> y, sr = librosa.load(librosa.util.example_audio_file(),
    ...                      offset=10, duration=10)

    >>> # We'll use power=1 to get a magnitude spectrum
    >>> # instead of a power spectrum
    >>> S = librosa.feature.melspectrogram(y, sr=sr, power=1)
    >>> log_S = librosa.amplitude_to_db(S, ref=np.max)
    >>> pcen_S = librosa.pcen(S)
    >>> plt.figure()
    >>> plt.subplot(2,1,1)
    >>> librosa.display.specshow(log_S, x_axis='time', y_axis='mel')
    >>> plt.title('log amplitude (dB)')
    >>> plt.colorbar()
    >>> plt.subplot(2,1,2)
    >>> librosa.display.specshow(pcen_S, x_axis='time', y_axis='mel')
    >>> plt.title('Per-channel energy normalization')
    >>> plt.colorbar()
    >>> plt.tight_layout()

    Compare PCEN with and without max-filtering

    >>> pcen_max = librosa.pcen(S, max_size=3)
    >>> plt.figure()
    >>> plt.subplot(2,1,1)
    >>> librosa.display.specshow(pcen_S, x_axis='time', y_axis='mel')
    >>> plt.title('Per-channel energy normalization (no max-filter)')
    >>> plt.colorbar()
    >>> plt.subplot(2,1,2)
    >>> librosa.display.specshow(pcen_max, x_axis='time', y_axis='mel')
    >>> plt.title('Per-channel energy normalization (max_size=3)')
    >>> plt.colorbar()
    >>> plt.tight_layout()