Example #1
0
def get_variables(circ):
    """Get a sympy matrix containing the circuit variables to be solved for.

    **Parameters:**

    circ : circuit instance
        The circuit

    **Returns:**

    vars : sympy matrix, shape (n, 1)
        The variables in a column vector.
    """
    # numero di soluzioni di tensione (al netto del ref)
    nv_1 = circ.get_nodes_number() - 1

    # descrizioni dei componenti non definibili in tensione
    idescr = [elem.part_id.upper()
              for elem in circ if circuit.is_elem_voltage_defined(elem)]

    mna_size = nv_1 + len(idescr)
    x = smzeros(mna_size, 1)

    for i in range(mna_size):
        if i < nv_1:
            x[i, 0] = _symbol_factory("V" + str(circ.nodes_dict[i + 1]))
        else:
            x[i, 0] = _symbol_factory("I[" + idescr[i - nv_1] + "]")
    return x
Example #2
0
def _expand_matrix(mat, add_a_row=False, add_a_col=False):
    if add_a_row:
        row = smzeros(1, mat.shape[1])
        mat = mat.row_insert(mat.shape[0], row)
    if add_a_col:
        col = sympy.zeros(mat.shape[0], 1)
        mat = mat.col_insert(mat.shape[1], col)
    return mat
Example #3
0
def get_variables(circ):
	"""Returns a sympy matrix with the circuit variables to be solved for.
	"""
	nv_1 = len(circ.nodes_dict) - 1 # numero di soluzioni di tensione (al netto del ref)
	
	# descrizioni dei componenti non definibili in tensione
	idescr = [ (elem.letter_id.upper() + elem.descr) \
		for elem in circ.elements if circuit.is_elem_voltage_defined(elem) ]

	mna_size = nv_1 + len(idescr)
	x = smzeros((mna_size, 1))

	for i in range(mna_size):
		if i < nv_1:
			x[i, 0] = sympy.Symbol("V" + str(circ.nodes_dict[i + 1]))
		else:
			x[i, 0] = sympy.Symbol("I["+idescr[i - nv_1]+"]")
	return x
Example #4
0
def get_variables(circ):
	"""Returns a sympy matrix with the circuit variables to be solved for.
	"""
	nv_1 = len(circ.nodes_dict) - 1 # numero di soluzioni di tensione (al netto del ref)
	
	# descrizioni dei componenti non definibili in tensione
	idescr = [ (elem.letter_id.upper() + elem.descr) \
		for elem in circ.elements if circuit.is_elem_voltage_defined(elem) ]

	mna_size = nv_1 + len(idescr)
	x = smzeros((mna_size, 1))

	for i in range(mna_size):
		if i < nv_1:
			x[i, 0] = sympy.Symbol("V" + str(circ.nodes_dict[i + 1]))
		else:
			x[i, 0] = sympy.Symbol("I["+idescr[i - nv_1]+"]")
	return x
