Exemplo n.º 1
0
def generate_Nac(circ):
	"""Generate the vector holding the contribution of AC sources.
	"""
	n_of_nodes = len(circ.nodes_dict)
	Nac = numpy.mat(numpy.zeros((n_of_nodes, 1)), dtype=complex)
	j = numpy.complex('j')
	# process isources
	for elem in circ.elements:
		if isinstance(elem, devices.isource) and elem.abs_ac is not None:
			#convenzione normale!
			N[elem.n1, 0] = N[elem.n1, 0] + elem.abs_ac*numpy.exp(j*elem.arg_ac)
			N[elem.n2, 0] = N[elem.n2, 0] - elem.abs_ac*numpy.exp(j*elem.arg_ac)
	# process vsources
	# for each vsource, introduce a new variable: the current flowing through it.
	# then we introduce a KVL equation to be able to solve the circuit
	for elem in circ.elements:
		if circuit.is_elem_voltage_defined(elem):
			index = Nac.shape[0] 
			Nac = utilities.expand_matrix(Nac, add_a_row=True, add_a_col=False)
			if isinstance(elem, devices.vsource) and elem.abs_ac is not None:
				Nac[index, 0] = -1.0*elem.abs_ac*numpy.exp(j*elem.arg_ac)
	return Nac
Exemplo n.º 2
0
Arquivo: ac.py Projeto: vovkd/ahkab
def generate_Nac(circ):
	"""Generate the vector holding the contribution of AC sources.
	"""
	n_of_nodes = len(circ.nodes_dict)
	Nac = numpy.mat(numpy.zeros((n_of_nodes, 1)), dtype=complex)
	j = numpy.complex('j')
	# process isources
	for elem in circ.elements:
		if isinstance(elem, devices.isource) and elem.abs_ac is not None:
			#convenzione normale!
			N[elem.n1, 0] = N[elem.n1, 0] + elem.abs_ac*numpy.exp(j*elem.arg_ac)
			N[elem.n2, 0] = N[elem.n2, 0] - elem.abs_ac*numpy.exp(j*elem.arg_ac)
	# process vsources
	# for each vsource, introduce a new variable: the current flowing through it.
	# then we introduce a KVL equation to be able to solve the circuit
	for elem in circ.elements:
		if circuit.is_elem_voltage_defined(elem):
			index = Nac.shape[0] 
			Nac = utilities.expand_matrix(Nac, add_a_row=True, add_a_col=False)
			if isinstance(elem, devices.vsource) and elem.abs_ac is not None:
				Nac[index, 0] = -1.0*elem.abs_ac*numpy.exp(j*elem.arg_ac)
	return Nac
