bag.data.lti

This module defines functions/classes for characterizing linear time-invariant circuits.

Module Contents

Classes

LTICircuit

A class that models a linear-time-invariant circuit.

Functions

get_w_crossings(→ Tuple[Optional[float], Optional[float]])

Compte gain margin/phase margin frequencies from the transfer function,

get_w_3db(→ Optional[float])

Given the numerator and denominator of the transfer function, compute the 3dB frequency.

get_stability_margins(→ Tuple[float, float])

Given the numerator and denominator of the transfer function, compute phase and gain margins.

class bag.data.lti.LTICircuit(udot_tol: float = 1e-12)[source]

Bases: object

A class that models a linear-time-invariant circuit.

This class computes AC transfer functions for linear-time-invariant circuits.

Note: Since this class work with AC transfer functions, ‘gnd’ in this circuit is AC ground.

Parameters:

udot_tol (float) – tolerance to determine if dependency on input derivatives is zero.

_float_min[source]
_get_node_id(name: str) int[source]
static _add(mat: Dict[Tuple[int, int], float], key: Tuple[int, int], val: float) None[source]
add_res(res: float, p_name: str, n_name: str) None[source]

Adds a resistor to the circuit.

Parameters:
  • res (float) – the resistance value, in Ohms.

  • p_name (str) – the positive terminal net name.

  • n_name (str) – the negative terminal net name.

add_conductance(g: float, p_name: str, n_name: str) None[source]

Adds a resistor to the circuit given conductance value.

Parameters:
  • g (float) – the conductance value, in inverse Ohms.

  • p_name (str) – the positive terminal net name.

  • n_name (str) – the negative terminal net name.

add_vccs(gm: float, p_name: str, n_name: str, cp_name: str, cn_name: str = 'gnd') None[source]

Adds a voltage controlled current source to the circuit.

Parameters:
  • gm (float) – the gain of the voltage controlled current source, in Siemens.

  • p_name (str) – the terminal that the current flows out of.

  • n_name (str) – the terminal that the current flows in to.

  • cp_name (str) – the positive voltage control terminal.

  • cn_name (str) – the negative voltage control terminal. Defaults to ‘gnd’.

add_vcvs(gain: float, p_name: str, n_name: str, cp_name: str, cn_name: str = 'gnd') None[source]

Adds a voltage controlled voltage source to the circuit.

Parameters:
  • gain (float) – the gain of the voltage controlled voltage source.

  • p_name (str) – the positive terminal of the output voltage source.

  • n_name (str) – the negative terminal of the output voltage source.

  • cp_name (str) – the positive voltage control terminal.

  • cn_name (str) – the negative voltage control terminal. Defaults to ‘gnd’.

add_cap(cap: float, p_name: str, n_name: str) None[source]

Adds a capacitor to the circuit.

Parameters:
  • cap (float) – the capacitance value, in Farads.

  • p_name (str) – the positive terminal net name.

  • n_name (str) – the negative terminal net name.

add_ind(ind: float, p_name: str, n_name: str) None[source]

Adds an inductor to the circuit.

Parameters:
  • ind (float) – the inductance value, in Henries.

  • p_name (str) – the positive terminal net name.

  • n_name (str) – the negative terminal net name.

add_transistor(tran_info: Dict[str, float], d_name: str, g_name: str, s_name: str, b_name: str = 'gnd', fg: Union[float, int] = 1, neg_cap: bool = True) None[source]

Adds a small signal transistor model to the circuit.

Parameters:
  • tran_info (Dict[str, float]) – a dictionary of 1-finger transistor small signal parameters. Should contain gm, gds, gb, cgd, cgs, cgb, cds, cdb, and csb.

  • d_name (str) – drain net name.

  • g_name (str) – gate net name.

  • s_name (str) – source net name.

  • b_name (str) – body net name. Defaults to ‘gnd’.

  • fg (Union[float, int]) – number of transistor fingers.

  • neg_cap (bool) – True to allow negative capacitance (which is there due to model fitting).