Example #5
0
def generate_mna_and_N(circ, opts, ac=False, verbose=3):
    """Generates a symbolic Modified Nodal Analysis matrix and N vector.
    """
    #   print options
    n_of_nodes = len(circ.nodes_dict)
    mna = smzeros(n_of_nodes)
    N = smzeros((n_of_nodes, 1))
    s = sympy.Symbol('s', complex=True)
    subs_g = {}

    for elem in circ:
        if isinstance(elem, devices.Resistor):
            # we use conductances instead of 1/R because there is a significant
            # overhead handling many 1/R terms in sympy.
            if elem.is_symbolic:
                R = sympy.Symbol(elem.part_id.upper(),
                                 real=True,
                                 positive=True)
                G = sympy.Symbol('G' + elem.part_id[1:],
                                 real=True,
                                 positive=True)
                # but we keep track of which is which and substitute back after
                # solving.
                subs_g.update({G: 1 / R})
            else:
                R = elem.value
                G = 1.0 / R
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + G
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - G
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - G
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + G
        elif isinstance(elem, devices.Capacitor):
            if ac:
                if elem.is_symbolic:
                    capa = sympy.Symbol(elem.part_id.upper(),
                                        real=True,
                                        positive=True)
                else:
                    capa = elem.value
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + s * capa
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - s * capa
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + s * capa
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - s * capa
            else:
                pass
        elif isinstance(elem, devices.Inductor):
            pass
        elif isinstance(elem, devices.GISource):
            if elem.is_symbolic:
                alpha = sympy.Symbol(elem.part_id.upper(), real=True)
            else:
                alpha = elem.value
            mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + alpha
            mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - alpha
            mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - alpha
            mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + alpha
        elif isinstance(elem, devices.ISource):
            if elem.is_symbolic:
                IDC = sympy.Symbol(elem.part_id.upper(), real=True)
            else:
                IDC = elem.dc_value
            N[elem.n1, 0] = N[elem.n1, 0] + IDC
            N[elem.n2, 0] = N[elem.n2, 0] - IDC
        elif isinstance(elem, mosq.mosq_device) or isinstance(
                elem, ekv.ekv_device):
            gm = sympy.Symbol('gm_' + elem.part_id, real=True, positive=True)
            mna[elem.n1, elem.ng] = mna[elem.n1, elem.ng] + gm
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gm
            mna[elem.n2, elem.ng] = mna[elem.n2, elem.ng] - gm
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gm
            if opts['r0s']:
                r0 = sympy.Symbol('r0_' + elem.part_id,
                                  real=True,
                                  positive=True)
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1 / r0
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1 / r0
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1 / r0
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1 / r0
        elif isinstance(elem, diode.diode):
            gd = sympy.Symbol("g" + elem.part_id, positive=True)
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + gd
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gd
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - gd
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gd
        elif isinstance(elem, devices.InductorCoupling):
            pass
            # this is taken care of within the inductors
        elif circuit.is_elem_voltage_defined(elem):
            pass
            # we'll add its lines afterwards
        elif verbose:
            printing.print_warning("Skipped elem %s: not implemented." %
                                   (elem.part_id.upper(), ))

    pre_vde = mna.shape[0]
    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            index = mna.shape[0]  # get_matrix_size(mna)[0]
            mna = expand_matrix(mna, add_a_row=True, add_a_col=True)
            N = expand_matrix(N, add_a_row=True, add_a_col=False)
            # KCL
            mna[elem.n1, index] = +1
            mna[elem.n2, index] = -1
            # KVL
            mna[index, elem.n1] = +1
            mna[index, elem.n2] = -1
            if isinstance(elem, devices.VSource):
                if elem.is_symbolic:
                    VDC = sympy.Symbol(elem.part_id.upper(), real=True)
                else:
                    VDC = elem.dc_value
                N[index, 0] = -VDC
            elif isinstance(elem, devices.EVSource):
                if elem.is_symbolic:
                    alpha = sympy.Symbol(elem.part_id.upper(), real=True)
                else:
                    alpha = elem.alpha
                mna[index, elem.sn1] = -alpha
                mna[index, elem.sn2] = +alpha
            elif isinstance(elem, devices.Inductor):
                if ac:
                    if elem.is_symbolic:
                        L = sympy.Symbol(elem.part_id.upper(),
                                         real=True,
                                         positive=True)
                    else:
                        L = elem.L
                    mna[index, index] = -s * L
                else:
                    pass
                    # already so: commented out
                    # N[index,0] = 0
            elif isinstance(elem, devices.HVSource):
                printing.print_warning(
                    "symbolic.py: BUG - hvsources are not implemented yet.")
                sys.exit(33)

    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            if isinstance(elem, devices.Inductor):
                if ac:
                    # find its index to know which column corresponds to its
                    # current
                    this_index = circ.find_vde_index(elem.part_id, verbose=0)
                    for cd in elem.coupling_devices:
                        if cd.is_symbolic:
                            M = sympy.Symbol(cd.part_id,
                                             real=True,
                                             positive=True)
                        else:
                            M = cd.K
                        # get `part_id` of the other inductor (eg. "L32")
                        other_id_wdescr = cd.get_other_inductor(elem.part_id)
                        # find its index to know which column corresponds to
                        # its current
                        other_index = circ.find_vde_index(other_id_wdescr,
                                                          verbose=0)
                        # add the term.
                        mna[pre_vde + this_index,
                            pre_vde + other_index] += -s * M
                else:
                    pass

    # all done
    return (mna, N, subs_g)