Exemplo n.º 3
0
def generate_mna_and_N(circ, verbose=3):
    """La vecchia versione usava il sistema visto a lezione, quella nuova mira ad essere
    magari meno elegante, ma funzionale, flessibile e comprensibile.
    MNA e N vengono creati direttamente della dimensione det. dal numero dei nodi, poi se
    ci sono voltage sources vengono allargate.

    Il vettore incognita � fatto cos�:
    x vettore colonna di lunghezza (N_nodi - 1) + N_vsources, i primi N_nodi valori di x, corrispondono
    alle tensioni ai nodi, gli altri alle correnti nei generatori di tensione.
    Le tensioni nodali sono ordinate tramite i numeri interni dei nodi, in ordine CRESCENTE, saltando
    il nodo 0, preso a riferimento.
    L'ordine delle correnti nei gen di tensione � det. dall'ordine in cui essi vengono incontrati
    scorrendo `circ`. Viene sempre usata la convenzione normale.

    Il sistema � cos� fatto: MNA*x + N = 0

    Richiede in ingresso la descrizione del circuito, circ.
    Restituisce: (MNA, N)
    """
    n_of_nodes = len(circ.nodes_dict)
    mna = numpy.mat(numpy.zeros((n_of_nodes, n_of_nodes)))
    N = numpy.mat(numpy.zeros((n_of_nodes, 1)))
    for elem in circ:
        if elem.is_nonlinear:
            continue
        elif isinstance(elem, devices.Resistor):
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1.0 / elem.value
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1.0 / elem.value
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1.0 / elem.value
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1.0 / elem.value
        elif isinstance(elem, devices.Capacitor):
            pass  # In a capacitor I(V) = 0
        elif isinstance(elem, devices.GISource):
            mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + elem.alpha
            mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - elem.alpha
            mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - elem.alpha
            mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + elem.alpha
        elif isinstance(elem, devices.ISource):
            if not elem.is_timedependent:  # convenzione normale!
                N[elem.n1, 0] = N[elem.n1, 0] + elem.I()
                N[elem.n2, 0] = N[elem.n2, 0] - elem.I()
            else:
                pass  # vengono aggiunti volta per volta
        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
        else:
            print "dc_analysis.py: BUG - Unknown linear element. Ref. #28934"
    # process vsources
    # i generatori di tensione non sono pilotabili in tensione: g � infinita
    # for each vsource, introduce a new variable: the current flowing through it.
    # then we introduce a KVL equation to be able to solve the circuit
    for elem in circ:
        if circuit.is_elem_voltage_defined(elem):
            index = mna.shape[0]  # get_matrix_size(mna)[0]
            mna = utilities.expand_matrix(mna, add_a_row=True, add_a_col=True)
            N = utilities.expand_matrix(N, add_a_row=True, add_a_col=False)
            # KCL
            mna[elem.n1, index] = 1.0
            mna[elem.n2, index] = -1.0
            # KVL
            mna[index, elem.n1] = +1.0
            mna[index, elem.n2] = -1.0
            if isinstance(elem, devices.VSource) and not elem.is_timedependent:
                # corretto, se � def una parte tempo-variabile ci pensa
                # mdn_solver a scegliere quella giusta da usare.
                N[index, 0] = -1.0 * elem.V()
            elif isinstance(elem, devices.VSource) and elem.is_timedependent:
                pass  # taken care step by step
            elif isinstance(elem, devices.EVSource):
                mna[index, elem.sn1] = -1.0 * elem.alpha
                mna[index, elem.sn2] = +1.0 * elem.alpha
            elif isinstance(elem, devices.Inductor):
                # N[index,0] = 0 pass, it's already zero
                pass
            elif isinstance(elem, devices.HVSource):
                print "dc_analysis.py: BUG - hvsources are not implemented yet."
                sys.exit(33)
            else:
                print "dc_analysis.py: BUG - found an unknown voltage_def elem."
                print elem
                sys.exit(33)

    # Seems a good place to run some sanity check
    # for the time being we do not halt the execution
    check_ground_paths(mna, circ, reduced_mna=False, verbose=verbose)

    # all done
    return (mna, N)
