# -*- coding: utf-8 -*-
# _impL1.py
# This module provides the impL1 function.
# Copyright 2013 Giuseppe Venturini
# This file is part of python-deltasigma.
#
# python-deltasigma is a 1:1 Python replacement of Richard Schreier's
# MATLAB delta sigma toolbox (aka "delsigma"), upon which it is heavily based.
# The delta sigma toolbox is (c) 2009, Richard Schreier.
#
# python-deltasigma is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# LICENSE file for the licensing terms.
"""This module provides the impL1() function, computing the impulse response
from the comparator output to the comparator input for a given NTF.
"""
import numpy as np
from scipy.signal import convolve, dimpulse
from ._padr import padr
from ._utils import _get_num_den, _is_num_den, _is_zpk
[docs]def impL1(arg1, n=10):
"""Impulse response evaluation for NTFs.
Compute the impulse response from the comparator
output to the comparator input for the given NTF.
**Parameters:**
arg1 : object
The NTF, which may be represented as:
* ZPK tuple,
* num, den tuple,
* A, B, C, D tuple,
* ABCD matrix,
* a scipy LTI object,
* a sequence of the tuples of any of the above types (experimental).
n : int
is the (optional) number of time steps (default: 10), resulting in
an impulse response with n+1 (default: 11) samples.
This function is useful when verifying the realization
of a NTF with a specified topology.
**Returns:**
y : ndarray
The NTF impulse response
.. note::
In the original implementation of impL1 in delsig, there is a
bug: impL1 calls MATLAB's impulse with tfinal=n, which means that
the function will return the impulse response evaluated on the times
[0, 1, 2 ... n], ie n+1 points. We keep the same behavior here,
but we state clearly that n is the number of time steps.
"""
if _is_num_den(arg1):
num, den = arg1
p = np.roots(den)
elif _is_zpk(arg1):
z, p, _ = arg1
num = np.poly(z)
den = np.poly(p)
else:
num, den = _get_num_den(arg1)
p = np.roots(den)
num = np.asarray(num)
den = np.asarray(den)
p = np.asarray(p)
lf_den = padr(num, len(p)+1)
lf_num = lf_den - den
ts = np.arange(n + 1) # be coherent with the original toolbox
all_lf = np.concatenate((lf_num, lf_den), axis=1)
lf_num, lf_den = lf_num.squeeze(), lf_den.squeeze()
if not np.allclose(np.imag(all_lf), np.zeros(all_lf.shape), atol=1e-9):
# Complex loop filter
lfr_den = np.real(convolve(lf_den, np.conj(lf_den))).squeeze()
lfr_num = convolve(lf_num, np.conj(lf_den)).squeeze()
lf_i = (np.real(lfr_num).tolist(), lfr_den.tolist(), 1)
lf_q = (np.imag(lfr_num).tolist(), lfr_den.tolist(), 1)
y = dimpulse(lf_i, t=ts)[1][0] + 1j*dimpulse(lf_q, t=ts)[1][0]
y = y.squeeze()
else:
_, y = dimpulse((lf_num, lf_den, 1), t=ts)
y = y[0].squeeze()
return y