classmethod _count_rank(diag: numpy.ndarray) int[source]
classmethod _solve_gx_bw(g: numpy.ndarray, b: numpy.ndarray) Tuple[numpy.ndarray, numpy.ndarray][source]

Solve the equation G*x + B*[w, w’, …].T = 0 for x.

Finds matrix Ka, Kw such that x = Ka * a + Kw * [w, w’, …].T solves the given equation for any value of a.

Parameters:
  • g (np.ndarray) – the G matrix, with shape (M, N) and M < N.

  • b (np.ndarray) – the B matrix.

Returns:

  • ka (np.ndarray) – the Ky matrix.

  • kw (np.ndarray) – the Kw matrix.

classmethod _transform_c_qr(g, c, b, d)[source]

Reveal redundant variables by transforming C matrix using QR decomposition

classmethod _reduce_state_space(g, c, b, d, e, ndim_w)[source]

Reduce state space variables.

Given the state equation G*x + C*x’ + B*[w, w’, w’’, …].T = 0, and y = D*x + E*[w, w’, w’’, …].T, check if C is full rank. If not, we compute new G, C, and B matrices with reduced dimensions.

classmethod _simplify(g, c, b, d, e, ndim_w)[source]

Eliminate input derivatives by re-defining state variables.

_build_mna_matrices(inputs: Union[str, List[str]], outputs: Union[str, List[str]], in_type: str = 'v') Tuple[numpy.ndarray, Ellipsis][source]

Create and return MNA matrices representing this circuit.

Parameters:
  • inputs (Union[str, List[str]]) – the input voltage/current node name(s).

  • outputs (Union[str, List[str]]) – the output voltage node name(s).

  • in_type (str) – set to ‘v’ for input voltage sources. Otherwise, current sources.

Returns:

  • g (np.ndarray) – the conductance matrix

  • c (np.ndarray) – the capacitance/inductance matrix.

  • b (np.ndarray) – the input-to-state matrix.

  • d (np.ndarray) – the state-to-output matrix.

  • e (np.ndarray) – the input-to-output matrix.

get_state_space(inputs: Union[str, List[str]], outputs: Union[str, List[str]], in_type: str = 'v') scipy.signal.ltisys.StateSpaceContinuous[source]

Compute the state space model from the given inputs to outputs.

Parameters:
  • inputs (Union[str, List[str]]) – the input voltage/current node name(s).

  • outputs (Union[str, List[str]]) – the output voltage node name(s).

  • in_type (str) – set to ‘v’ for input voltage sources. Otherwise, current sources.

Returns:

system – the scipy state space object. See scipy.signal package on how to use this object.

Return type:

StateSpaceContinuous

get_num_den(in_name: str, out_name: str, in_type: str = 'v', atol: float = 0.0) Tuple[numpy.ndarray, numpy.ndarray][source]

Compute the transfer function between the two given nodes.

Parameters:
  • in_name (str) – the input voltage/current node name.

  • out_name (Union[str, List[str]]) – the output voltage node name.

  • in_type (str) – set to ‘v’ for input voltage sources. Otherwise, current sources.

  • atol (float) – absolute tolerance for checking zeros in the numerator. Used to filter out scipy warnings.

Returns:

  • num (np.ndarray) – the numerator polynomial.

  • den (np.ndarray) – the denominator polynomial.

get_transfer_function(in_name: str, out_name: str, in_type: str = 'v', atol: float = 0.0) scipy.signal.ltisys.TransferFunctionContinuous[source]

Compute the transfer function between the two given nodes.

Parameters:
  • in_name (str) – the input voltage/current node name.

  • out_name (Union[str, List[str]]) – the output voltage node name.

  • in_type (str) – set to ‘v’ for input voltage sources. Otherwise, current sources.

  • atol (float) – absolute tolerance for checking zeros in the numerator. Used to filter out scipy warnings.

Returns:

system – the scipy transfer function object. See scipy.signal package on how to use this object.

Return type:

TransferFunctionContinuous

get_impedance(node_name: str, freq: float, atol: float = 0.0) complex[source]