Exemplo n.º 4
0
def generate_mna_and_N(circ):
    """La vecchia versione usava il sistema visto a lezione, quella nuova mira ad essere 
	magari meno elegante, ma funzionale, flessibile e comprensibile. 
	MNA e N vengono creati direttamente della dimensione det. dal numero dei nodi, poi se 
	ci sono voltage sources vengono allargate.
	
	Il vettore incognita � fatto cos�:
	x vettore colonna di lunghezza (N_nodi - 1) + N_vsources, i primi N_nodi valori di x, corrispondono
	alle tensioni ai nodi, gli altri alle correnti nei generatori di tensione.
	Le tensioni nodali sono ordinate tramite i numeri interni dei nodi, in ordine CRESCENTE, saltando
	il nodo 0, preso a riferimento.
	L'ordine delle correnti nei gen di tensione � det. dall'ordine in cui essi vengono incontrati 
	scorrendo circ.elements. Viene sempre usata la convenzione normale.
	
	Il sistema � cos� fatto: MNA*x + N = 0
	
	Richiede in ingresso la descrizione del circuito, circ.
	Restituisce: (MNA, N)
	"""
    n_of_nodes = len(circ.nodes_dict)
    mna = numpy.mat(numpy.zeros((n_of_nodes, n_of_nodes)))
    N = numpy.mat(numpy.zeros((n_of_nodes, 1)))
    for elem in circ.elements:
        if elem.is_nonlinear:
            continue
        elif isinstance(elem, devices.resistor):
            mna[elem.n1, elem.n1] = mna[elem.n1, elem.n1] + 1.0 / elem.R
            mna[elem.n1, elem.n2] = mna[elem.n1, elem.n2] - 1.0 / elem.R
            mna[elem.n2, elem.n1] = mna[elem.n2, elem.n1] - 1.0 / elem.R
            mna[elem.n2, elem.n2] = mna[elem.n2, elem.n2] + 1.0 / elem.R
        elif isinstance(elem, devices.capacitor):
            pass  # In a capacitor I(V) = 0
        elif isinstance(elem, devices.gisource):
            mna[elem.n1, elem.sn1] = mna[elem.n1, elem.sn1] + elem.alpha
            mna[elem.n1, elem.sn2] = mna[elem.n1, elem.sn2] - elem.alpha
            mna[elem.n2, elem.sn1] = mna[elem.n2, elem.sn1] - elem.alpha
            mna[elem.n2, elem.sn2] = mna[elem.n2, elem.sn2] + elem.alpha
        elif isinstance(elem, devices.isource):
            if not elem.is_timedependent:  # convenzione normale!
                N[elem.n1, 0] = N[elem.n1, 0] + elem.I()
                N[elem.n2, 0] = N[elem.n2, 0] - elem.I()
            else:
                pass  # vengono aggiunti volta per volta
        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:
            print "dc_analysis.py: BUG - Unknown linear element. Ref. #28934"
            # process vsources
            # i generatori di tensione non sono pilotabili in tensione: g � infinita
            # for each vsource, introduce a new variable: the current flowing through it.
            # then we introduce a KVL equation to be able to solve the circuit
    for elem in circ.elements:
        if circuit.is_elem_voltage_defined(elem):
            index = mna.shape[0]  # get_matrix_size(mna)[0]
            mna = utilities.expand_matrix(mna, add_a_row=True, add_a_col=True)
            N = utilities.expand_matrix(N, add_a_row=True, add_a_col=False)
            # KCL
            mna[elem.n1, index] = 1.0
            mna[elem.n2, index] = -1.0
            # KVL
            mna[index, elem.n1] = +1.0
            mna[index, elem.n2] = -1.0
            if isinstance(elem, devices.vsource) and not elem.is_timedependent:
                # corretto, se � def una parte tempo-variabile ci pensa
                # mdn_solver a scegliere quella giusta da usare.
                N[index, 0] = -1.0 * elem.V()
            elif isinstance(elem, devices.vsource) and elem.is_timedependent:
                pass  # taken care step by step
            elif isinstance(elem, devices.evsource):
                mna[index, elem.sn1] = -1.0 * elem.alpha
                mna[index, elem.sn2] = +1.0 * elem.alpha
            elif isinstance(elem, devices.inductor):
                # N[index,0] = 0 pass, it's already zero
                pass
            elif isinstance(elem, devices.hvsource):
                print "dc_analysis.py: BUG - hvsources are not implemented yet."
                sys.exit(33)
            else:
                print "dc_analysis.py: BUG - found an unknown voltage_def elem."
                print elem
                sys.exit(33)

                # Seems a good place to run some sanity check
                # for the time being we do not halt the execution
    check_ground_paths(mna, circ, reduced_mna=False)

    # all done
    return (mna, N)