Example #6
0
def generate_mna_and_N(circ, opts, ac=False, verbose=3):
    """Generates a symbolic Modified Nodal Analysis matrix and N vector.
    """
    #   print options
    n_of_nodes = len(circ.nodes_dict)
    mna = smzeros(n_of_nodes)
    N = smzeros((n_of_nodes, 1))
    subs_g = {}

    for elem in circ:
        if isinstance(elem, devices.Resistor):
            # we use conductances instead of 1/R because there is a significant
            # overhead handling many 1/R terms in sympy.
            if elem.is_symbolic:
                R = _symbol_factory(
                    elem.part_id.upper(), real=True, positive=True)
                G = _symbol_factory('G' + elem.part_id[1:], real=True, positive=True)
                # but we keep track of which is which and substitute back after
                # solving.
                subs_g.update({G: 1 / R})
            else:
                R = elem.value
                G = 1.0 / R
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + G
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - G
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - G
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + G
        elif isinstance(elem, devices.Capacitor):
            if ac:
                if elem.is_symbolic:
                    capa = _symbol_factory(
                        elem.part_id.upper(), real=True, positive=True)
                else:
                    capa = elem.value
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + s * capa
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - s * capa
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + s * capa
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - s * capa
            else:
                pass
        elif isinstance(elem, devices.Inductor):
            pass
        elif isinstance(elem, devices.GISource):
            if elem.is_symbolic:
                alpha = _symbol_factory(elem.part_id.upper(), real=True)
            else:
                alpha = elem.value
            mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + alpha
            mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - alpha
            mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - alpha
            mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + alpha
        elif isinstance(elem, devices.ISource):
            if elem.is_symbolic:
                IDC = _symbol_factory(elem.part_id.upper())
            else:
                IDC = elem.dc_value
            N[elem.n1, 0] = N[elem.n1, 0] + IDC
            N[elem.n2, 0] = N[elem.n2, 0] - IDC
        elif isinstance(elem, mosq.mosq_device) or isinstance(elem, ekv.ekv_device):
            gm = _symbol_factory('gm_' + elem.part_id, real=True, positive=True)
            mna[elem.n1, elem.ng] = mna[elem.n1, elem.ng] + gm
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gm
            mna[elem.n2, elem.ng] = mna[elem.n2, elem.ng] - gm
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gm
            if opts['r0s']:
                r0 = _symbol_factory(
                    'r0_' + elem.part_id, real=True, positive=True)
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1 / r0
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1 / r0
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1 / r0
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1 / r0
        elif isinstance(elem, diode.diode):
            gd = _symbol_factory("g" + elem.part_id, positive=True)
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + gd
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gd
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - gd
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gd
        elif isinstance(elem, devices.InductorCoupling):
            pass
            # this is taken care of within the inductors
        elif circuit.is_elem_voltage_defined(elem):
            pass
            # we'll add its lines afterwards
        elif verbose:
            printing.print_warning(
                "Skipped elem %s: not implemented." % (elem.part_id.upper(),))

    pre_vde = mna.shape[0]
    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            index = mna.shape[0]  # get_matrix_size(mna)[0]
            mna = expand_matrix(mna, add_a_row=True, add_a_col=True)
            N = expand_matrix(N, add_a_row=True, add_a_col=False)
            # KCL
            mna[elem.n1, index] = +1
            mna[elem.n2, index] = -1
            # KVL
            mna[index, elem.n1] = +1
            mna[index, elem.n2] = -1
            if isinstance(elem, devices.VSource):
                if elem.is_symbolic:
                    VDC = _symbol_factory(elem.part_id.upper())
                else:
                    VDC = elem.dc_value
                N[index, 0] = -VDC
            elif isinstance(elem, devices.EVSource):
                if elem.is_symbolic:
                    alpha = _symbol_factory(elem.part_id.upper(), real=True)
                else:
                    alpha = elem.alpha
                mna[index, elem.sn1] = -alpha
                mna[index, elem.sn2] = +alpha
            elif isinstance(elem, devices.Inductor):
                if ac:
                    if elem.is_symbolic:
                        L = _symbol_factory(
                            elem.part_id.upper(), real=True, positive=True)
                    else:
                        L = elem.L
                    mna[index, index] = -s * L
                else:
                    pass
                    # already so: commented out
                    # N[index,0] = 0
            elif isinstance(elem, devices.HVSource):
                printing.print_warning(
                    "symbolic.py: BUG - hvsources are not implemented yet.")
                sys.exit(33)

    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            if isinstance(elem, devices.Inductor):
                if ac:
                    # find its index to know which column corresponds to its
                    # current
                    this_index = circ.find_vde_index(elem.part_id, verbose=0)
                    for cd in elem.coupling_devices:
                        if cd.is_symbolic:
                            M = _symbol_factory(
                                cd.part_id, real=True, positive=True)
                        else:
                            M = cd.K
                        # get `part_id` of the other inductor (eg. "L32")
                        other_id_wdescr = cd.get_other_inductor(elem.part_id)
                        # find its index to know which column corresponds to
                        # its current
                        other_index = circ.find_vde_index(
                            other_id_wdescr, verbose=0)
                        # add the term.
                        mna[pre_vde + this_index,
                            pre_vde + other_index] += -s * M
                else:
                    pass

    # all done
    return (mna, N, subs_g)
