Source code for deltasigma._calculateQTF

# -*- coding: utf-8 -*-
# _calculateQTF.py
# Module providing the calculateQTF 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.

"""Module providing the calculateQTF() function
"""

from __future__ import division

import numpy as np

from scipy.signal import ss2tf, tf2zpk

from ._cancelPZ import cancelPZ
from ._partitionABCD import partitionABCD


[docs]def calculateQTF(ABCDr): """Calculate noise and signal transfer functions for a quadrature modulator **Parameters:** ABCDr : ndarray The ABCD matrix, in real form. You may call :func:`mapQtoR` to convert an imaginary (quadrature) ABCD matrix to a real one. **Returns:** ntf, stf, intf, istf : tuple of zpk tuples The quadrature noise and signal transfer functions. :raises RuntimeError: if the supplied ABCD matrix results in denominator mismatches. """ A, B, C, D = partitionABCD(ABCDr, 4) #Construct an ABCD description of the closed-loop system # sys is a tuple in A, B, C, D form Acl = A + np.dot(B[:, 2:4], C) Bcl = B Ccl = C Dcl = np.hstack((D[:, 0:2], np.eye(2))) #sys = (A + np.dot(B[:, 2:4], C), B, C, # np.hstack((D[:, 0:2], np.eye(2)))) #Calculate the 2x4 matrix of transfer functions tfs = np.empty((2, 4), dtype=object) # Each tf is a tuple in num, den form # tf[i, j] corresponds to the TF from input j to output i for i in range(2): for j in range(4): tfs[i, j] = ss2tf(Acl, Bcl, Ccl[i, :], Dcl[i, :], input=j) #Reduce these to NTF, STF, INTF and ISTF if any(tfs[0, 2][1] != tfs[1, 3][1]): raise RuntimeError('TF Denominator mismatch. Location 1') ntf_x = (0.5 * (tfs[0, 2][0] + tfs[1, 3][0]), tfs[0, 2][1]) intf_x = (0.5 * (tfs[0, 2][0] - tfs[1, 3][0]), tfs[0, 2][1]) if any(tfs[0, 3][1] != tfs[1, 2][1]): raise RuntimeError('TF Denominator mismatch. Location 2') ntf_y = (0.5 * (tfs[1, 2][0] - tfs[0, 3][0]), tfs[1, 2][1]) intf_y = (0.5 * (tfs[1, 2][0] + tfs[0, 3][0]), tfs[1, 2][1]) if any(ntf_x[1] != ntf_y[1]): raise RuntimeError('TF Denominator mismatch. Location 3') if any(tfs[0, 0][1] != tfs[1, 1][1]): raise RuntimeError('TF Denominator mismatch. Location 4') stf_x = (0.5 * (tfs[0, 0][0] + tfs[1, 1][0]), tfs[0, 0][1]) istf_x = (0.5 * (tfs[0, 0][0] - tfs[1, 1][0]), tfs[0, 0][1]) if any(tfs[0, 1][1] != tfs[1, 0][1]): raise RuntimeError('TF Denominator mismatch. Location 5') stf_y = (0.5 * (tfs[1, 0][0] - tfs[0, 1][0]), tfs[1, 0][1]) istf_y = (0.5 * (tfs[1, 0][0] + tfs[0, 1][0]), tfs[1, 0][1]) if any(stf_x[1] != stf_y[1]): raise RuntimeError('TF Denominator mismatch. Location 6') # suppress warnings about complex TFs #warning('off') ntf = cancelPZ(tf2zpk(ntf_x[0] + 1j*ntf_y[0], ntf_x[1])) intf = cancelPZ(tf2zpk(intf_x[0] + 1j*intf_y[0], intf_x[1])) stf = cancelPZ(tf2zpk(stf_x[0] + 1j*stf_y[0], ntf_x[1])) istf = cancelPZ(tf2zpk(istf_x[0] + 1j*istf_y[0], intf_x[1])) #warning('on') return ntf, stf, intf, istf