Exemplo n.º 5
0
def get_dc_guess(circ, verbose=3):
    """This method tries to build a DC guess, according to what the
	elements suggest.
	A element can suggest its guess through the elem.dc_guess field.
	
	verbose: verbosity level (from 0 silent to 5 debug)
	
	Returns: the dc_guess (matrix) or None
	"""
    if verbose:
        sys.stdout.write("Calculating guess: ")
        sys.stdout.flush()

    # A DC guess has meaning only if the circuit has NL elements
    if not circ.is_nonlinear():
        if verbose:
            print "skipped. (linear circuit)"
        return None

    if verbose > 3:
        print ""

    nv = len(circ.nodes_dict)
    M = numpy.mat(numpy.zeros((1, nv)))
    T = numpy.mat(numpy.zeros((1, 1)))
    index = 0
    v_eq = 0  # number of current equations
    one_element_with_dc_guess_found = False

    for elem in circ.elements:
        # In the meanwhile, check how many current equations are
        # required to solve the circuit
        if circuit.is_elem_voltage_defined(elem):
            v_eq = v_eq + 1
        # This is the main focus: build a system of equations (M*x = T)
        if hasattr(elem, "dc_guess") and elem.dc_guess is not None:
            if not one_element_with_dc_guess_found:
                one_element_with_dc_guess_found = True
            if elem.is_nonlinear:
                port_index = 0
                for (n1, n2) in elem.ports:
                    if n1 == n2:
                        continue
                    if index:
                        M = utilities.expand_matrix(M,
                                                    add_a_row=True,
                                                    add_a_col=False)
                        T = utilities.expand_matrix(T,
                                                    add_a_row=True,
                                                    add_a_col=False)
                    M[index, n1] = +1
                    M[index, n2] = -1
                    T[index] = elem.dc_guess[port_index]
                    port_index = port_index + 1
                    index = index + 1
            else:
                if elem.n1 == elem.n2:
                    continue
                if index:
                    M = utilities.expand_matrix(M,
                                                add_a_row=True,
                                                add_a_col=False)
                    T = utilities.expand_matrix(T,
                                                add_a_row=True,
                                                add_a_col=False)
                M[index, elem.n1] = +1
                M[index, elem.n2] = -1
                T[index] = elem.dc_guess[0]
                index = index + 1

    if verbose == 5:
        print "DBG: get_dc_guess(): M and T, no reduction"
        print M
        print T
    M = utilities.remove_row_and_col(M, rrow=10 * M.shape[0], rcol=0)

    if not one_element_with_dc_guess_found:
        if verbose == 5:
            print "DBG: get_dc_guess(): no element has a dc_guess"
        elif verbose <= 3:
            print "skipped."
        return None

    # We wish to find the linearly dependent lines of the M matrix.
    # The matrix is made by +1, -1, 0 elements.
    # Hence, if two lines are linearly dependent, one of these equations
    # has to be satisfied: (L1, L2 are two lines)
    # L1 + L2 = 0 (vector)
    # L2 - L1 = 0 (vector)
    # This is tricky, because I wish to remove lines of the matrix while
    # browsing it.
    # We browse the matrix by line from bottom up and compare each line
    # with the upper lines. If a linearly dep. line is found, we remove
    # the current line.
    # Then break from the loop, get the next line (bottom up), which is
    # the same we were considering before; compare with the upper lines..
    # Not optimal, but it works.
    for i in range(M.shape[0] - 1, -1, -1):
        for j in range(i - 1, -1, -1):
            #print i, j, M[i, :], M[j, :]
            dummy1 = M[i, :] - M[j, :]
            dummy2 = M[i, :] + M[j, :]
            if not dummy1.any() or not dummy2.any():
                #print "REM:", M[i, :]
                M = utilities.remove_row(M, rrow=i)
                T = utilities.remove_row(T, rrow=i)
                break
    if verbose == 5:
        print "DBG: get_dc_guess(): M and T, after removing LD lines"
        print M
        print T

    # Remove empty columns:
    # If a column is empty, we have no guess regarding the corresponding
    # node. It makes the matrix singular. -> Remove the col & remember
    # that we are _not_ calculating a guess for it.
    removed_index = []
    for i in range(M.shape[1] - 1, -1, -1):
        if not M[:, i].any():
            M = utilities.remove_row_and_col(M, rrow=M.shape[0], rcol=i)
            removed_index.append(i)

    if verbose > 3:
        print "DBG: get_dc_guess(): M and T, after removing empty columns."
        print M
        print "T\n", T

    # Now, we have a set of equations to be solved.
    # There are three cases:
    # 1. The M matrix has a different number of rows and columns.
    #    We use the Moore-Penrose matrix inverse to get
    #    the shortest length least squares solution to the problem
    #          M*x + T = 0
    # 2. The matrix is square.
    #    It seems that if the circuit is not pathological,
    #    we are likely to find a solution (the matrix has det != 0).
    #    I'm not sure about this though.

    if M.shape[0] != M.shape[1]:
        Rp = numpy.mat(numpy.linalg.pinv(M)) * T
    else:  # case M.shape[0] == M.shape[1], use normal
        if numpy.linalg.det(M) != 0:
            try:
                Rp = numpy.linalg.inv(M) * T
            except numpy.linalg.linalg.LinAlgError:
                eig = numpy.linalg.eig(M)[0]
                cond = abs(eig).max() / abs(eig).min()
                if verbose:
                    print "cond=" + str(cond) + ". No guess."
                return None
        else:
            if verbose:
                print "Guess matrix is singular. No guess."
            return None

    # Now we want to:
    # 1. Add voltages for the nodes for which we have no clue to guess.
    # 2. Append to each vector of guesses the values for currents in
    #    voltage defined elem.
    # Both them are set to 0
    for index in removed_index:
        Rp = numpy.concatenate(( \
        numpy.concatenate((Rp[:index, 0], \
        numpy.mat(numpy.zeros((1, 1)))), axis=0), \
        Rp[index:, 0]), axis=0)
    # add the 0s for the currents due to the voltage defined
    # elements (we have no guess for those...)
    if v_eq > 0:
        Rp = numpy.concatenate((Rp, numpy.mat(numpy.zeros((v_eq, 1)))), axis=0)

    if verbose == 5:
        print circ.nodes_dict

    if verbose and verbose < 4:
        print "done."
    if verbose > 3:
        print "Guess:"
        print Rp

    return Rp