Example #7
0
def generate_mna_and_N(circ, opts, ac=False, subs=None, verbose=3):
    """Generate a symbolic Modified Nodal Analysis matrix and N vector.

    Only elements that have an ``is_symbolic`` attribute set to ``True``
    (the default) are considered symbolically. Simply set the attribute to
    ``False`` to employ the numeric value. This allows to simplify and speed
    up the work of the symbolic solver.

    The formulation can be performed using conductances or resistances. The
    choice is made setting the global ``options.symb_formulate_with_gs`` value
    to ``True``. A formulation done in terms of resistors, may result in many
    separate :math:`1/R` terms in the matrices. Historically, ``sympy`` choked
    on those, because of a long-standing bug in polys. Now the issue seems to
    have been solved and the two computations should be symbolically equivalent
    albeit computationally different (as expected). The option value
    ``options.symb_formulate_with_gs`` is provided to restore the old
    functionality in case you use an old version of ``sympy``.

    **Parameters:**

    circ : circuit instance
        The circuit.
    opts : dict
        The options to be used for the generation of the matrices. As of now,
        the only supported option is ``'r0s'`` which can be set to either
        ``True`` or ``False``, and selects whether the equivalent output
        resistance of the transistors should be taken into account or not.
    ac : bool, optional
        Flag to trigger the inclusion of frequency-dependent elements. Defaults
        to ``False`` currently (but may change).
    subs : dict, optional
        The substitution dictionary, composed by mappings of
        ``<symbol>``:``<sympy expression>``.
    verbose : int, optional
        Verbosity flag, from ``0`` (silent) to ``6`` (very logorrhoic). Defaults
        to ``3``.

    **Returns:**

    mna, N : Sympy matrices
        The MNA matrix and the contant term of symbolic type.
    subs_gs : dict of symbols
        In case the formulation of the MNA is performed in terms of
        conducatances, this dictionary is to be used to substitute away the
        conducatances for the resistor symbols, after the circuit is solved but
        before the results are shown to the user. ``sympy``'s ``sub()`` can take
        care of that for you. If not necessary, this dictionary is empty.

    .. note::

        Setting ``opts['r0s'] = True``, ie considering all the transistors output
        resistances, can significantly slow down -- or even prevent by consuming
        all available memory -- the solution of complex circuits with several
        active elements.

        We recommend a combination of the following:

        * setting the above option in simple circuits only,
        * inserting explicitely the :math:`r_0` you wish to consider at circuit
          level,
        * beefing up your machine with extra RAM and extra computing power,
        * being patient.
    """
    n_of_nodes = circ.get_nodes_number()
    mna = smzeros(n_of_nodes)
    N = smzeros(n_of_nodes, 1)
    subs_g = {}

    for elem in circ:
        if isinstance(elem, devices.Resistor):
            # we use conductances instead of 1/R because there is a significant
            # overhead handling many 1/R terms in sympy.
            if elem.is_symbolic:
                R = _symbol_factory(elem.part_id.upper(), real=True,
                                    positive=True)
                if R in subs:  # instant substitution
                    R = subs[R]
                if options.symb_formulate_with_gs:
                    G = _symbol_factory('Gxxx' + str(R)[1:], real=True,
                                        positive=True)
                    # but we keep track of which is which and substitute back after
                    # solving.
                    subs_g.update({G:1/R})
                else:
                    G = 1.0/R
            else:
                    G = 1.0/elem.value
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + G
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - G
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - G
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + G
        elif isinstance(elem, devices.Capacitor):
            if ac:
                if elem.is_symbolic:
                    capa = _symbol_factory(
                        elem.part_id.upper(), real=True, positive=True)
                    if capa in subs:  # instant substitution
                        capa = subs[capa]
                else:
                    capa = elem.value
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + s * capa
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - s * capa
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + s * capa
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - s * capa
            else:
                pass
        elif isinstance(elem, devices.Inductor):
            pass
        elif isinstance(elem, devices.GISource):
            if elem.is_symbolic:
                alpha = _symbol_factory(elem.part_id.upper(), real=True)
                if alpha in subs:  # instant substitution
                    alpha = subs[alpha]
            else:
                alpha = elem.value
            mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + alpha
            mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - alpha
            mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - alpha
            mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + alpha
        elif isinstance(elem, devices.ISource):
            if elem.is_symbolic:
                IDC = _symbol_factory(elem.part_id.upper())
                if IDC in subs:  # instant substitution
                    IDC = subs[IDC]
            else:
                IDC = elem.dc_value
            N[elem.n1, 0] = N[elem.n1, 0] + IDC
            N[elem.n2, 0] = N[elem.n2, 0] - IDC
        elif isinstance(elem, mosq.mosq_device) or isinstance(elem, ekv.ekv_device):
            gm = _symbol_factory('gm_' + elem.part_id, real=True, positive=True)
            if gm in subs:  # instant substitution
                gm = subs[gm]
            mna[elem.n1, elem.ng] = mna[elem.n1, elem.ng] + gm
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gm
            mna[elem.n2, elem.ng] = mna[elem.n2, elem.ng] - gm
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gm
            if opts['r0s']:
                r0 = _symbol_factory(
                    'r0_' + elem.part_id, real=True, positive=True)
                if r0 in subs:  # instant substitution
                    r0 = subs[r0]
                mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1 / r0
                mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1 / r0
                mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1 / r0
                mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1 / r0
        elif isinstance(elem, diode.diode):
            gd = _symbol_factory("g" + elem.part_id, positive=True)
            if gd in subs:  # instant substitution
                gd = subs[gd]
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + gd
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gd
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - gd
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gd
        elif isinstance(elem, devices.FISource):
            # These are added after all VDEs have been accounted for
            pass
        elif isinstance(elem, devices.InductorCoupling):
            pass
            # this is taken care of within the inductors
        elif circuit.is_elem_voltage_defined(elem):
            pass
            # we'll add its lines afterwards
        elif verbose:
            printing.print_warning("Skipped elem %s: not implemented." %
                                   (elem.part_id.upper(),))

    pre_vde = mna.shape[0]
    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            index = mna.shape[0]  # get_matrix_size(mna)[0]
            mna = _expand_matrix(mna, add_a_row=True, add_a_col=True)
            N = _expand_matrix(N, add_a_row=True, add_a_col=False)
            # KCL
            mna[elem.n1, index] = +1
            mna[elem.n2, index] = -1
            # KVL
            mna[index, elem.n1] = +1
            mna[index, elem.n2] = -1
            if isinstance(elem, devices.VSource):
                if elem.is_symbolic:
                    VDC = _symbol_factory(elem.part_id.upper())
                    if VDC in subs:  # instant substitution
                        VDC = subs[VDC]
                else:
                    VDC = elem.dc_value
                N[index, 0] = -VDC
            elif isinstance(elem, devices.EVSource):
                if elem.is_symbolic:
                    alpha = _symbol_factory(elem.part_id.upper(), real=True)
                    if alpha in subs:  # instant substitution
                        alpha = subs[alpha]
                else:
                    alpha = elem.alpha
                mna[index, elem.sn1] = -alpha
                mna[index, elem.sn2] = +alpha
            elif isinstance(elem, devices.HVSource):
                if elem.is_symbolic:
                    alpha = _symbol_factory(elem.part_id.upper(), real=True)
                    if alpha in subs:  # instant substitution
                        alpha = subs[alpha]
                else:
                    alpha = elem.alpha
                source_index = circ.find_vde_index(elem.source_id)
                mna[index, n_of_nodes + source_index] = +alpha
            elif isinstance(elem, devices.Inductor):
                if ac:
                    if elem.is_symbolic:
                        L = _symbol_factory(
                            elem.part_id.upper(), real=True, positive=True)
                        if L in subs:  # instant substitution
                            L = subs[L]
                    else:
                        L = elem.L
                    mna[index, index] = -s * L
                else:
                    pass
                    # already so: commented out
                    # N[index,0] = 0
            else:
                raise circuit.CircuitError('Element %s is not supported. ' +
                                           'Please report this bug.' %
                                           elem.__class__)

    for elem in circ:
        if ac and isinstance(elem, devices.Inductor):
            # find its index to know which column corresponds to its
            # current
            this_index = circ.find_vde_index(elem.part_id, verbose=0)
            for cd in elem.coupling_devices:
                if cd.is_symbolic:
                    M = _symbol_factory(
                        cd.part_id, real=True, positive=True)
                    if M in subs:  # instant substitution
                        M = subs[M]
                else:
                    M = cd.K
                # get `part_id` of the other inductor (eg. "L32")
                other_id_wdescr = cd.get_other_inductor(elem.part_id)
                # find its index to know which column corresponds to
                # its current
                other_index = circ.find_vde_index(
                    other_id_wdescr, verbose=0)
                # add the term.
                mna[pre_vde + this_index,
                    pre_vde + other_index] += -s * M
        elif isinstance(elem, devices.FISource):
            source_current_index = circ.find_vde_index(elem.source_id, verbose=0)
            if elem.is_symbolic:
                F = _symbol_factory(elem.part_id, real=True)
                if F in subs:  # instant substitution
                    F = subs[F]
            else:
                F = elem.alpha
            mna[elem.n1, pre_vde + source_current_index] += +F
            mna[elem.n2, pre_vde + source_current_index] += -F
        else:
            pass

    # all done
    return mna, N, subs_g