Computes the impedance looking into the given node.

Parameters:
  • node_name (str) – the node to compute impedance for. We will inject a current into this node and measure the voltage on this node.

  • freq (float) – the frequency to compute the impedance at, in Hertz.

  • atol (float) – absolute tolerance for checking zeros in the numerator. Used to filter out scipy warnings.

Returns:

impedance – the impedance value, in Ohms.

Return type:

complex

bag.data.lti.get_w_crossings(num: numpy.ndarray, den: numpy.ndarray, atol: float = 1e-08) Tuple[Optional[float], Optional[float]][source]

Compte gain margin/phase margin frequencies from the transfer function,

To determine the crossover frequencies, we write the transfer function as:

\[\frac{A(w) + jB(w)}{C(w) + jD(w)}\]

where \(A(w)\), \(B(w)\), \(C(w)\), and \(D(w)\) are real polynomials. The gain margin frequency is the frequency at which:

\[\frac{B(w)}{A(w)} = \frac{D(w)}{C(w)} \implies A(w)D(w) - B(w)C(w) = 0\]

The phase margin frequency is the frequency at which:

\[\frac{A^2(w) + B^2(w)}{C^2(w) + D^2(w)} = 1 : implies A^2(w) + B^2(w) - C^2(w) - D^2(w) = 0\]

This function solves these two equations and returns the smallest real and positive roots.

Parameters:
  • num (np.ndarray) – the numerator polynomial coefficients array. index 0 is coefficient for highest term.

  • den (np.ndarray) – the denominator polynomial coefficients array. index 0 is coefficient for highest term.

  • atol (float) – absolute tolerance used to check if the imaginary part of a root is 0, or if a root is greater than 0.

Returns:

  • w_phase (Optional[float]) – lowest positive frequency in rad/s at which the gain becomes unity. None if no such frequency exist.

  • w_gain (Optional[float]) – lower positive frequency in rad/s at which the phase becomes 180 degrees. None if no such frequency exist.

bag.data.lti.get_w_3db(num: numpy.ndarray, den: numpy.ndarray, atol: float = 1e-08) Optional[float][source]

Given the numerator and denominator of the transfer function, compute the 3dB frequency.

To determine the 3dB frequency, we first normalize the transfer function so that its DC gain is one, then we write the transfer function as:

\[\frac{A(w) + jB(w)}{C(w) + jD(w)}\]

where \(A(w)\), \(B(w)\), \(C(w)\), and \(D(w)\) are real polynomials. The 3dB frequency is the frequency at which:

\[\frac{A^2(w) + B^2(w)}{C^2(w) + D^2(w)} = 0.5 : implies A^2(w) + B^2(w) - 0.5\left(C^2( w) + D^2(w)\right) = 0\]

This function solves this equation and returns the smallest real and positive roots.

Parameters:
  • num (np.ndarray) – the numerator polynomial coefficients array. index 0 is coefficient for highest term.

  • den (np.ndarray) – the denominator polynomial coefficients array. index 0 is coefficient for highest term.

  • atol (float) – absolute tolerance used to check if the imaginary part of a root is 0, or if a root is greater than 0.

Returns:

w_3db – the 3dB frequency in rad/s. None if no such frequency exist.

Return type:

Optional[float]

bag.data.lti.get_stability_margins(num: numpy.ndarray, den: numpy.ndarray, rtol: float = 1e-08, atol: float = 1e-08) Tuple[float, float][source]

Given the numerator and denominator of the transfer function, compute phase and gain margins.

Parameters:
  • num (np.ndarray) – the numerator polynomial coefficients array. index 0 is coefficient for highest term.

  • den (np.ndarray) – the denominator polynomial coefficients array. index 0 is coefficient for highest term.

  • rtol (float) – relative tolerance. Used to check if two frequencies are equal.

  • atol (float) – absolute tolerance. Used to check a number is equal to 0.

Returns:

  • phase_margin (float) – the phase margin in degrees. If the system is unstable, a negative number is returned.

  • gain_margin (float) – the gain margin.