Exemplo n.º 6
0
def get_dc_guess(circ, verbose=3):
	"""This method tries to build a DC guess, according to what the
	elements suggest.
	A element can suggest its guess through the elem.dc_guess field.
	
	verbose: verbosity level (from 0 silent to 5 debug)
	
	Returns: the dc_guess (matrix) or None
	"""
	if verbose: 
		sys.stdout.write("Calculating guess: ")
		sys.stdout.flush()
	
	# A DC guess has meaning only if the circuit has NL elements
	if not circ.is_nonlinear():
		if verbose:
			print "skipped. (linear circuit)"
		return None
	
	
	if verbose > 3:
		print ""

	nv = len(circ.nodes_dict)
	M = numpy.mat(numpy.zeros((1, nv)))
	T = numpy.mat(numpy.zeros((1, 1)))
	index = 0
	v_eq = 0 # number of current equations
	one_element_with_dc_guess_found = False

	for elem in circ.elements:
		# In the meanwhile, check how many current equations are 
		# required to solve the circuit
		if circuit.is_elem_voltage_defined(elem):
			v_eq = v_eq + 1
		# This is the main focus: build a system of equations (M*x = T)
		if hasattr(elem, "dc_guess") and elem.dc_guess is not None:
			if not one_element_with_dc_guess_found:
				one_element_with_dc_guess_found = True
			if elem.is_nonlinear:
				port_index = 0
				for (n1, n2) in elem.ports:
					if n1 == n2:
						continue
					if index:
						M = utilities.expand_matrix(M, add_a_row=True, add_a_col=False)
						T = utilities.expand_matrix(T, add_a_row=True, add_a_col=False)
					M[index, n1] = +1
					M[index, n2] = -1
					T[index] = elem.dc_guess[port_index]
					port_index = port_index + 1
					index = index + 1
			else:
				if elem.n1 == elem.n2:
					continue
				if index:
					M = utilities.expand_matrix(M, add_a_row=True, add_a_col=False)
					T = utilities.expand_matrix(T, add_a_row=True, add_a_col=False)
				M[index, elem.n1] = +1
				M[index, elem.n2] = -1
				T[index] = elem.dc_guess[0]
				index = index + 1
	
	if verbose == 5:
		print "DBG: get_dc_guess(): M and T, no reduction"
		print M
		print T
	M = utilities.remove_row_and_col(M, rrow=10*M.shape[0], rcol=0)
	
	if not one_element_with_dc_guess_found:
		if verbose == 5:
			print "DBG: get_dc_guess(): no element has a dc_guess"
		elif verbose <= 3:
			print "skipped."
		return None
	
	# We wish to find the linearly dependent lines of the M matrix.
	# The matrix is made by +1, -1, 0 elements. 
	# Hence, if two lines are linearly dependent, one of these equations
	# has to be satisfied: (L1, L2 are two lines)
	# L1 + L2 = 0 (vector)
	# L2 - L1 = 0 (vector)
	# This is tricky, because I wish to remove lines of the matrix while
	# browsing it.
	# We browse the matrix by line from bottom up and compare each line 
	# with the upper lines. If a linearly dep. line is found, we remove 
	# the current line.
	# Then break from the loop, get the next line (bottom up), which is
	# the same we were considering before; compare with the upper lines..
	# Not optimal, but it works.
	for i in range(M.shape[0]-1, -1, -1):
		for j in range(i-1, -1, -1):
			#print i, j, M[i, :], M[j, :]
			dummy1 = M[i, :] - M[j, :]
			dummy2 = M[i, :] + M[j, :]
			if not dummy1.any() or not dummy2.any():
				#print "REM:", M[i, :]
				M = utilities.remove_row(M, rrow=i)
				T = utilities.remove_row(T, rrow=i)
				break
	if verbose == 5:
		print "DBG: get_dc_guess(): M and T, after removing LD lines"
		print M
		print T
			
	# Remove empty columns:
	# If a column is empty, we have no guess regarding the corresponding
	# node. It makes the matrix singular. -> Remove the col & remember
	# that we are _not_ calculating a guess for it.
	removed_index = []
	for i in range(M.shape[1]-1, -1, -1):
		if not M[:, i].any():
			M = utilities.remove_row_and_col(M, rrow=M.shape[0], rcol=i)
			removed_index.append(i)
	
	if verbose > 3:
		print "DBG: get_dc_guess(): M and T, after removing empty columns."
		print M
		print "T\n", T

	# Now, we have a set of equations to be solved.
	# There are three cases:
	# 1. The M matrix has a different number of rows and columns.
	#    We use the Moore-Penrose matrix inverse to get 
	#    the shortest length least squares solution to the problem
	#          M*x + T = 0
	# 2. The matrix is square.
	#    It seems that if the circuit is not pathological,
	#    we are likely to find a solution (the matrix has det != 0).
	#    I'm not sure about this though.
	
	if M.shape[0] != M.shape[1]:
		Rp = numpy.mat(numpy.linalg.pinv(M)) * T
	else: # case M.shape[0] == M.shape[1], use normal
		if numpy.linalg.det(M) != 0:
			try:
				Rp = numpy.linalg.inv(M) * T
			except numpy.linalg.linalg.LinAlgError:
				eig = numpy.linalg.eig(M)[0]
				cond = abs(eig).max()/abs(eig).min()
				if verbose:
					print "cond=" +str(cond)+". No guess."
				return None
		else:
			if verbose:
				print "Guess matrix is singular. No guess."
			return None
			

	# Now we want to:
	# 1. Add voltages for the nodes for which we have no clue to guess.
	# 2. Append to each vector of guesses the values for currents in 
	#    voltage defined elem.
	# Both them are set to 0
	for index in removed_index:
		Rp = numpy.concatenate(( \
		numpy.concatenate((Rp[:index, 0], \
		numpy.mat(numpy.zeros((1, 1)))), axis=0), \
		Rp[index:, 0]), axis=0)
	# add the 0s for the currents due to the voltage defined 
	# elements (we have no guess for those...)
	if v_eq > 0:
		Rp = numpy.concatenate((Rp, numpy.mat(numpy.zeros((v_eq, 1)))), axis=0)
	
	if verbose == 5:
		print circ.nodes_dict
	
	if verbose and verbose < 4:
		print "done."
	if verbose > 3:
		print "Guess:"
		print Rp
	
	return Rp