Example #8
0
def generate_mna_and_N(circ, opts, ac=False):
	"""Generates a symbolic Modified Nodal Analysis matrix and N vector.
	"""
	#print options
	n_of_nodes = len(circ.nodes_dict)
	mna = smzeros(n_of_nodes)
	N = smzeros((n_of_nodes, 1))
	s = sympy.Symbol("s", complex=True)
	subs_g = {}
	#process_elements() 	
	for elem in circ.elements:
		#if elem.is_nonlinear and not (isinstance(elem, mosq.mosq_device) or isinstance(elem, ekv.ekv_device)): 
		#	print "Skipped elem "+elem.letter_id.upper()+elem.descr + ": not implemented."	
		#	continue
		if isinstance(elem, devices.resistor):
			# we use conductances instead of 1/R because there is a significant
			# overhead handling many 1/R terms in sympy.
			if elem.is_symbolic:
				R = sympy.Symbol(elem.letter_id.upper()+elem.descr, real=True)
				G = sympy.Symbol("G"+elem.descr, real=True)
				# but we keep track of which is which and substitute back after solving.
				subs_g.update({G:1/R})
			else:
				R = elem.R
				G = 1.0/R
			#mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1/R
			#mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1/R
			#mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1/R
			#mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1/R
			mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + G
			mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - G
			mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - G
			mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + G
		elif isinstance(elem, devices.capacitor):
			if ac:
				if elem.is_symbolic:
					capa = sympy.Symbol(elem.letter_id.upper()+elem.descr, real=True)
				else:
					capa = elem.C
				mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + s*capa
				mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - s*capa
				mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + s*capa
				mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - s*capa
			else:
				pass
		elif isinstance(elem, devices.inductor):
			pass
		elif isinstance(elem, devices.gisource):
			if elem.is_symbolic:
				alpha = sympy.Symbol(elem.letter_id+elem.descr, real=True)
			else:
				alpha = elem.alpha
			mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + alpha
			mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - alpha
			mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - alpha
			mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + alpha
		elif isinstance(elem, devices.isource):
			if elem.is_symbolic:
				IDC = sympy.Symbol(elem.letter_id.upper()+elem.descr, real=True)
			else:
				IDC = elem.idc
			N[elem.n1, 0] = N[elem.n1, 0] + IDC
			N[elem.n2, 0] = N[elem.n2, 0] - IDC
		elif isinstance(elem, mosq.mosq_device) or isinstance(elem, ekv.ekv_device):
			gm = sympy.Symbol('gm_'+elem.letter_id+elem.descr, real=True)
			mna[elem.n1, elem.ng] = mna[elem.n1, elem.ng] + gm
			mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gm
			mna[elem.n2, elem.ng] = mna[elem.n2, elem.ng] - gm
			mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gm
			if opts['r0s']:
				r0 = sympy.Symbol('r0_'+elem.letter_id+elem.descr, real=True)
				mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1/r0
				mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1/r0
				mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1/r0
				mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1/r0
		elif isinstance(elem, diode.diode):
			gd = sympy.Symbol("g"+elem.letter_id+elem.descr)
			mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + gd
			mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - gd
			mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - gd
			mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + gd
		elif isinstance(elem, devices.inductor_coupling):
			pass
			# this is taken care of within the inductors
		elif circuit.is_elem_voltage_defined(elem):
			pass
			#we'll add its lines afterwards
		else:
			printing.print_warning("Skipped elem %s: not implemented." % (elem.letter_id.upper()+elem.descr,))

	pre_vde = mna.shape[0]
	for elem in circ.elements:
		if circuit.is_elem_voltage_defined(elem):
			index = mna.shape[0] #get_matrix_size(mna)[0]
			mna = expand_matrix(mna, add_a_row=True, add_a_col=True)
			N = expand_matrix(N, add_a_row=True, add_a_col=False)
			# KCL
			mna[elem.n1, index] = +1
			mna[elem.n2, index] = -1
			# KVL
			mna[index, elem.n1] = +1
			mna[index, elem.n2] = -1
			if isinstance(elem, devices.vsource):
				if elem.is_symbolic:
					VDC = sympy.Symbol(elem.letter_id.upper() + elem.descr, real=True)
				else:
					VDC = elem.vdc
				N[index, 0] = -VDC
			elif isinstance(elem, devices.evsource):
				if elem.is_symbolic:
					alpha = sympy.Symbol(elem.letter_id.upper() + elem.descr, real=True)
				else:
					alpha = elem.alpha
				mna[index, elem.sn1] = -alpha
				mna[index, elem.sn2] = +alpha
			elif isinstance(elem, devices.inductor):
				if ac:
					if elem.is_symbolic:
						L = sympy.Symbol(elem.letter_id.upper() + elem.descr, real=True)
					else:
						L = elem.L
					mna[index, index] = -s*L
				else: 
					pass
					# already so: commented out				
					# N[index,0] = 0
			elif isinstance(elem, devices.hvsource):
				printing.print_warning("symbolic.py: BUG - hvsources are not implemented yet.")
				sys.exit(33)
	
	for elem in circ.elements:
		if circuit.is_elem_voltage_defined(elem):
			if isinstance(elem, devices.inductor):
				if ac:
					# find its index to know which column corresponds to its current
					this_index = circ.find_vde_index("L"+elem.descr, verbose=0)
					for cd in elem.coupling_devices:
						if cd.is_symbolic:
							M = sympy.Symbol("M" + cd.descr, real=True)
						else:
							M = cd.K
						# get id+descr of the other inductor (eg. "L32")
						other_id_wdescr = cd.get_other_inductor("L"+elem.descr)
						# find its index to know which column corresponds to its current
						other_index = circ.find_vde_index(other_id_wdescr, verbose=0)
						# add the term.
						#print "other_index: "+str(other_index)
						#print "this_index: "+str(this_index)
						mna[pre_vde+this_index,pre_vde+other_index] += -s*M
						#print mna
				else: 
					pass
					# already so: commented out				
					# N[index,0] = 0
			
	
	#all done
	return (mna, N, subs_g)