Пример #1
0
def build_CMAT(mna, D, step, points, tick, n_of_var=None, verbose=3):
	if n_of_var is None: 
		n_of_var = mna.shape[0]
	printing.print_info_line(("Building CMAT (%dx%d)... " % (n_of_var*points, n_of_var*points), 5), verbose, print_nl=False)
	tick.reset()
	tick.display(verbose > 2)
	(C1, C0) = implicit_euler.get_df_coeff(step)
	I = numpy.mat(numpy.eye(n_of_var))
	M = mna + C1*D
	N = C0 * D
	#Z = numpy.mat(numpy.zeros((n_of_var, n_of_var)))
	CMAT = numpy.mat(numpy.zeros((n_of_var*points, n_of_var*points)))
	for li in xrange(points): #li = line index
		for ci in xrange(points):
			if li == 0:
				if ci == 0:
					temp = 1.0 * I
				elif ci == points - 1:
					temp = -1.0 * I
				else:
					continue #temp = Z
			else:
				if ci == li:
					temp = M
				elif ci == li -1:
					temp = N
				else:
					continue #temp = Z
			CMAT = set_submatrix(row=li*n_of_var, col=ci*n_of_var, dest_matrix=CMAT, source_matrix=temp)
		tick.step(verbose > 2)
	tick.hide(verbose > 2)
	printing.print_info_line(("done.", 5), verbose)

	return CMAT
Пример #2
0
def build_Tass_static_vector(circ, Tf, points, step, tick, n_of_var, verbose=3):
    Tass_vector = []
    nv = len(circ.nodes_dict)
    printing.print_info_line(("Building Tass...", 5), verbose, print_nl=False)

    tick.reset()
    tick.display(verbose > 2)
    for index in xrange(0, points):
            Tt = numpy.zeros((n_of_var, 1))
            v_eq = 0
            time = index * step
            for elem in circ:
                    if (isinstance(elem, devices.VSource) or isinstance(elem, devices.ISource)) and elem.is_timedependent:
                        if isinstance(elem, devices.VSource):
                                Tt[nv - 1 + v_eq, 0] = -1.0 * elem.V(time)
                        elif isinstance(elem, devices.ISource):
                                if elem.n1:
                                        Tt[elem.n1 - 1, 0] = \
                                            Tt[elem.n1 - 1, 0] + elem.I(time)
                                if elem.n2:
                                        Tt[elem.n2 - 1, 0] = \
                                            Tt[elem.n2 - 1, 0] - elem.I(time)
                    if circuit.is_elem_voltage_defined(elem):
                            v_eq = v_eq + 1
            tick.step(verbose > 2)
            Tass_vector.append(Tf + Tt)
    tick.hide(verbose > 2)
    printing.print_info_line(("done.", 5), verbose)

    return Tass_vector
Пример #3
0
    def find_vde_index(self, id_wdescr, verbose=3):
        """Finds a voltage defined element MNA index.

        Parameters:
        id_wdescr (string): the element name, eg. 'V1'. Notice it includes
                            both the id ('V') and the description ('1').
        verbose (int): verbosity level, from 0 (silent) to 6 (debug).

        Returns:
        the index (int)
        """
        vde_index = 0
        found = False
        for elem in self:
            if is_elem_voltage_defined(elem):
                if elem.part_id.upper() == id_wdescr.upper():
                    found = True
                    break
                else:
                    vde_index += 1

        if not found:
            printing.print_warning(
                "find_vde_index(): element %s was not found. This is a bug." % (id_wdescr,))
        else:
            printing.print_info_line(
                ("%s found at index %d" % (id_wdescr, vde_index), 6), verbose)
        return vde_index
Пример #4
0
def build_Tt(circ, points, step, tick, n_of_var, verbose=3):
	nv = len(circ.nodes_dict)
	printing.print_info_line(("Building Tt...", 5), verbose, print_nl=False)
	tick.reset()
	tick.display(verbose > 2)	
	Tt = numpy.zeros((points*n_of_var, 1))
	for index in xrange(1, points):
		v_eq = 0
		time = index * step
		for elem in circ.elements:
			if (isinstance(elem, devices.vsource) or isinstance(elem, devices.isource)) and elem.is_timedependent:
				if isinstance(elem, devices.vsource):
					Tt[index*n_of_var + nv - 1 + v_eq, 0] = -1.0 * elem.V(time)
				elif isinstance(elem, devices.isource):
					if elem.n1:
						Tt[index*n_of_var + elem.n1-1, 0] = \
						Tt[index*n_of_var + elem.n1-1, 0] + elem.I(time)
					if elem.n2:
						Tt[index*n_of_var + elem.n2-1, 0] = \
						Tt[index*n_of_var + elem.n2-1, 0] - elem.I(time)
			if circuit.is_elem_voltage_defined(elem):
				v_eq = v_eq +1
			#print Tt[index*n_of_var:(index+1)*n_of_var]
		tick.step(verbose > 2)
	tick.hide(verbose > 2)
	printing.print_info_line(("done.", 5), verbose)
	
	return Tt
Пример #5
0
def build_Tt(circ, points, step, tick, n_of_var, verbose=3):
    nv = len(circ.nodes_dict)
    printing.print_info_line(("Building Tt...", 5), verbose, print_nl=False)
    tick.reset()
    tick.display(verbose > 2)
    Tt = numpy.zeros((points * n_of_var, 1))
    for index in xrange(1, points):
        v_eq = 0
        time = index * step
        for elem in circ:
            if (isinstance(elem, devices.VSource) or isinstance(
                    elem, devices.ISource)) and elem.is_timedependent:
                if isinstance(elem, devices.VSource):
                    Tt[index * n_of_var + nv - 1 + v_eq, 0] = - \
                        1.0 * elem.V(time)
                elif isinstance(elem, devices.ISource):
                    if elem.n1:
                        Tt[index * n_of_var + elem.n1 - 1, 0] = \
                            Tt[index * n_of_var + elem.n1 - 1, 0] + \
                            elem.I(time)
                    if elem.n2:
                        Tt[index * n_of_var + elem.n2 - 1, 0] = \
                            Tt[index * n_of_var + elem.n2 - 1, 0] - \
                                elem.I(time)
            if circuit.is_elem_voltage_defined(elem):
                v_eq = v_eq + 1
            # print Tt[index*n_of_var:(index+1)*n_of_var]
        tick.step(verbose > 2)
    tick.hide(verbose > 2)
    printing.print_info_line(("done.", 5), verbose)

    return Tt
Пример #6
0
def set_next_solve_method(standard_solving,
                          gmin_stepping,
                          source_stepping,
                          verbose=3):
    if standard_solving["enabled"]:
        printing.print_info_line(("failed.", 1), verbose)
        standard_solving["enabled"] = False
        standard_solving["failed"] = True
    elif gmin_stepping["enabled"]:
        printing.print_info_line(("failed.", 1), verbose)
        gmin_stepping["enabled"] = False
        gmin_stepping["failed"] = True
    elif source_stepping["enabled"]:
        printing.print_info_line(("failed.", 1), verbose)
        source_stepping["enabled"] = False
        source_stepping["failed"] = True
    if not standard_solving["failed"] and options.use_standard_solve_method:
        standard_solving["enabled"] = True
    elif not gmin_stepping["failed"] and options.use_gmin_stepping:
        gmin_stepping["enabled"] = True
        printing.print_info_line(
            ("Enabling gmin stepping convergence aid.", 3), verbose)
    elif not source_stepping["failed"] and options.use_source_stepping:
        source_stepping["enabled"] = True
        printing.print_info_line(
            ("Enabling source stepping convergence aid.", 3), verbose)

    return standard_solving, gmin_stepping, source_stepping
Пример #7
0
    def find_vde_index(self, id_wdescr, verbose=3):
        """Finds a voltage defined element MNA index.

        Parameters:
        id_wdescr (string): the element name, eg. 'V1'. Notice it includes
                            both the id ('V') and the description ('1').
        verbose (int): verbosity level, from 0 (silent) to 6 (debug).

        Returns:
        the index (int)
        """
        vde_index = 0
        found = False
        for elem in self:
            if is_elem_voltage_defined(elem):
                if elem.part_id.upper() == id_wdescr.upper():
                    found = True
                    break
                else:
                    vde_index += 1

        if not found:
            printing.print_warning(
                "find_vde_index(): element %s was not found. This is a bug." %
                (id_wdescr, ))
        else:
            printing.print_info_line(
                ("%s found at index %d" % (id_wdescr, vde_index), 6), verbose)
        return vde_index
Пример #8
0
def build_gmin_matrix(circ, gmin, mna_size, verbose):
	printing.print_info_line(("Building Gmin matrix...", 5), verbose)
	Gmin_matrix = numpy.mat(numpy.zeros((mna_size, mna_size)))
	for index in xrange(len(circ.nodes_dict)-1):
		Gmin_matrix[index, index] = gmin
		# the three missing terms of the stample matrix go on [index,0] [0,0] [0, index] but since 
		# we discarded the 0 row and 0 column, we simply don't need to add them
		#the last lines are the KVL lines, introduced by voltage sources. Don't add gmin there.
	return Gmin_matrix
Пример #9
0
def build_gmin_matrix(circ, gmin, mna_size, verbose):
    printing.print_info_line(("Building Gmin matrix...", 5), verbose)
    Gmin_matrix = numpy.mat(numpy.zeros((mna_size, mna_size)))
    for index in xrange(len(circ.nodes_dict) - 1):
        Gmin_matrix[index, index] = gmin
        # the three missing terms of the stample matrix go on [index,0] [0,0] [0, index] but since
        # we discarded the 0 row and 0 column, we simply don't need to add them
        # the last lines are the KVL lines, introduced by voltage sources. Don't add gmin there.
    return Gmin_matrix
Пример #10
0
def build_Tf(sTf, points, tick, n_of_var, verbose=3):
	printing.print_info_line(("Building Tf...", 5), verbose, print_nl=False)
	tick.reset()
	tick.display(verbose > 2)
	Tf = numpy.mat(numpy.zeros((points*n_of_var, 1)))
	
	for index in xrange(1, points):
		Tf = set_submatrix(row=index*n_of_var, col=0, dest_matrix=Tf, source_matrix=sTf)
		tick.step(verbose > 2)
	

	tick.hide(verbose > 2)
	printing.print_info_line(("done.", 5), verbose)
	
	return Tf
Пример #11
0
def build_Tf(sTf, points, tick, n_of_var, verbose=3):
    printing.print_info_line(("Building Tf...", 5), verbose, print_nl=False)
    tick.reset()
    tick.display(verbose > 2)
    Tf = numpy.mat(numpy.zeros((points * n_of_var, 1)))

    for index in xrange(1, points):
        Tf = set_submatrix(row=index * n_of_var,
                           col=0,
                           dest_matrix=Tf,
                           source_matrix=sTf)
        tick.step(verbose > 2)

    tick.hide(verbose > 2)
    printing.print_info_line(("done.", 5), verbose)

    return Tf
Пример #12
0
def build_x(mna, step, points, tick, x0=None, n_of_var=None, verbose=3):
	if n_of_var is None: 
		n_of_var = mna.shape[0]
	printing.print_info_line(("Building x...", 5), verbose, print_nl=False)
	tick.reset()
	tick.display(verbose > 2)
	x = numpy.mat(numpy.zeros((points*n_of_var, 1)))
	if x0 is not None:
		if isinstance(x0, results.op_solution):
			x0 = x0.asmatrix()
		if x0.shape[0] != n_of_var:
			print "Warning x0 has the wrong dimensions. Using all 0s."
		else:
			for index in xrange(points):
				x = set_submatrix(row=index*n_of_var, col=0, dest_matrix=x, source_matrix=x0)
				tick.step(verbose > 2)

	tick.hide(verbose > 2)
	printing.print_info_line(("done.", 5), verbose)
	
	return x
Пример #13
0
def build_CMAT(mna, D, step, points, tick, n_of_var=None, verbose=3):
    if n_of_var is None:
        n_of_var = mna.shape[0]
    printing.print_info_line(("Building CMAT (%dx%d)... " %
                              (n_of_var * points, n_of_var * points), 5),
                             verbose,
                             print_nl=False)
    tick.reset()
    tick.display(verbose > 2)
    (C1, C0) = implicit_euler.get_df_coeff(step)
    I = numpy.mat(numpy.eye(n_of_var))
    M = mna + C1 * D
    N = C0 * D
    # Z = numpy.mat(numpy.zeros((n_of_var, n_of_var)))
    CMAT = numpy.mat(numpy.zeros((n_of_var * points, n_of_var * points)))
    for li in xrange(points):  # li = line index
        for ci in xrange(points):
            if li == 0:
                if ci == 0:
                    temp = 1.0 * I
                elif ci == points - 1:
                    temp = -1.0 * I
                else:
                    continue  # temp = Z
            else:
                if ci == li:
                    temp = M
                elif ci == li - 1:
                    temp = N
                else:
                    continue  # temp = Z
            CMAT = set_submatrix(row=li * n_of_var,
                                 col=ci * n_of_var,
                                 dest_matrix=CMAT,
                                 source_matrix=temp)
        tick.step(verbose > 2)
    tick.hide(verbose > 2)
    printing.print_info_line(("done.", 5), verbose)

    return CMAT
Пример #14
0
def set_next_solve_method(standard_solving, gmin_stepping, source_stepping, verbose=3):
    if standard_solving["enabled"]:
        printing.print_info_line(("failed.", 1), verbose)
        standard_solving["enabled"] = False
        standard_solving["failed"] = True
    elif gmin_stepping["enabled"]:
        printing.print_info_line(("failed.", 1), verbose)
        gmin_stepping["enabled"] = False
        gmin_stepping["failed"] = True
    elif source_stepping["enabled"]:
        printing.print_info_line(("failed.", 1), verbose)
        source_stepping["enabled"] = False
        source_stepping["failed"] = True
    if not standard_solving["failed"] and options.use_standard_solve_method:
        standard_solving["enabled"] = True
    elif not gmin_stepping["failed"] and options.use_gmin_stepping:
        gmin_stepping["enabled"] = True
        printing.print_info_line(("Enabling gmin stepping convergence aid.", 3), verbose)
    elif not source_stepping["failed"] and options.use_source_stepping:
        source_stepping["enabled"] = True
        printing.print_info_line(("Enabling source stepping convergence aid.", 3), verbose)

    return standard_solving, gmin_stepping, source_stepping
Пример #15
0
def build_Tass_static_vector(circ,
                             Tf,
                             points,
                             step,
                             tick,
                             n_of_var,
                             verbose=3):
    Tass_vector = []
    nv = len(circ.nodes_dict)
    printing.print_info_line(("Building Tass...", 5), verbose, print_nl=False)

    tick.reset()
    tick.display(verbose > 2)
    for index in xrange(0, points):
        Tt = numpy.zeros((n_of_var, 1))
        v_eq = 0
        time = index * step
        for elem in circ.elements:
            if (isinstance(elem, devices.vsource) or isinstance(
                    elem, devices.isource)) and elem.is_timedependent:
                if isinstance(elem, devices.vsource):
                    Tt[nv - 1 + v_eq, 0] = -1.0 * elem.V(time)
                elif isinstance(elem, devices.isource):
                    if elem.n1:
                        Tt[elem.n1-1, 0] = \
                        Tt[elem.n1-1, 0] + elem.I(time)
                    if elem.n2:
                        Tt[elem.n2-1, 0] = \
                        Tt[elem.n2-1, 0] - elem.I(time)
            if circuit.is_elem_voltage_defined(elem):
                v_eq = v_eq + 1
        tick.step(verbose > 2)
        Tass_vector.append(Tf + Tt)
    tick.hide(verbose > 2)
    printing.print_info_line(("done.", 5), verbose)

    return Tass_vector
Пример #16
0
def build_x(mna, step, points, tick, x0=None, n_of_var=None, verbose=3):
    if n_of_var is None:
        n_of_var = mna.shape[0]
    printing.print_info_line(("Building x...", 5), verbose, print_nl=False)
    tick.reset()
    tick.display(verbose > 2)
    x = numpy.mat(numpy.zeros((points * n_of_var, 1)))
    if x0 is not None:
        if isinstance(x0, results.op_solution):
            x0 = x0.asmatrix()
        if x0.shape[0] != n_of_var:
            print "Warning x0 has the wrong dimensions. Using all 0s."
        else:
            for index in xrange(points):
                x = set_submatrix(row=index * n_of_var,
                                  col=0,
                                  dest_matrix=x,
                                  source_matrix=x0)
                tick.step(verbose > 2)

    tick.hide(verbose > 2)
    printing.print_info_line(("done.", 5), verbose)

    return x
Пример #17
0
def bfpss(circ,
          period,
          step=None,
          points=None,
          autonomous=False,
          x0=None,
          mna=None,
          Tf=None,
          D=None,
          outfile='stdout',
          vector_norm=lambda v: max(abs(v)),
          verbose=3):
    """Performs a PSS analysis.

    Time step is constant, IE will be used as DF

    Parameters:
    circ is the circuit description class
    period is the period of the solution
    mna, D, Tf are not compulsory they will be computed if they're set to None
    step is the time step between consecutive points
    points is the number of points to be used
    step and points are mutually exclusive options:
    - if step is specified, the number of points will be automatically determined
    - if points is set, the step will be automatically determined
    - if none of them is set, options.shooting_default_points will be used as points
    autonomous has to be False, autonomous circuits are not supported
    x0 is the initial guess to be used. Needs work.
    outfile is the output filename. Defaults to stdout.
    verbose is set to zero (print errors only) if datafilename == 'stdout'.

    Returns: nothing
    """
    if outfile == "stdout":
        verbose = 0

    printing.print_info_line(("Starting periodic steady state analysis:", 3),
                             verbose)
    printing.print_info_line(("Method: brute-force", 3), verbose)

    if mna is None or Tf is None:
        (mna, Tf) = dc_analysis.generate_mna_and_N(circ, verbose=verbose)
        mna = utilities.remove_row_and_col(mna)
        Tf = utilities.remove_row(Tf, rrow=0)
    elif not mna.shape[0] == Tf.shape[0]:
        printing.print_general_error(
            "mna matrix and N vector have different number of rows.")
        sys.exit(0)

    if D is None:
        D = transient.generate_D(circ, [mna.shape[0], mna.shape[0]])
        D = utilities.remove_row_and_col(D)
    elif not mna.shape == D.shape:
        printing.print_general_error(
            "mna matrix and D matrix have different sizes.")
        sys.exit(0)

    (points, step) = check_step_and_points(step, points, period)

    n_of_var = mna.shape[0]
    locked_nodes = circ.get_locked_nodes()
    tick = ticker.ticker(increments_for_step=1)

    CMAT = build_CMAT(mna,
                      D,
                      step,
                      points,
                      tick,
                      n_of_var=n_of_var,
                      verbose=verbose)

    x = build_x(mna,
                step,
                points,
                tick,
                x0=x0,
                n_of_var=n_of_var,
                verbose=verbose)

    Tf = build_Tf(Tf, points, tick, n_of_var=n_of_var, verbose=verbose)

    # time variable component: Tt this is always the same in each iter. So we build it once for all
    # this holds all time-dependent sources (both V/I).
    Tt = build_Tt(circ, points, step, tick, n_of_var=n_of_var, verbose=verbose)

    # Indices to differentiate between currents and voltages in the
    # convergence check
    nv_indices = []
    ni_indices = []
    nv_1 = len(circ.nodes_dict) - 1
    ni = n_of_var - nv_1
    for i in range(points):
        nv_indices += (i * mna.shape[0] * numpy.ones(nv_1) + \
                      numpy.arange(nv_1)).tolist()
        ni_indices += (i * mna.shape[0] * numpy.ones(ni) + \
                      numpy.arange(nv_1, n_of_var)).tolist()

    converged = False

    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick.reset()
    tick.display(verbose > 2)
    J = numpy.mat(numpy.zeros(CMAT.shape))
    T = numpy.mat(numpy.zeros((CMAT.shape[0], 1)))
    # td is a numpy matrix that will hold the damping factors
    td = numpy.mat(numpy.zeros((points, 1)))
    iteration = 0  # newton iteration counter

    while True:
        if iteration:  # the first time are already all zeros
            J[:, :] = 0
            T[:, 0] = 0
            td[:, 0] = 0
        for index in xrange(1, points):
            for elem in circ:
                # build all dT(xn)/dxn (stored in J) and T(x)
                if elem.is_nonlinear:
                    oports = elem.get_output_ports()
                    for opindex in range(len(oports)):
                        dports = elem.get_drive_ports(opindex)
                        v_ports = []
                        for dpindex in range(len(dports)):
                            dn1, dn2 = dports[dpindex]
                            v = 0  # build v: remember we trashed the 0 row and 0 col of mna -> -1
                            if dn1:
                                v = v + x[index * n_of_var + dn1 - 1, 0]
                            if dn2:
                                v = v - x[index * n_of_var + dn2 - 1, 0]
                            v_ports.append(v)
                        # all drive ports are ready.
                        n1, n2 = oports[opindex][0], oports[opindex][1]
                        if n1:
                            T[index * n_of_var + n1 - 1, 0] = T[index * n_of_var + n1 - 1, 0] + \
                                                              elem.i(opindex, v_ports)
                        if n2:
                            T[index * n_of_var + n2 - 1, 0] = T[index * n_of_var + n2 - 1, 0] - \
                                                              elem.i(opindex, v_ports)
                        for dpindex in range(len(dports)):
                            dn1, dn2 = dports[dpindex]
                            if n1:
                                if dn1:
                                    J[index * n_of_var + n1 - 1, index * n_of_var + dn1 - 1] = \
                                        J[index * n_of_var + n1 - 1, index * n_of_var + dn1 - 1] + \
                                            elem.g(opindex, v_ports, dpindex)
                                if dn2:
                                    J[index * n_of_var + n1 - 1, index * n_of_var + dn2 - 1] =\
                                        J[index * n_of_var + n1 - 1, index * n_of_var + dn2 - 1] - 1.0 * \
                                            elem.g(opindex, v_ports, dpindex)
                            if n2:
                                if dn1:
                                    J[index * n_of_var + n2 - 1, index * n_of_var + dn1 - 1] = \
                                        J[index * n_of_var + n2 - 1, index * n_of_var + dn1 - 1] - 1.0 * \
                                            elem.g(opindex, v_ports, dpindex)
                                if dn2:
                                    J[index * n_of_var + n2 - 1, index * n_of_var + dn2 - 1] =\
                                        J[index * n_of_var + n2 - 1, index * n_of_var + dn2 - 1] + \
                                            elem.g(opindex, v_ports, dpindex)

        J = J + CMAT
        residuo = CMAT * x + T + Tf + Tt
        dx = -1 * (numpy.linalg.inv(J) * residuo)
        # td
        for index in xrange(points):
            td[index, 0] = dc_analysis.get_td(dx[index * n_of_var:(index + 1) *
                                                 n_of_var, 0],
                                              locked_nodes,
                                              n=-1)
        x = x + min(abs(td))[0, 0] * dx
        # convergence check
        converged = convergence_check(dx, x, nv_indices, ni_indices,
                                      vector_norm)
        if converged:
            break
        tick.step(verbose > 2)

        if options.shooting_max_nr_iter and iteration == options.shooting_max_nr_iter:
            printing.print_general_error("Hitted SHOOTING_MAX_NR_ITER (" +
                                         str(options.shooting_max_nr_iter) +
                                         "), iteration halted.")
            converged = False
            break
        else:
            iteration = iteration + 1

    tick.hide(verbose > 2)
    if converged:
        printing.print_info_line(("done.", 3), verbose)
        t = numpy.mat(numpy.arange(points) * step)
        t = t.reshape((1, points))
        x = x.reshape((points, n_of_var))
        sol = results.pss_solution(circ=circ,
                                   method="brute-force",
                                   period=period,
                                   outfile=outfile,
                                   t_array=t,
                                   x_array=x.T)
    else:
        print "failed."
        sol = None
    return sol
Пример #18
0
def bfpss(circ, period, step=None, mna=None, Tf=None, D=None, points=None, autonomous=False, x0=None,  data_filename='stdout', vector_norm=lambda v: max(abs(v)), verbose=3):
	"""Performs a PSS analysis. 
	
	Time step is constant, IE will be used as DF
	
	Parameters:
	circ is the circuit description class
	period is the period of the solution
	mna, D, Tf are not compulsory they will be computed if they're set to None
	step is the time step between consecutive points
	points is the number of points to be used
	step and points are mutually exclusive options:
	- if step is specified, the number of points will be automatically determined 
	- if points is set, the step will be automatically determined
	- if none of them is set, options.shooting_default_points will be used as points
	autonomous has to be False, autonomous circuits are not supported
	x0 is the initial guess to be used. Needs work.
	data_filename is the output filename. Defaults to stdout.
	verbose is set to zero (print errors only) if datafilename == 'stdout'.

	Returns: nothing
	"""
	if data_filename == "stdout":
		verbose = 0
	
	printing.print_info_line(("Starting periodic steady state analysis:",3), verbose)
	printing.print_info_line(("Method: brute-force",3), verbose)
	
	if mna is None or Tf is None:
		(mna, Tf) = dc_analysis.generate_mna_and_N(circ)
		mna = utilities.remove_row_and_col(mna)
		Tf = utilities.remove_row(Tf, rrow=0)
	elif not mna.shape[0] == Tf.shape[0]:
		printing.print_general_error("mna matrix and N vector have different number of rows.")
		sys.exit(0)
	
	if D is None:
		D = transient.generate_D(circ, [mna.shape[0], mna.shape[0]])
		D = utilities.remove_row_and_col(D)
	elif not mna.shape == D.shape:
		printing.print_general_error("mna matrix and D matrix have different sizes.")
		sys.exit(0)
	
	(points, step) = check_step_and_points(step, points, period)
	
	n_of_var = mna.shape[0]
	locked_nodes = circ.get_locked_nodes()
	tick = ticker.ticker(increments_for_step=1)


	CMAT = build_CMAT(mna, D, step, points, tick, n_of_var=n_of_var, \
		verbose=verbose)

	x = build_x(mna, step, points, tick, x0=x0, n_of_var=n_of_var, \
		verbose=verbose)

	Tf = build_Tf(Tf, points, tick, n_of_var=n_of_var, verbose=verbose)
	
	# time variable component: Tt this is always the same in each iter. So we build it once for all
	# this holds all time-dependent sources (both V/I).
	Tt = build_Tt(circ, points, step, tick, n_of_var=n_of_var, verbose=verbose)

	# Indices to differentiate between currents and voltages in the convergence check
	nv_indices = []
	ni_indices = []
	nv_1 = len(circ.nodes_dict) - 1
	ni = n_of_var - nv_1
	for i in range(points):
		nv_indices += (i*mna.shape[0]*numpy.ones(nv_1) + numpy.arange(nv_1)).tolist()
		ni_indices += (i*mna.shape[0]*numpy.ones(ni) + numpy.arange(nv_1, n_of_var)).tolist()

	converged = False

	printing.print_info_line(("Solving... ",3), verbose, print_nl=False)
	tick.reset()
	tick.display(verbose > 2)
	J = numpy.mat(numpy.zeros(CMAT.shape))
	T = numpy.mat(numpy.zeros((CMAT.shape[0], 1)))
	# td is a numpy matrix that will hold the damping factors
	td = numpy.mat(numpy.zeros((points, 1)))
	iteration = 0 # newton iteration counter
	
	while True:
		if iteration: # the first time are already all zeros
			J[:, :] = 0
			T[:, 0] = 0
			td[:, 0] = 0
		for index in xrange(1, points):
			for elem in circ.elements:
				# build all dT(xn)/dxn (stored in J) and T(x)
				if elem.is_nonlinear:
					oports = elem.get_output_ports()
					for opindex in range(len(oports)):
						dports = elem.get_drive_ports(opindex)
						v_ports = []
						for dpindex in range(len(dports)):
							dn1, dn2 = dports[dpindex]
							v = 0 # build v: remember we trashed the 0 row and 0 col of mna -> -1
							if dn1:
								v = v + x[index*n_of_var + dn1 - 1, 0]
							if dn2:
								v = v - x[index*n_of_var + dn2 - 1, 0]
							v_ports.append(v)
						# all drive ports are ready.
						n1, n2 = oports[opindex][0], oports[opindex][1]
						if n1:
							T[index*n_of_var + n1 - 1, 0] = T[index*n_of_var + n1 - 1, 0] + elem.i(opindex, v_ports)
						if n2:
							T[index*n_of_var + n2 - 1, 0] = T[index*n_of_var + n2 - 1, 0] - elem.i(opindex, v_ports)
						for dpindex in range(len(dports)):
							dn1, dn2 = dports[dpindex]
							if n1:
								if dn1:
									J[index*n_of_var + n1-1, index*n_of_var + dn1-1] = \
									J[index*n_of_var + n1-1, index*n_of_var + dn1-1] + elem.g(opindex, v_ports, dpindex)
								if dn2:
									J[index*n_of_var + n1-1, index*n_of_var + dn2-1] =\
									J[index*n_of_var + n1-1, index * n_of_var + dn2-1] - 1.0*elem.g(opindex, v_ports, dpindex)
							if n2:
								if dn1:	
									J[index*n_of_var + n2-1, index*n_of_var + dn1-1] = \
									J[index*n_of_var + n2-1, index*n_of_var + dn1-1] - 1.0*elem.g(opindex, v_ports, dpindex)
								if dn2:
									J[index*n_of_var + n2-1, index*n_of_var + dn2-1] =\
									J[index*n_of_var + n2-1, index*n_of_var + dn2-1] + elem.g(opindex, v_ports, dpindex)

		J = J + CMAT
		residuo = CMAT*x + T + Tf + Tt
		dx = -1 * (numpy.linalg.inv(J) *  residuo)
		#td
		for index in xrange(points):
			td[index, 0] = dc_analysis.get_td(dx[index*n_of_var:(index+1)*n_of_var, 0], locked_nodes, n=-1)
		x = x + min(abs(td))[0, 0] * dx
		# convergence check
		converged = convergence_check(dx, x, nv_indices, ni_indices, vector_norm)
		if converged:
			break
		tick.step(verbose > 2)
	
		if options.shooting_max_nr_iter and iteration == options.shooting_max_nr_iter:
			printing.print_general_error("Hitted SHOOTING_MAX_NR_ITER (" + str(options.shooting_max_nr_iter) + "), iteration halted.")
			converged = False
			break
		else:
			iteration = iteration + 1

	tick.hide(verbose > 2)
	if converged:
		printing.print_info_line(("done.", 3), verbose)
		t = numpy.mat(numpy.arange(points)*step)
		t = t.reshape((1, points))
		x = x.reshape((points, n_of_var))
		sol = results.pss_solution(circ=circ, method="brute-force", period=period, outfile=data_filename, t_array=t, x_array=x.T)
	else:
		print "failed."
		sol = None
	return sol
Пример #19
0
def dc_analysis(circ, start, stop, step, type_descr, xguess=None, data_filename="stdout", print_int_nodes=True, guess=True, stype="LINEAR", verbose=2):
	"""Performs a sweep of the value of V or I of a independent source from start 
	value to stop value using the provided step. 
	For every circuit generated, computes the op and prints it out.
	This function relays on dc_analysis.op_analysis to actually solve each circuit.
	
	circ: the circuit instance to be simulated
	start: start value of the sweep source
	stop: stop value of the sweep source
	step: step value of the sweep source
	elem_type: string, may be 'vsource' or 'isource'
	elem_descr: the description of the element, used to recognize it in circ (i.e v<desc>)
	data_filename: string, filename of the output file. If set to stdout, prints to screen
	print_int_nodes: do it
	guess: op_analysis will guess to start the first NR iteration for the first point, the previsious dc is used from then on
	verbose: verbosity level
	
	Returns:
	A results.dc_solution instance, if a solution was found for at least one sweep value.
	None, if an error occurred (eg invalid start/stop/step values) or there was no solution
	for any sweep value.
	"""
	if data_filename == 'stdout':
		verbose = 0
	printing.print_info_line(("Starting DC analysis:", 2), verbose)
	(elem_type, elem_descr) = type_descr
	sweep_label = elem_type[0].upper()+elem_descr

	#check step/start/stop parameters
	if step == 0:
		printing.print_general_error("Can't sweep with step=0 !")
		sys.exit(1)
	if start > stop:
		printing.print_general_error("DC analysis has start > stop")
		sys.exit(1)
	if (stop-start)/step < 1:
		printing.print_general_error("DC analysis has number of steps < 1")
		sys.exit(1)
	if stype == options.dc_log_step:
		dc_iter = utilities.log_axis_iterator(stop, start, nsteps=int(stop-start)/step)
	elif stype == options.dc_lin_step:
		dc_iter = utilities.lin_axis_iterator(stop, start, nsteps=int(stop-start)/step)
	else:
		printing.print_general_error("Unknown sweep type: %s" % (stype,)) 
		sys.exit(1)

	if elem_type != 'vsource' and elem_type != 'isource':
		printing.print_general_error("Sweeping is possible only with voltage and current sources. (" +str(elem_type)+ ")")
		sys.exit(1)

	source_elem = None
	for index in xrange(len(circ.elements)):
		if circ.elements[index].descr == elem_descr:
			if elem_type == 'vsource': 
				if isinstance(circ.elements[index], devices.vsource):
					source_elem = circ.elements[index]
					break
			if elem_type == 'isource':
				if isinstance(circ.elements[index], devices.isource):
					source_elem = circ.elements[index]
					break
	if not source_elem:
		printing.print_general_error(elem_type + " element with descr. "+ elem_descr +" was not found.")
		sys.exit(1)
	
	if isinstance(source_elem, devices.vsource):
		initial_value = source_elem.vdc
	else:
		initial_value = source_elem.idc

	# The initial value is set to None and this IS CORRECT. 
	# op_analysis will attempt to do a smart guess, if called with x0 = None and guess=True
	# For each iteration over the source voltage (current) value, the last result is used as x0.
	# op_analysis will not attempt to guess the op if x0 is not None
	x = None
	
	sol = results.dc_solution(circ, start, stop, sweepvar=sweep_label, stype=stype, outfile=data_filename)
	
	printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
	tick = ticker.ticker(1)
	tick.display(verbose>2)

	#sweep setup
	
	#tarocca il generatore di tensione, avvia DC silenziosa, ritarocca etc
	index = 0
	for sweep_value in dc_iter:
		index = index + 1
		if isinstance(source_elem, devices.vsource):
			source_elem.vdc = sweep_value
		else:
			source_elem.idc = sweep_value
		#silently calculate the op
		op = op_analysis(circ, x0=x, guess=guess, verbose=0)
		if op is None:
			tick.hide(verbose>2)
			if not options.dc_sweep_skip_allowed:
				print "Could't solve the circuit for sweep value:", start + index*step
				solved = False
				break
			else:
				print "Skipping sweep value:", start + index*step
				continue
		solved = True
		sol.add_op(sweep_value, op)
		
		if guess:
			guess = False

		tick.step(verbose>2)
	
	tick.hide(verbose>2)
	if solved:
		printing.print_info_line(("done", 3), verbose)
	
	# clean up
	if isinstance(source_elem, devices.vsource):
		source_elem.vdc = initial_value
	else:
		source_elem.idc = initial_value

	return sol if solved else None
Пример #20
0
def dc_analysis(circ,
                start,
                stop,
                step,
                source,
                sweep_type='LINEAR',
                guess=True,
                x0=None,
                outfile="stdout",
                verbose=3):
    """Performs a sweep of the value of V or I of a independent source from start
    value to stop value using the provided step.
    For every circuit generated, computes the op and prints it out.
    This function relays on dc_analysis.op_analysis to actually solve each circuit.

    circ: the circuit instance to be simulated
    start: start value of the sweep source
    stop: stop value of the sweep source
    step: the step size in the sweep
    source: string, the name of the source to be swept
    sweep_type: either options.dc_lin_step (default) or options.dc_log_step
    guess: op_analysis will guess to start the first NR iteration for the first point,
           the previsious dc is used from then on
    outfile: string, filename of the output file. If set to 'stdout', prints to screen.
    verbose: verbosity level

    Returns:
    * A results.dc_solution instance, if a solution was found for at least one sweep value.
    * None, if an error occurred (eg invalid start/stop/step values) or there was no solution
      for any sweep value.
    """
    if outfile == 'stdout':
        verbose = 0
    printing.print_info_line(("Starting DC analysis:", 2), verbose)
    elem_type, elem_descr = source[0].lower(), source.lower()  # eg. 'v', 'v34'
    sweep_label = elem_type[0].upper() + elem_descr[1:]

    if sweep_type == options.dc_log_step and stop - start < 0:
        printing.print_general_error(
            "DC analysis has log sweeping and negative stepping.")
        sys.exit(1)
    if (stop - start) * step < 0:
        raise ValueError, "Unbonded stepping in DC analysis."

    points = (stop - start) / step + 1
    sweep_type = sweep_type.upper()[:3]

    if sweep_type == options.dc_log_step:
        dc_iter = utilities.log_axis_iterator(stop, start, nsteps=points)
    elif sweep_type == options.dc_lin_step:
        dc_iter = utilities.lin_axis_iterator(stop, start, nsteps=points)
    else:
        printing.print_general_error("Unknown sweep type: %s" % (sweep_type, ))
        sys.exit(1)

    if elem_type != 'v' and elem_type != 'i':
        printing.print_general_error(
            "Sweeping is possible only with voltage and current sources. (" +
            str(elem_type) + ")")
        sys.exit(1)

    source_elem = None
    for index in xrange(len(circ)):
        if circ[index].part_id.lower() == elem_descr:
            if elem_type == 'v':
                if isinstance(circ[index], devices.VSource):
                    source_elem = circ[index]
                    break
            if elem_type == 'i':
                if isinstance(circ[index], devices.ISource):
                    source_elem = circ[index]
                    break
    if not source_elem:
        printing.print_general_error("%s was not found." % source[0].part_id)
        sys.exit(1)

    if isinstance(source_elem, devices.VSource):
        initial_value = source_elem.dc_value
    else:
        initial_value = source_elem.dc_value

    # If the initial value is set to None, op_analysis will attempt a smart guess (if guess),
    # Then for each iteration, the last result is used as x0, since op_analysis will not
    # attempt to guess the op if x0 is not None.
    x = x0

    sol = results.dc_solution(circ,
                              start,
                              stop,
                              sweepvar=sweep_label,
                              stype=sweep_type,
                              outfile=outfile)

    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick = ticker.ticker(1)
    tick.display(verbose > 2)

    # sweep setup

    # tarocca il generatore di tensione, avvia DC silenziosa, ritarocca etc
    index = 0
    for sweep_value in dc_iter:
        index = index + 1
        if isinstance(source_elem, devices.VSource):
            source_elem.dc_value = sweep_value
        else:
            source_elem.dc_value = sweep_value
        # silently calculate the op
        x = op_analysis(circ, x0=x, guess=guess, verbose=0)
        if x is None:
            tick.hide(verbose > 2)
            if not options.dc_sweep_skip_allowed:
                print "Could't solve the circuit for sweep value:", start + index * step
                solved = False
                break
            else:
                print "Skipping sweep value:", start + index * step
                continue
        solved = True
        sol.add_op(sweep_value, x)

        tick.step(verbose > 2)

    tick.hide(verbose > 2)
    if solved:
        printing.print_info_line(("done", 3), verbose)

    # clean up
    if isinstance(source_elem, devices.VSource):
        source_elem.dc_value = initial_value
    else:
        source_elem.dc_value = initial_value

    return sol if solved else None
Пример #21
0
def dc_solve(mna,
             Ndc,
             circ,
             Ntran=None,
             Gmin=None,
             x0=None,
             time=None,
             MAXIT=None,
             locked_nodes=None,
             skip_Tt=False,
             verbose=3):
    """Tries to perform a DC analysis of the circuit.
    The system we want to solve is:
    (mna+Gmin)*x + N + T(x) = 0

    mna is the reduced mna matrix with the required KVL rows
    N is Ndc + Ntran
    T(x) will be built.

    circ is the circuit instance from which mna, N were built.

    x0 is the (optional) initial guess. If not specified, the all-zeros vector will be used

    This method is used ever by transient analysis. For transient analysis, time has to be set.
    In "real" DC analysis, time may be left to None. See circuit.py for more info about the default
    behaviour of time variant sources that also have a dc value.

    MAXIT is the maximum number of NR iteration to be supplied to mdn_solver.

    locked_nodes: array of tuples of nodes controlling non linear elements of the circuit.
    This is generated by circ.get_locked_nodes() and will be generated that way if left to none.
    However, if you are doing lots of simulations of the same circuit (a transient analysis), it's
    a good idea to generate it only once.

    Returns:
    (x, error, converged, tot_iterations)
    """
    if MAXIT == None:
        MAXIT = options.dc_max_nr_iter
    if locked_nodes is None:
        locked_nodes = circ.get_locked_nodes()
    mna_size = mna.shape[0]
    nv = len(circ.nodes_dict)
    tot_iterations = 0

    if Gmin is None:
        Gmin = 0

    if Ntran is None:
        Ntran = 0

    # time variable component: Tt this is always the same in each iter. So we
    # build it once for all.
    Tt = numpy.mat(numpy.zeros((mna_size, 1)))
    v_eq = 0
    if not skip_Tt:
        for elem in circ:
            if (isinstance(elem, devices.VSource) or isinstance(
                    elem, devices.ISource)) and elem.is_timedependent:
                if isinstance(elem, devices.VSource):
                    Tt[nv - 1 + v_eq, 0] = -1 * elem.V(time)
                elif isinstance(elem, devices.ISource):
                    if elem.n1:
                        Tt[elem.n1 - 1, 0] = Tt[elem.n1 - 1, 0] + elem.I(time)
                    if elem.n2:
                        Tt[elem.n2 - 1, 0] = Tt[elem.n2 - 1, 0] - elem.I(time)
            if circuit.is_elem_voltage_defined(elem):
                v_eq = v_eq + 1
    # update N to include the time variable sources
    Ndc = Ndc + Tt

    # initial guess, if specified, otherwise it's zero
    if x0 is not None:
        if isinstance(x0, results.op_solution):
            x = x0.asmatrix()
        else:
            x = x0
    else:
        x = numpy.mat(numpy.zeros((mna_size, 1)))
        # has n-1 rows because of discard of ^^^

    converged = False
    standard_solving, gmin_stepping, source_stepping = get_solve_methods()
    standard_solving, gmin_stepping, source_stepping = set_next_solve_method(
        standard_solving, gmin_stepping, source_stepping, verbose)

    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)

    while (not converged):
        if standard_solving["enabled"]:
            mna_to_pass = mna + Gmin
            N_to_pass = Ndc + Ntran * (Ntran is not None)
        elif gmin_stepping["enabled"]:
            # print "gmin index:", str(gmin_stepping["index"])+", gmin:", str(
            # 10**(gmin_stepping["factors"][gmin_stepping["index"]]))
            printing.print_info_line(
                ("Setting Gmin to: " +
                 str(10**gmin_stepping["factors"][gmin_stepping["index"]]), 6),
                verbose)
            mna_to_pass = build_gmin_matrix(
                circ, 10**(gmin_stepping["factors"][gmin_stepping["index"]]),
                mna_size, verbose) + mna
            N_to_pass = Ndc + Ntran * (Ntran is not None)
        elif source_stepping["enabled"]:
            printing.print_info_line(("Setting sources to " + str(
                source_stepping["factors"][source_stepping["index"]] * 100) +
                                      "% of their actual value", 6), verbose)
            mna_to_pass = mna + Gmin
            N_to_pass = source_stepping["factors"][
                source_stepping["index"]] * Ndc + Ntran * (Ntran is not None)
        try:
            (x, error, converged, n_iter,
             convergence_by_node) = mdn_solver(x,
                                               mna_to_pass,
                                               circ,
                                               T=N_to_pass,
                                               nv=nv,
                                               print_steps=(verbose > 0),
                                               locked_nodes=locked_nodes,
                                               time=time,
                                               MAXIT=MAXIT,
                                               debug=(verbose == 6))
            tot_iterations += n_iter
        except numpy.linalg.linalg.LinAlgError:
            n_iter = 0
            converged = False
            print "failed."
            printing.print_general_error("J Matrix is singular")
        except OverflowError:
            n_iter = 0
            converged = False
            print "failed."
            printing.print_general_error("Overflow")

        if not converged:
            if verbose == 6:
                for ivalue in range(len(convergence_by_node)):
                    if not convergence_by_node[ivalue] and ivalue < nv - 1:
                        print "Convergence problem node %s" % (
                            circ.int_node_to_ext(ivalue), )
                    elif not convergence_by_node[ivalue] and ivalue >= nv - 1:
                        e = circ.find_vde(ivalue)
                        print "Convergence problem current in %s" % e.part_id
            if n_iter == MAXIT - 1:
                printing.print_general_error("Error: MAXIT exceeded (" +
                                             str(MAXIT) + ")")
            if more_solve_methods_available(standard_solving, gmin_stepping,
                                            source_stepping):
                standard_solving, gmin_stepping, source_stepping = set_next_solve_method(
                    standard_solving, gmin_stepping, source_stepping, verbose)
            else:
                # print "Giving up."
                x = None
                error = None
                break
        else:
            printing.print_info_line(("[%d iterations]" % (n_iter, ), 6),
                                     verbose)
            if (source_stepping["enabled"] and source_stepping["index"] != 9):
                converged = False
                source_stepping["index"] = source_stepping["index"] + 1
            elif (gmin_stepping["enabled"] and gmin_stepping["index"] != 9):
                gmin_stepping["index"] = gmin_stepping["index"] + 1
                converged = False
            else:
                printing.print_info_line((" done.", 3), verbose)
    return (x, error, converged, tot_iterations)
Пример #22
0
def ac_analysis(circ, start, points, stop, sweep_type, x0=None,
                mna=None, AC=None, Nac=None, J=None,
                outfile="stdout", verbose=3):
    """Performs an AC analysis of the circuit described by circ.

    Parameters:
    start (float): the start angular frequency for the AC analysis
    stop (float): stop angular frequency
    points (float): the number of points to be use the discretize the
                    [start, stop] interval.
    sweep_type (string): Either 'LOG' or 'LINEAR', defaults to 'LOG'.
    outfile (string): the filename of the output file where the results will be written.
                      '.ac' is automatically added at the end to prevent different
                      analyses from overwriting each-other's results.
                      If unset or set to None, defaults to stdout.
    verbose (int): the verbosity level, from 0 (silent) to 6 (debug).

    Returns: an AC results object
        """

    if outfile == 'stdout':
        verbose = 0

    # check step/start/stop parameters
    nsteps = points - 1
    if start == 0:
        printing.print_general_error("AC analysis has start frequency = 0")
        sys.exit(5)
    if start > stop:
        printing.print_general_error("AC analysis has start > stop")
        sys.exit(1)
    if nsteps < 1:
        printing.print_general_error("AC analysis has number of steps <= 1")
        sys.exit(1)
    if sweep_type == options.ac_log_step:
        omega_iter = utilities.log_axis_iterator(stop, start, nsteps)
    elif sweep_type == options.ac_lin_step:
        omega_iter = utilities.lin_axis_iterator(stop, start, nsteps)
    else:
        printing.print_general_error("Unknown sweep type.")
        sys.exit(1)

    tmpstr = "Vea =", options.vea, "Ver =", options.ver, "Iea =", options.iea, "Ier =", \
        options.ier, "max_ac_nr_iter =", options.ac_max_nr_iter
    printing.print_info_line((tmpstr, 5), verbose)
    del tmpstr

    printing.print_info_line(("Starting AC analysis: ", 1), verbose)
    tmpstr = "w: start = %g Hz, stop = %g Hz, %d steps" % (start, stop, nsteps)
    printing.print_info_line((tmpstr, 3), verbose)
    del tmpstr

    # It's a good idea to call AC with prebuilt MNA matrix if the circuit is
    # big
    if mna is None:
        (mna, N) = dc_analysis.generate_mna_and_N(circ, verbose=verbose)
        del N
        mna = utilities.remove_row_and_col(mna)
    if Nac is None:
        Nac = generate_Nac(circ)
        Nac = utilities.remove_row(Nac, rrow=0)
    if AC is None:
        AC = generate_AC(circ, [mna.shape[0], mna.shape[0]])
        AC = utilities.remove_row_and_col(AC)

    if circ.is_nonlinear():
        if J is not None:
            pass
            # we used the supplied linearization matrix
        else:
            if x0 is None:
                printing.print_info_line(
                    ("Starting OP analysis to get a linearization point...", 3), verbose, print_nl=False)
                # silent OP
                x0 = dc_analysis.op_analysis(circ, verbose=0)
                if x0 is None:  # still! Then op_analysis has failed!
                    printing.print_info_line(("failed.", 3), verbose)
                    printing.print_general_error(
                        "OP analysis failed, no linearization point available. Quitting.")
                    sys.exit(3)
                else:
                    printing.print_info_line(("done.", 3), verbose)
            printing.print_info_line(
                ("Linearization point (xop):", 5), verbose)
            if verbose > 4:
                x0.print_short()
            printing.print_info_line(
                ("Linearizing the circuit...", 5), verbose, print_nl=False)
            J = generate_J(xop=x0.asmatrix(), circ=circ, mna=mna,
                           Nac=Nac, data_filename=outfile, verbose=verbose)
            printing.print_info_line((" done.", 5), verbose)
            # we have J, continue
    else:  # not circ.is_nonlinear()
        # no J matrix is required.
        J = 0

    printing.print_info_line(("MNA (reduced):", 5), verbose)
    printing.print_info_line((str(mna), 5), verbose)
    printing.print_info_line(("AC (reduced):", 5), verbose)
    printing.print_info_line((str(AC), 5), verbose)
    printing.print_info_line(("J (reduced):", 5), verbose)
    printing.print_info_line((str(J), 5), verbose)
    printing.print_info_line(("Nac (reduced):", 5), verbose)
    printing.print_info_line((str(Nac), 5), verbose)

    sol = results.ac_solution(circ, ostart=start, ostop=stop,
                              opoints=nsteps, stype=sweep_type, op=x0, outfile=outfile)

    # setup the initial values to start the iteration:
    nv = len(circ.nodes_dict)
    j = numpy.complex('j')

    Gmin_matrix = dc_analysis.build_gmin_matrix(
        circ, options.gmin, mna.shape[0], verbose)

    iter_n = 0  # contatore d'iterazione
    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick = ticker.ticker(increments_for_step=1)
    tick.display(verbose > 1)

    x = x0
    for omega in omega_iter:
        (x, error, solved, n_iter) = dc_analysis.dc_solve(
            mna=(mna + numpy.multiply(j * omega, AC) + J),
            Ndc = Nac,
            Ntran = 0,
            circ = circuit.Circuit(
                title="Dummy circuit for AC", filename=None),
            Gmin = Gmin_matrix,
            x0 = x,
            time = None,
            locked_nodes = None,
            MAXIT = options.ac_max_nr_iter,
            skip_Tt = True,
            verbose = 0)
        if solved:
            tick.step(verbose > 1)
            iter_n = iter_n + 1
            # hooray!
            sol.add_line(omega, x)
        else:
            break

    tick.hide(verbose > 1)

    if solved:
        printing.print_info_line(("done.", 1), verbose)
        ret_value = sol
    else:
        printing.print_info_line(("failed.", 1), verbose)
        ret_value = None

    return ret_value
Пример #23
0
def dc_solve(
    mna, Ndc, circ, Ntran=None, Gmin=None, x0=None, time=None, MAXIT=None, locked_nodes=None, skip_Tt=False, verbose=3
):
    """Tries to perform a DC analysis of the circuit. 
	The system we want to solve is:
	(mna+Gmin)*x + N + T(x) = 0
	
	mna is the reduced mna matrix with the required KVL rows
	N is Ndc + Ntran
	T(x) will be built.
	
	circ is the circuit instance from which mna, N were built.
	
	x0 is the (optional) initial guess. If not specified, the all-zeros vector will be used
	
	This method is used ever by transient analysis. For transient analysis, time has to be set.
	In "real" DC analysis, time may be left to None. See circuit.py for more info about the default
	behaviour of time variant sources that also have a dc value.
	
	MAXIT is the maximum number of NR iteration to be supplied to mdn_solver.
	
	locked_nodes: array of tuples of nodes controlling non linear elements of the circuit.
	This is generated by circ.get_locked_nodes() and will be generated that way if left to none.
	However, if you are doing lots of simulations of the same circuit (a transient analysis), it's
	a good idea to generate it only once.

	Returns:
	(x, error, converged, tot_iterations)
	"""
    if MAXIT == None:
        MAXIT = options.dc_max_nr_iter
    if locked_nodes is None:
        locked_nodes = circ.get_locked_nodes()
    mna_size = mna.shape[0]
    nv = len(circ.nodes_dict)
    tot_iterations = 0

    if Gmin is None:
        Gmin = 0

    if Ntran is None:
        Ntran = 0

        # time variable component: Tt this is always the same in each iter. So we build it once for all.
    Tt = numpy.mat(numpy.zeros((mna_size, 1)))
    v_eq = 0
    if not skip_Tt:
        for elem in circ.elements:
            if (isinstance(elem, devices.vsource) or isinstance(elem, devices.isource)) and elem.is_timedependent:
                if isinstance(elem, devices.vsource):
                    Tt[nv - 1 + v_eq, 0] = -1 * elem.V(time)
                elif isinstance(elem, devices.isource):
                    if elem.n1:
                        Tt[elem.n1 - 1, 0] = Tt[elem.n1 - 1, 0] + elem.I(time)
                    if elem.n2:
                        Tt[elem.n2 - 1, 0] = Tt[elem.n2 - 1, 0] - elem.I(time)
            if circuit.is_elem_voltage_defined(elem):
                v_eq = v_eq + 1
                # update N to include the time variable sources
    Ndc = Ndc + Tt

    # initial guess, if specified, otherwise it's zero
    if x0 is not None:
        if isinstance(x0, results.op_solution):
            x = x0.asmatrix()
        else:
            x = x0
    else:
        x = numpy.mat(numpy.zeros((mna_size, 1)))  # has n-1 rows because of discard of ^^^

    converged = False
    standard_solving, gmin_stepping, source_stepping = get_solve_methods()
    standard_solving, gmin_stepping, source_stepping = set_next_solve_method(
        standard_solving, gmin_stepping, source_stepping, verbose
    )

    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)

    while not converged:
        if standard_solving["enabled"]:
            mna_to_pass = mna + Gmin
            N_to_pass = Ndc + Ntran * (Ntran is not None)
        elif gmin_stepping["enabled"]:
            # print "gmin index:", str(gmin_stepping["index"])+", gmin:", str( 10**(gmin_stepping["factors"][gmin_stepping["index"]]))
            printing.print_info_line(
                ("Setting Gmin to: " + str(10 ** gmin_stepping["factors"][gmin_stepping["index"]]), 6), verbose
            )
            mna_to_pass = (
                build_gmin_matrix(circ, 10 ** (gmin_stepping["factors"][gmin_stepping["index"]]), mna_size, verbose)
                + mna
            )
            N_to_pass = Ndc + Ntran * (Ntran is not None)
        elif source_stepping["enabled"]:
            printing.print_info_line(
                (
                    "Setting sources to "
                    + str(source_stepping["factors"][source_stepping["index"]] * 100)
                    + "% of their actual value",
                    6,
                ),
                verbose,
            )
            mna_to_pass = mna + Gmin
            N_to_pass = source_stepping["factors"][source_stepping["index"]] * Ndc + Ntran * (Ntran is not None)
        try:
            (x, error, converged, n_iter, convergence_by_node) = mdn_solver(
                x,
                mna_to_pass,
                circ,
                T=N_to_pass,
                nv=nv,
                print_steps=(verbose > 0),
                locked_nodes=locked_nodes,
                time=time,
                MAXIT=MAXIT,
                debug=(verbose == 6),
            )
            tot_iterations += n_iter
        except numpy.linalg.linalg.LinAlgError:
            n_iter = 0
            converged = False
            print "failed."
            printing.print_general_error("J Matrix is singular")
        except OverflowError:
            n_iter = 0
            converged = False
            print "failed."
            printing.print_general_error("Overflow")

        if not converged:
            if verbose == 6:
                for ivalue in range(len(convergence_by_node)):
                    if not convergence_by_node[ivalue] and ivalue < nv - 1:
                        print "Convergence problem node %s" % (circ.int_node_to_ext(ivalue),)
                    elif not convergence_by_node[ivalue] and ivalue >= nv - 1:
                        e = circ.find_vde(ivalue)
                        print "Convergence problem current in %s%s" % (e.letter_id, e.descr)
            if n_iter == MAXIT - 1:
                printing.print_general_error("Error: MAXIT exceeded (" + str(MAXIT) + ")")
            if more_solve_methods_available(standard_solving, gmin_stepping, source_stepping):
                standard_solving, gmin_stepping, source_stepping = set_next_solve_method(
                    standard_solving, gmin_stepping, source_stepping, verbose
                )
            else:
                # print "Giving up."
                x = None
                error = None
                break
        else:
            printing.print_info_line(("[%d iterations]" % (n_iter,), 6), verbose)
            if source_stepping["enabled"] and source_stepping["index"] != 9:
                converged = False
                source_stepping["index"] = source_stepping["index"] + 1
            elif gmin_stepping["enabled"] and gmin_stepping["index"] != 9:
                gmin_stepping["index"] = gmin_stepping["index"] + 1
                converged = False
            else:
                printing.print_info_line((" done.", 3), verbose)
    return (x, error, converged, tot_iterations)
Пример #24
0
def dc_analysis(
    circ,
    start,
    stop,
    step,
    type_descr,
    xguess=None,
    data_filename="stdout",
    print_int_nodes=True,
    guess=True,
    stype="LINEAR",
    verbose=2,
):
    """Performs a sweep of the value of V or I of a independent source from start 
	value to stop value using the provided step. 
	For every circuit generated, computes the op and prints it out.
	This function relays on dc_analysis.op_analysis to actually solve each circuit.
	
	circ: the circuit instance to be simulated
	start: start value of the sweep source
	stop: stop value of the sweep source
	step: step value of the sweep source
	elem_type: string, may be 'vsource' or 'isource'
	elem_descr: the description of the element, used to recognize it in circ (i.e v<desc>)
	data_filename: string, filename of the output file. If set to stdout, prints to screen
	print_int_nodes: do it
	guess: op_analysis will guess to start the first NR iteration for the first point, the previsious dc is used from then on
	verbose: verbosity level
	
	Returns:
	A results.dc_solution instance, if a solution was found for at least one sweep value.
	None, if an error occurred (eg invalid start/stop/step values) or there was no solution
	for any sweep value.
	"""
    if data_filename == "stdout":
        verbose = 0
    printing.print_info_line(("Starting DC analysis:", 2), verbose)
    (elem_type, elem_descr) = type_descr
    sweep_label = elem_type[0].upper() + elem_descr

    # check step/start/stop parameters
    if step == 0:
        printing.print_general_error("Can't sweep with step=0 !")
        sys.exit(1)
    if start > stop:
        printing.print_general_error("DC analysis has start > stop")
        sys.exit(1)
    if (stop - start) / step < 1:
        printing.print_general_error("DC analysis has number of steps < 1")
        sys.exit(1)
    if stype == options.dc_log_step:
        dc_iter = utilities.log_axis_iterator(stop, start, nsteps=int(stop - start) / step)
    elif stype == options.dc_lin_step:
        dc_iter = utilities.lin_axis_iterator(stop, start, nsteps=int(stop - start) / step)
    else:
        printing.print_general_error("Unknown sweep type: %s" % (stype,))
        sys.exit(1)

    if elem_type != "vsource" and elem_type != "isource":
        printing.print_general_error(
            "Sweeping is possible only with voltage and current sources. (" + str(elem_type) + ")"
        )
        sys.exit(1)

    source_elem = None
    for index in xrange(len(circ.elements)):
        if circ.elements[index].descr == elem_descr:
            if elem_type == "vsource":
                if isinstance(circ.elements[index], devices.vsource):
                    source_elem = circ.elements[index]
                    break
            if elem_type == "isource":
                if isinstance(circ.elements[index], devices.isource):
                    source_elem = circ.elements[index]
                    break
    if not source_elem:
        printing.print_general_error(elem_type + " element with descr. " + elem_descr + " was not found.")
        sys.exit(1)

    if isinstance(source_elem, devices.vsource):
        initial_value = source_elem.vdc
    else:
        initial_value = source_elem.idc

        # The initial value is set to None and this IS CORRECT.
        # op_analysis will attempt to do a smart guess, if called with x0 = None and guess=True
        # For each iteration over the source voltage (current) value, the last result is used as x0.
        # op_analysis will not attempt to guess the op if x0 is not None
    x = None

    sol = results.dc_solution(circ, start, stop, sweepvar=sweep_label, stype=stype, outfile=data_filename)

    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick = ticker.ticker(1)
    tick.display(verbose > 2)

    # sweep setup

    # tarocca il generatore di tensione, avvia DC silenziosa, ritarocca etc
    index = 0
    for sweep_value in dc_iter:
        index = index + 1
        if isinstance(source_elem, devices.vsource):
            source_elem.vdc = sweep_value
        else:
            source_elem.idc = sweep_value
            # silently calculate the op
        op = op_analysis(circ, x0=x, guess=guess, verbose=0)
        if op is None:
            tick.hide(verbose > 2)
            if not options.dc_sweep_skip_allowed:
                print "Could't solve the circuit for sweep value:", start + index * step
                solved = False
                break
            else:
                print "Skipping sweep value:", start + index * step
                continue
        solved = True
        sol.add_op(sweep_value, op)

        if guess:
            guess = False

        tick.step(verbose > 2)

    tick.hide(verbose > 2)
    if solved:
        printing.print_info_line(("done", 3), verbose)

        # clean up
    if isinstance(source_elem, devices.vsource):
        source_elem.vdc = initial_value
    else:
        source_elem.idc = initial_value

    return sol if solved else None
Пример #25
0
def solve(circ, tf_source=None, subs=None, opts=None, verbose=3):
	"""Attempt a symbolic solution of the circuit.
	circ: the circuit instance to be simulated.
	tf_source: the name (string) of the source to be used as input for the transfer
		   function. If None, no transfer function is evaluated.
	subs: a dictionary of sympy Symbols to be substituted. It makes solving the circuit 
	      easier. Eg. {R1:R2} - replace R1 with R2. It can be generated with 
	      parse_substitutions()
	opts: dict of 'option':boolean to be taken into account in simulation.
	      currently 'r0s' and 'ac' are the only options considered.
	verbose: verbosity level 0 (silent) to 6 (painful).
	
	Returns: a dictionary with the solutions.
	"""
	if opts is None:
		# load the defaults
		opts = {'r0s':True, 'ac':False}
	if not 'r0s' in opts.keys():
		opts.update({'r0s':True})
	if not 'ac' in opts.keys():
		opts.update({'ac':False})
	if subs is None:
		subs = {} # no subs by default

	if not opts['ac']:
		printing.print_info_line(("Starting symbolic DC...", 1), verbose)
	else:
		printing.print_info_line(("Starting symbolic AC...", 1), verbose)		
		
	printing.print_info_line(("Building symbolic MNA, N and x...", 2), verbose, print_nl=False)
	mna, N, subs_g = generate_mna_and_N(circ, opts, opts['ac'])
	x = get_variables(circ)
	mna = mna[1:, 1:]
	N = N[1:, :]
	printing.print_info_line((" done.", 2), verbose)	

	printing.print_info_line(("Performing variable substitutions...", 5), verbose)
	mna, N = apply_substitutions(mna, N, subs)

	printing.print_info_line(("MNA matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(mna)
	printing.print_info_line(("N matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(N)

	printing.print_info_line(("Building equations...", 2), verbose)	
	eq = []
	for i in to_real_list(mna * x + N):
		eq.append(sympy.Eq(i, 0))

	x = to_real_list(x)
	if verbose > 4:
		printing.print_symbolic_equations(eq)
		print "To be solved for:"
		print x
		#print "Matrix is singular: ", (mna.det() == 0)
	#print -1.0*mna.inv()*N #too heavy
	#print sympy.solve_linear_system(mna.row_join(-N), x)
	printing.print_info_line(("Performing auxiliary simplification...", 2), verbose)	
	eq, x, sol_h = help_the_solver(eq, x)
		
	if len(eq):
		if verbose > 3:
			print "Symplified sytem:"
			printing.print_symbolic_equations(eq)
			print "To be solved for:"
			print x
			printing.print_info_line(("Solving...", 2), verbose)	

		if options.symb_internal_solver:
			sol = local_solve(eq, x)
		else:
			sol = sympy.solve(eq, x, manual=options.symb_sympy_manual_solver, simplify=True)
		if sol is not None:		
			sol.update(sol_h)
		else:
			sol = sol_h
	else:
		printing.print_info_line(("Auxiliary simplification solved the problem.", 3), verbose)	
		sol = sol_h

	for ks in sol.keys():
		sol.update({ks:sol[ks].subs(subs_g)})

	#sol = sol_to_dict(sol, x)

	if sol == {}:
		printing.print_warning("No solutions. Check the netlist.")
	else:
		printing.print_info_line(("Success!", 2), verbose)	
		if verbose > 1:
			print "Results:"
		printing.print_symbolic_results(sol)

	if tf_source is not None:
		src = sympy.Symbol(tf_source.upper(), real=True)
		printing.print_info_line(("Calculating small-signal symbolic transfer functions (%s))..."%(str(src),), 2), verbose, print_nl=False)
		tfs = calculate_gains(sol, src)
		printing.print_info_line(("done.", 2), verbose)	
		printing.print_info_line(("Small-signal symbolic transfer functions:", 1), verbose)	
		printing.print_symbolic_transfer_functions(tfs)
	else:
		tfs = None
	
	return sol, tfs
Пример #26
0
def transient_analysis(circ, tstart, tstep, tstop, method=TRAP, x0=None, mna=None, N=None, \
	D=None, data_filename="stdout", use_step_control=True, return_req_dict=None, verbose=3):
	"""Performs a transient analysis of the circuit described by circ.
	
	Important parameters:
	- tstep is the maximum step to be allowed during simulation.
	- print_step_and_lte is a boolean value. Is set to true, the step and the LTE of the first
	element of x will be printed out to step_and_lte.graph in the current directory.
	
	"""
	if data_filename == "stdout":
		verbose = 0
	_debug = False
	if _debug:
		print_step_and_lte = True
	else:
		print_step_and_lte = False
	
	HMAX = tstep
	
	#check parameters
	if tstart > tstop:
		printing.print_general_error("tstart > tstop")
		sys.exit(1)
	if tstep < 0:
		printing.print_general_error("tstep < 0")
		sys.exit(1)

	if verbose > 4:
		tmpstr = "Vea = %g Ver = %g Iea = %g Ier = %g max_time_iter = %g HMIN = %g" % \
		(options.vea, options.ver, options.iea, options.ier, options.transient_max_time_iter, options.hmin)
		printing.print_info_line((tmpstr, 5), verbose)
	
	locked_nodes = circ.get_locked_nodes()
	
	if print_step_and_lte:
		flte = open("step_and_lte.graph", "w")
		flte.write("#T\tStep\tLTE\n")
	
	printing.print_info_line(("Starting transient analysis: ", 3), verbose)
	printing.print_info_line(("Selected method: %s" % (method,), 3), verbose)
	#It's a good idea to call transient with prebuilt MNA and N matrix
	#the analysis will be slightly faster (long netlists). 
	if mna is None or N is None:
		(mna, N) = dc_analysis.generate_mna_and_N(circ)
		mna = utilities.remove_row_and_col(mna)
		N = utilities.remove_row(N, rrow=0)
	elif not mna.shape[0] == N.shape[0]:
		printing.print_general_error("mna matrix and N vector have different number of columns.")
		sys.exit(0)
	if D is None:
		# if you do more than one tran analysis, output streams should be changed...
		# this needs to be fixed
		D = generate_D(circ, [mna.shape[0], mna.shape[0]])
		D = utilities.remove_row_and_col(D)

	# setup x0
	if x0 is None:
		printing.print_info_line(("Generating x(t=%g) = 0" % (tstart,), 5), verbose)
		x0 = numpy.matrix(numpy.zeros((mna.shape[0], 1)))
		opsol =  results.op_solution(x=x0, error=x0, circ=circ, outfile=None)
	else:
		if isinstance(x0, results.op_solution):
			opsol = x0
			x0 = x0.asmatrix()
		else:
			opsol =  results.op_solution(x=x0, error=numpy.matrix(numpy.zeros((mna.shape[0], 1))), circ=circ, outfile=None)
		printing.print_info_line(("Using the supplied op as x(t=%g)." % (tstart,), 5), verbose)
		
	if verbose > 4:
		print "x0:"
		opsol.print_short()
	
	# setup the df method
	printing.print_info_line(("Selecting the appropriate DF ("+method+")... ", 5), verbose, print_nl=False)
	if method == IMPLICIT_EULER:
		import implicit_euler as df
	elif method == TRAP:
		import trap as df
	elif method == GEAR1:
		import gear as df
		df.order = 1
	elif method == GEAR2:
		import gear as df
		df.order = 2
	elif method == GEAR3:
		import gear as df
		df.order = 3
	elif method == GEAR4:
		import gear as df
		df.order = 4
	elif method == GEAR5:
		import gear as df
		df.order = 5
	elif method == GEAR6:
		import gear as df
		df.order = 6
	else:
		df = import_custom_df_module(method, print_out=(data_filename != "stdout"))
		# df is none if module is not found
	
	if df is None:
		sys.exit(23)
		
	if not df.has_ff() and use_step_control:
		printing.print_warning("The chosen DF does not support step control. Turning off the feature.")
		use_step_control = False
		#use_aposteriori_step_control = False

	printing.print_info_line(("done.", 5), verbose)
		
	# setup the data buffer
	# if you use the step control, the buffer has to be one point longer.
	# That's because the excess point is used by a FF in the df module to predict the next value.
	printing.print_info_line(("Setting up the buffer... ", 5), verbose, print_nl=False)
	((max_x, max_dx), (pmax_x, pmax_dx)) = df.get_required_values()
	if max_x is None and max_dx is None:
		printing.print_general_error("df doesn't need any value?")
		sys.exit(1)
	if use_step_control:
		thebuffer = dfbuffer(length=max(max_x, max_dx, pmax_x, pmax_dx) + 1, width=3)
	else:
		thebuffer = dfbuffer(length=max(max_x, max_dx) + 1, width=3)
	thebuffer.add((tstart, x0, None)) #setup the first values
	printing.print_info_line(("done.", 5), verbose) #FIXME
	
	#setup the output buffer
	if return_req_dict:
		output_buffer = dfbuffer(length=return_req_dict["points"], width=1)
		output_buffer.add((x0,))
	else:
		output_buffer = None
	
	# import implicit_euler to be used in the first iterations
	# this is because we don't have any dx when we start, nor any past point value
	if (max_x is not None and max_x > 0) or max_dx is not None:
		import implicit_euler
	
	printing.print_info_line(("MNA (reduced):", 5), verbose)
	printing.print_info_line((str(mna), 5), verbose)
	printing.print_info_line(("D (reduced):", 5), verbose)
	printing.print_info_line((str(D), 5), verbose)
	
	# setup the initial values to start the iteration:
	x = None
	time = tstart
	nv = len(circ.nodes_dict)

	Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose)

	# lo step viene generato automaticamente, ma non superare mai quello fornito.
	if use_step_control:
		#tstep = min((tstop-tstart)/9999.0, HMAX, 100.0 * options.hmin)
		tstep = min((tstop-tstart)/9999.0, HMAX)
	printing.print_info_line(("Initial step: %g"% (tstep,), 5), verbose)

	if max_dx is None:
		max_dx_plus_1 = None
	else:
		max_dx_plus_1 = max_dx +1
	if pmax_dx is None:
		pmax_dx_plus_1 = None
	else:
		pmax_dx_plus_1 = pmax_dx +1
	
	# setup error vectors
	aerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
	aerror[:nv-1, 0] = options.vea
	aerror[nv-1:, 0] = options.vea
	rerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
	rerror[:nv-1, 0] = options.ver
	rerror[nv-1:, 0] = options.ier
	
	iter_n = 0  # contatore d'iterazione
	lte = None
	sol = results.tran_solution(circ, tstart, tstop, op=x0, method=method, outfile=data_filename)
	printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
	tick = ticker.ticker(increments_for_step=1)
	tick.display(verbose > 1)
	while time < tstop:
		if iter_n < max(max_x, max_dx_plus_1):
			x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff = \
			implicit_euler.get_df((thebuffer.get_df_vector()[0],), tstep, \
			predict=(use_step_control and (iter_n >= max(pmax_x, pmax_dx_plus_1))))
			
		else:
			[x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff] = \
			df.get_df(thebuffer.get_df_vector(), tstep, predict=use_step_control)
		
		if options.transient_prediction_as_x0 and use_step_control and prediction is not None:
			x0 = prediction
		elif x is not None:
			x0 = x
		
		(x1, error, solved, n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(x_coeff, D)) , Ndc=N,  Ntran=D*const, circ=circ, Gmin=Gmin_matrix, x0=x0, time=(time + tstep), locked_nodes=locked_nodes, MAXIT=options.transient_max_nr_iter, verbose=0)
		
		if solved:
			old_step = tstep #we will modify it, if we're using step control otherwise it's the same
			# step control (yeah)
			if use_step_control:
				if x_lte_coeff is not None and pred_lte_coeff is not None and prediction is not None:
					# this is the Local Truncation Error :)
					lte = abs((x_lte_coeff / (pred_lte_coeff - x_lte_coeff)) * (prediction - x1))
					# it should NEVER happen that new_step > 2*tstep, for stability
					new_step_coeff = 2 
					for index in xrange(x.shape[0]):
						if lte[index, 0] != 0:
							new_value = ((aerror[index, 0] + rerror[index, 0]*abs(x[index, 0])) / lte[index, 0]) \
							** (1.0 / (df.order+1))
							if new_value < new_step_coeff:
								new_step_coeff = new_value
							#print new_value
					new_step = tstep * new_step_coeff
					if options.transient_use_aposteriori_step_control and new_step < options.transient_aposteriori_step_threshold * tstep: 
						#don't recalculate a x for a small change
						tstep = check_step(new_step, time, tstop, HMAX)
						#print "Apost. (reducing) step = "+str(tstep)
						continue
					tstep = check_step(new_step, time, tstop, HMAX) # used in the next iteration
					#print "Apriori tstep = "+str(tstep)
				else:
					#print "LTE not calculated."
					lte = None
			if print_step_and_lte and lte is not None: 
				#if you wish to look at the step. We print just a lte
				flte.write(str(time)+"\t"+str(old_step)+"\t"+str(lte.max())+"\n")
			# if we get here, either aposteriori_step_control is 
			# disabled, or it's enabled and the error is small
			# enough. Anyway, the result is GOOD, STORE IT.
			time = time + old_step
			x = x1
			iter_n = iter_n + 1
			sol.add_line(time, x)
			
			dxdt = numpy.multiply(x_coeff, x) + const
			thebuffer.add((time, x, dxdt))
			if output_buffer is not None:
				output_buffer.add((x, ))
			tick.step(verbose > 1)
		else:
			# If we get here, Newton failed to converge. We need to reduce the step...
			if use_step_control:
				tstep = tstep/5.0
				tstep = check_step(tstep, time, tstop, HMAX)
				printing.print_info_line(("At %g s reducing step: %g s (convergence failed)" % (time, tstep), 5), verbose)
			else: #we can't reduce the step
				printing.print_general_error("Can't converge with step "+str(tstep)+".")
				printing.print_general_error("Try setting --t-max-nr to a higher value or set step to a lower one.")
				solved = False
				break
		if options.transient_max_time_iter and iter_n == options.transient_max_time_iter:
			printing.print_general_error("MAX_TIME_ITER exceeded ("+str(options.transient_max_time_iter)+"), iteration halted.")
			solved = False
			break
	
	if print_step_and_lte:
		flte.close()
	
	tick.hide(verbose > 1)
	
	if solved:
		printing.print_info_line(("done.", 3), verbose)
		printing.print_info_line(("Average time step: %g" % ((tstop - tstart)/iter_n,), 3), verbose)

		if output_buffer:
			ret_value = output_buffer.get_as_matrix()
		else:
			ret_value = sol
	else:
		print "failed."
		ret_value =  None
	
	return ret_value
Пример #27
0
def shooting(circ, period, step=None, x0=None, points=None, autonomous=False,
             mna=None, Tf=None, D=None, outfile='stdout', vector_norm=lambda v: max(abs(v)), verbose=3):
    """Performs a periodic steady state analysis based on the algorithm described in
    Brambilla, A.; D'Amore, D., "Method for steady-state simulation of
    strongly nonlinear circuits in the time domain," Circuits and
    Systems I: Fundamental Theory and Applications, IEEE Transactions on,
    vol.48, no.7, pp.885-889, Jul 2001
    URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=933329&isnumber=20194

    The results have been computed again by me, the formulas are not exactly the
    same, but the idea behind the shooting algorithm is.

    This method allows us to have a period with many points without having to
    invert a huge matrix (and being limited to the maximum matrix size).

    A tran is performed to initialize the solver.

    We compute the change in the last point, calculating several matrices in
    the process.
    From that, with the same matrices we calculate the changes in all points,
    starting from 0 (which is the same as the last one), then 1, ...

    Key points:
    - Only not autonomous circuits are supported.
    - The time step is constant
    - Implicit euler is used as DF

    Parameters:
    circ is the circuit description class
    period is the period of the solution
    mna, D, Tf are not compulsory they will be computed if they're set to None
    step is the time step between consecutive points
    points is the number of points to be used
    step and points are mutually exclusive options:
    - if step is specified, the number of points will be automatically determined
    - if points is set, the step will be automatically determined
    - if none of them is set, options.shooting_default_points will be used as points
    autonomous has to be False, autonomous circuits are not supported
    outfile is the output filename. Defaults to stdout.
    verbose is set to zero (print errors only) if datafilename == 'stdout'.

    Returns: nothing
    """

    if outfile == "stdout":
        verbose = 0

    printing.print_info_line(
        ("Starting periodic steady state analysis:", 3), verbose)
    printing.print_info_line(("Method: shooting", 3), verbose)

    if isinstance(x0, results.op_solution):
        x0 = x0.asmatrix()
    if mna is None or Tf is None:
        (mna, Tf) = dc_analysis.generate_mna_and_N(circ, verbose=verbose)
        mna = utilities.remove_row_and_col(mna)
        Tf = utilities.remove_row(Tf, rrow=0)
    elif not mna.shape[0] == Tf.shape[0]:
        printing.print_general_error(
            "mna matrix and N vector have different number of rows.")
        sys.exit(0)

    if D is None:
        D = transient.generate_D(circ, [mna.shape[0], mna.shape[0]])
        D = utilities.remove_row_and_col(D)
    elif not mna.shape == D.shape:
        printing.print_general_error(
            "mna matrix and D matrix have different sizes.")
        sys.exit(0)

    (points, step) = check_step_and_points(step, points, period)
    print "points", points
    print "step", step

    n_of_var = mna.shape[0]
    locked_nodes = circ.get_locked_nodes()

    printing.print_info_line(
        ("Starting transient analysis for algorithm init: tstop=%g, tstep=%g... " % (10 * points * step, step), 3), verbose, print_nl=False)
    xtran = transient.transient_analysis(
        circ=circ, tstart=0, tstep=step, tstop=10 * points * step, method="TRAP", x0=None, mna=mna, N=Tf,
        D=D, use_step_control=False, outfile=outfile + ".tran", return_req_dict={"points": points}, verbose=0)
    if xtran is None:
        print "failed."
        return None
    printing.print_info_line(("done.", 3), verbose)

    x = []
    for index in range(points):
        x.append(xtran[index * n_of_var:(index + 1) * n_of_var, 0])

    tick = ticker.ticker(increments_for_step=1)

    MAass_static, MBass = build_static_MAass_and_MBass(mna, D, step)

    # This contains
    # the time invariant part, Tf
    # time variable component: Tt this is always the same, since the time interval is the same
    # this holds all time-dependent sources (both V/I).
    Tass_static_vector = build_Tass_static_vector(
        circ, Tf, points, step, tick, n_of_var, verbose)

    converged = False
    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick.reset()
    tick.display(verbose > 2)

    iteration = 0  # newton iteration counter
    conv_counter = 0

    while True:
        dx = []
        Tass_variable_vector = []
        MAass_variable_vector = []
        for index in range(points):
            if index == 0:
                xn_minus_1 = x[points - 1]
            else:
                xn_minus_1 = x[index - 1]
            MAass_variable, Tass_variable = get_variable_MAass_and_Tass(
                circ, x[index], xn_minus_1, mna, D, step, n_of_var)
            MAass_variable_vector.append(MAass_variable + MAass_static)
            Tass_variable_vector.append(
                Tass_variable + Tass_static_vector[index])

        dxN = compute_dxN(circ, MAass_variable_vector, MBass,
                          Tass_variable_vector, n_of_var, points, verbose=verbose)
        td = dc_analysis.get_td(dxN, locked_nodes, n=-1)
        x[points - 1] = td * dxN + x[points - 1]

        for index in range(points - 1):
            if index == 0:
                dxi_minus_1 = dxN
            else:
                dxi_minus_1 = dx[index - 1]
            dx.append(
                compute_dx(MAass_variable_vector[index], MBass, Tass_variable_vector[index], dxi_minus_1))
            td = dc_analysis.get_td(dx[index], locked_nodes, n=-1)
            x[index] = td * dx[index] + x[index]
        dx.append(dxN)

        if (vector_norm_wrapper(dx, vector_norm) < min(options.ver, options.ier) * vector_norm_wrapper(x, vector_norm) + min(options.vea, options.iea)):  # \
        # and (dc_analysis.vector_norm(residuo) <
        # options.er*dc_analysis.vector_norm(x) + options.ea):
            if conv_counter == 3:
                converged = True
                break
            else:
                conv_counter = conv_counter + 1
        elif vector_norm(dx[points - 1]) is numpy.nan:  # needs work fixme
            raise OverflowError
            # break
        else:
            conv_counter = 0
            tick.step(verbose > 2)

        if options.shooting_max_nr_iter and iteration == options.shooting_max_nr_iter:
            printing.print_general_error(
                "Hitted SHOOTING_MAX_NR_ITER (" + str(options.shooting_max_nr_iter) + "), iteration halted.")
            converged = False
            break
        else:
            iteration = iteration + 1

    tick.hide(verbose > 2)
    if converged:
        printing.print_info_line(("done.", 3), verbose)
        t = numpy.mat(numpy.arange(points) * step)
        t = t.reshape((1, points))
        xmat = x[0]
        for index in xrange(1, points):
            xmat = numpy.concatenate((xmat, x[index]), axis=1)
        sol = results.pss_solution(
            circ=circ, method="shooting", period=period, outfile=outfile, t_array=t, x_array=xmat)
        # print_results(circ, x, fdata, points, step)
    else:
        print "failed."
        sol = None
    return sol
Пример #28
0
def main(filename, outfile="stdout", tran_method=transient.TRAP.lower(), no_step_control=False, dc_guess='guess', print_circuit=False, remote=True, verbose=3):
	"""This method allows calling ahkab from a Python script.
	"""
	printing.print_info_line(("This is ahkab %s running with:" %(__version__),6), verbose)
	printing.print_info_line(("  Python %s" % (sys.version.split('\n')[0],),6), verbose)
	printing.print_info_line(("  Numpy %s"  % (numpy.__version__),6), verbose)
	printing.print_info_line(("  Sympy %s"  % (sympy.__version__),6), verbose)
	printing.print_info_line(("  Matplotlib %s"  % (matplotlib.__version__),6), verbose)

	utilities._set_execution_lock()

	read_netlist_from_stdin = (filename is None or filename == "-")
	(circ, directives, postproc_direct) = netlist_parser.parse_circuit(filename, read_netlist_from_stdin)
	
	check, reason = dc_analysis.check_circuit(circ)
	if not check:
		printing.print_general_error(reason)
		printing.print_circuit(circ)
		sys.exit(3)
	
	if verbose > 3 or print_circuit:
		print "Parsed circuit:"
		printing.print_circuit(circ)
	elif verbose > 1:
		print circ.title.upper()
	
	an_list = netlist_parser.parse_analysis(circ, directives)
	postproc_list = netlist_parser.parse_postproc(circ, an_list, postproc_direct)
	if len(an_list) > 0: 
		printing.print_info_line(("Requested an.:", 4), verbose)
		if verbose >= 4:
			map(printing.print_analysis, an_list)
	else:
		if verbose:
			printing.print_warning("No analysis requested.")
	if len(an_list) > 0:
		results = process_analysis(an_list, circ, outfile, verbose, guess=dc_guess.lower()=="guess", \
		cli_tran_method=tran_method, disable_step_control=no_step_control)
	else:
		printing.print_warning("Nothing to do. Quitting.")

	if len(an_list) > 0 and len(postproc_list) > 0 and len(results):
		process_postproc(postproc_list, circ.title, results, outfile, remote)

	utilities._unset_execution_lock()

	return results
Пример #29
0
def op_analysis(circ, x0=None, guess=True, data_filename=None, verbose=3):
    """Runs an Operating Point (OP) analysis
	circ: the circuit instance on which the simulation is run
	x0: is the initial guess to be used to start the NR mdn_solver
	guess: if set to True and x0 is None, it will generate a 'smart' guess
	verbose: verbosity level from 0 (silent) to 6 (debug).

	Returns a Operation Point result, if successful, None otherwise.
	"""
    # use_gmin = True
    # solved=False
    # x0 = numpy.mat(numpy.zeros((1,2)))

    (mna, N) = generate_mna_and_N(circ)

    printing.print_info_line(("MNA matrix and constant term (complete):", 4), verbose)
    printing.print_info_line((str(mna), 4), verbose)
    printing.print_info_line((str(N), 4), verbose)

    # lets trash the unneeded col & row
    printing.print_info_line(("Removing unneeded row and column...", 4), verbose)
    mna = utilities.remove_row_and_col(mna)
    N = utilities.remove_row(N, rrow=0)

    printing.print_info_line(("Starting op analysis:", 2), verbose)

    if x0 is None and guess:
        x0 = dc_guess.get_dc_guess(circ, verbose=verbose)
        # if x0 is not None, use that

    printing.print_info_line(("Solving with Gmin:", 4), verbose)
    Gmin_matrix = build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose - 2)
    (x1, error1, solved1, n_iter1) = dc_solve(mna, N, circ, Gmin=Gmin_matrix, x0=x0, verbose=verbose)

    # We'll check the results now. Recalculate them without Gmin (using previsious solution as initial guess)
    # and check that differences on nodes and current do not exceed the tolerances.
    if solved1:
        op1 = results.op_solution(x1, error1, circ, outfile=data_filename, iterations=n_iter1)
        printing.print_info_line(("Solving without Gmin:", 4), verbose)
        (x2, error2, solved2, n_iter2) = dc_solve(mna, N, circ, Gmin=None, x0=x1, verbose=verbose)

        if not solved2:
            printing.print_general_error("Can't solve without Gmin.")
            if verbose:
                print "Displaying latest valid results."
                op1.write_to_file(filename="stdout")
            opsolution = op1
        else:
            op2 = results.op_solution(x2, error2, circ, outfile=data_filename, iterations=n_iter1 + n_iter2)
            op2.gmin = 0
            badvars = results.op_solution.gmin_check(op2, op1)
            printing.print_result_check(badvars, verbose=verbose)
            check_ok = not (len(badvars) > 0)
            if not check_ok and verbose:
                print "Solution with Gmin:"
                op1.write_to_file(filename="stdout")
                print "Solution without Gmin:"
            if verbose:
                op2.write_to_file(filename="stdout")
            opsolution = op2

        if data_filename != "stdout" and data_filename is not None:
            opsolution.write_to_file()
    else:
        printing.print_general_error("Couldn't solve the circuit. Giving up.")
        opsolution = None

    return opsolution
Пример #30
0
def main(filename,
         outfile="stdout",
         tran_method=transient.TRAP.lower(),
         no_step_control=False,
         dc_guess='guess',
         print_circuit=False,
         remote=True,
         verbose=3):
    """This method allows calling ahkab from a Python script.
	"""
    printing.print_info_line(
        ("This is ahkab %s running with:" % (__version__), 6), verbose)
    printing.print_info_line(
        ("  Python %s" % (sys.version.split('\n')[0], ), 6), verbose)
    printing.print_info_line(("  Numpy %s" % (numpy.__version__), 6), verbose)
    printing.print_info_line(("  Sympy %s" % (sympy.__version__), 6), verbose)
    printing.print_info_line(("  Matplotlib %s" % (matplotlib.__version__), 6),
                             verbose)

    utilities._set_execution_lock()

    read_netlist_from_stdin = (filename is None or filename == "-")
    (circ, directives,
     postproc_direct) = netlist_parser.parse_circuit(filename,
                                                     read_netlist_from_stdin)

    check, reason = dc_analysis.check_circuit(circ)
    if not check:
        printing.print_general_error(reason)
        printing.print_circuit(circ)
        sys.exit(3)

    if verbose > 3 or print_circuit:
        print "Parsed circuit:"
        printing.print_circuit(circ)
    elif verbose > 1:
        print circ.title.upper()

    an_list = netlist_parser.parse_analysis(circ, directives)
    postproc_list = netlist_parser.parse_postproc(circ, an_list,
                                                  postproc_direct)
    if len(an_list) > 0:
        printing.print_info_line(("Requested an.:", 4), verbose)
        if verbose >= 4:
            map(printing.print_analysis, an_list)
    else:
        if verbose:
            printing.print_warning("No analysis requested.")
    if len(an_list) > 0:
        results = process_analysis(an_list, circ, outfile, verbose, guess=dc_guess.lower()=="guess", \
        cli_tran_method=tran_method, disable_step_control=no_step_control)
    else:
        printing.print_warning("Nothing to do. Quitting.")

    if len(an_list) > 0 and len(postproc_list) > 0 and len(results):
        process_postproc(postproc_list, circ.title, results, outfile, remote)

    utilities._unset_execution_lock()

    return results
Пример #31
0
def solve(circ, tf_source=None, subs=None, opts=None, verbose=3):
	"""Attempt a symbolic solution of the circuit.
	circ: the circuit instance to be simulated.
	tf_source: the name (string) of the source to be used as input for the transfer
		   function. If None, no transfer function is evaluated.
	subs: a dictionary of sympy Symbols to be substituted. It makes solving the circuit 
	      easier. Eg. {R1:R2} - replace R1 with R2. It can be generated with 
	      parse_substitutions()
	opts: dict of 'option':boolean to be taken into account in simulation.
	      currently 'r0s' and 'ac' are the only options considered.
	verbose: verbosity level 0 (silent) to 6 (painful).
	
	Returns: a dictionary with the solutions.
	"""
	if opts is None:
		# load the defaults
		opts = {'r0s':True, 'ac':False}
	if not 'r0s' in opts.keys():
		opts.update({'r0s':True})
	if not 'ac' in opts.keys():
		opts.update({'ac':False})
	if subs is None:
		subs = {} # no subs by default

	if not opts['ac']:
		printing.print_info_line(("Starting symbolic DC analysis...", 1), verbose)
	else:
		printing.print_info_line(("Starting symbolic AC analysis...", 1), verbose)		
		
	printing.print_info_line(("Building symbolic MNA, N and x...", 3), verbose, print_nl=False)
	mna, N, subs_g = generate_mna_and_N(circ, opts, opts['ac'])
	x = get_variables(circ)
	mna = mna[1:, 1:]
	N = N[1:, :]
	printing.print_info_line((" done.", 3), verbose)	

	printing.print_info_line(("Performing variable substitutions...", 5), verbose)
	mna, N = apply_substitutions(mna, N, subs)

	printing.print_info_line(("MNA matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(mna)
	printing.print_info_line(("N matrix (reduced):", 5), verbose)	
	if verbose > 5:	print sympy.sstr(N)

	printing.print_info_line(("Building equations...", 3), verbose)	
	eq = []
	for i in to_real_list(mna * x + N):
		eq.append(sympy.Eq(i, 0))

	x = to_real_list(x)
	if verbose > 4:
		printing.print_symbolic_equations(eq)
		print "To be solved for:"
		print x
		#print "Matrix is singular: ", (mna.det() == 0)
	#print -1.0*mna.inv()*N #too heavy
	#print sympy.solve_linear_system(mna.row_join(-N), x)
	printing.print_info_line(("Performing auxiliary simplification...", 3), verbose)	
	eq, x, sol_h = help_the_solver(eq, x)
		
	if len(eq):
		if verbose > 3:
			print "Symplified sytem:"
			printing.print_symbolic_equations(eq)
			print "To be solved for:"
			print x
			printing.print_info_line(("Solving...", 1), verbose)	

		if options.symb_internal_solver:
			sol = local_solve(eq, x)
		else:
			sol = sympy.solve(eq, x, manual=options.symb_sympy_manual_solver, simplify=True)
		if sol is not None:		
			sol.update(sol_h)
		else:
			sol = sol_h
	else:
		printing.print_info_line(("Auxiliary simplification solved the problem.", 3), verbose)	
		sol = sol_h

	for ks in sol.keys():
		sol.update({ks:sol[ks].subs(subs_g)})

	#sol = sol_to_dict(sol, x)

	if sol == {}:
		printing.print_warning("No solutions. Check the netlist.")
	else:
		printing.print_info_line(("Success!", 2), verbose)	
		if verbose > 1:
			print "Results:"
		printing.print_symbolic_results(sol)

	if tf_source is not None:
		src = sympy.Symbol(tf_source.upper(), real=True)
		printing.print_info_line(("Calculating small-signal symbolic transfer functions (%s))..."%(str(src),), 2), verbose, print_nl=False)
		tfs = calculate_gains(sol, src)
		printing.print_info_line(("done.", 2), verbose)	
		printing.print_info_line(("Small-signal symbolic transfer functions:", 1), verbose)	
		printing.print_symbolic_transfer_functions(tfs)
	else:
		tfs = None
	
	# convert to a results instance
	sol = results.symbolic_solution(sol, subs, circ)
	return sol, tfs
Пример #32
0
def ac_analysis(circ, start, nsteps, stop, step_type, xop=None, mna=None,\
 AC=None, Nac=None, J=None, data_filename="stdout", verbose=3):
    """Performs an AC analysis of the circuit (described by circ).
	"""

    if data_filename == 'stdout':
        verbose = 0

    #check step/start/stop parameters
    if start == 0:
        printing.print_general_error("AC analysis has start frequency = 0")
        sys.exit(5)
    if start > stop:
        printing.print_general_error("AC analysis has start > stop")
        sys.exit(1)
    if nsteps < 1:
        printing.print_general_error("AC analysis has number of steps <= 1")
        sys.exit(1)
    if step_type == options.ac_log_step:
        omega_iter = utilities.log_axis_iterator(stop, start, nsteps)
    elif step_type == options.ac_lin_step:
        omega_iter = utilities.lin_axis_iterator(stop, start, nsteps)
    else:
        printing.print_general_error("Unknown sweep type.")
        sys.exit(1)

    tmpstr = "Vea =", options.vea, "Ver =", options.ver, "Iea =", options.iea, "Ier =", \
    options.ier, "max_ac_nr_iter =", options.ac_max_nr_iter
    printing.print_info_line((tmpstr, 5), verbose)
    del tmpstr

    printing.print_info_line(("Starting AC analysis: ", 1), verbose)
    tmpstr = "w: start = %g Hz, stop = %g Hz, %d steps" % (start, stop, nsteps)
    printing.print_info_line((tmpstr, 3), verbose)
    del tmpstr

    #It's a good idea to call AC with prebuilt MNA matrix if the circuit is big
    if mna is None:
        (mna, N) = dc_analysis.generate_mna_and_N(circ)
        del N
        mna = utilities.remove_row_and_col(mna)
    if Nac is None:
        Nac = generate_Nac(circ)
        Nac = utilities.remove_row(Nac, rrow=0)
    if AC is None:
        AC = generate_AC(circ, [mna.shape[0], mna.shape[0]])
        AC = utilities.remove_row_and_col(AC)

    if circ.is_nonlinear():
        if J is not None:
            pass
            # we used the supplied linearization matrix
        else:
            if xop is None:
                printing.print_info_line(
                    ("Starting OP analysis to get a linearization point...",
                     3),
                    verbose,
                    print_nl=False)
                #silent OP
                xop = dc_analysis.op_analysis(circ, verbose=0)
                if xop is None:  #still! Then op_analysis has failed!
                    printing.print_info_line(("failed.", 3), verbose)
                    printing.print_general_error(
                        "OP analysis failed, no linearization point available. Quitting."
                    )
                    sys.exit(3)
                else:
                    printing.print_info_line(("done.", 3), verbose)
            printing.print_info_line(("Linearization point (xop):", 5),
                                     verbose)
            if verbose > 4: xop.print_short()
            printing.print_info_line(("Linearizing the circuit...", 5),
                                     verbose,
                                     print_nl=False)
            J = generate_J(xop=xop.asmatrix(),
                           circ=circ,
                           mna=mna,
                           Nac=Nac,
                           data_filename=data_filename,
                           verbose=verbose)
            printing.print_info_line((" done.", 5), verbose)
            # we have J, continue
    else:  #not circ.is_nonlinear()
        # no J matrix is required.
        J = 0

    printing.print_info_line(("MNA (reduced):", 5), verbose)
    printing.print_info_line((str(mna), 5), verbose)
    printing.print_info_line(("AC (reduced):", 5), verbose)
    printing.print_info_line((str(AC), 5), verbose)
    printing.print_info_line(("J (reduced):", 5), verbose)
    printing.print_info_line((str(J), 5), verbose)
    printing.print_info_line(("Nac (reduced):", 5), verbose)
    printing.print_info_line((str(Nac), 5), verbose)

    sol = results.ac_solution(circ,
                              ostart=start,
                              ostop=stop,
                              opoints=nsteps,
                              stype=step_type,
                              op=xop,
                              outfile=data_filename)

    # setup the initial values to start the iteration:
    nv = len(circ.nodes_dict)
    j = numpy.complex('j')

    Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin,
                                                mna.shape[0], verbose)

    iter_n = 0  # contatore d'iterazione
    #printing.print_results_header(circ, fdata, print_int_nodes=options.print_int_nodes, print_omega=True)
    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick = ticker.ticker(increments_for_step=1)
    tick.display(verbose > 1)

    x = xop
    for omega in omega_iter:
        (x, error, solved, n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(j*omega, AC) + J), \
        Ndc=Nac,  Ntran=0, circ=circuit.circuit(title="Dummy circuit for AC", filename=None), Gmin=Gmin_matrix, x0=x, \
        time=None, locked_nodes=None, MAXIT=options.ac_max_nr_iter, skip_Tt=True, verbose=0)
        if solved:
            tick.step(verbose > 1)
            iter_n = iter_n + 1
            # hooray!
            sol.add_line(omega, x)
        else:
            break

    tick.hide(verbose > 1)

    if solved:
        printing.print_info_line(("done.", 1), verbose)
        ret_value = sol
    else:
        printing.print_info_line(("failed.", 1), verbose)
        ret_value = None

    return ret_value
Пример #33
0
def transient_analysis(circ, tstart, tstep, tstop, method=TRAP, x0=None, mna=None, N=None, \
 D=None, data_filename="stdout", use_step_control=True, return_req_dict=None, verbose=3):
    """Performs a transient analysis of the circuit described by circ.
	
	Important parameters:
	- tstep is the maximum step to be allowed during simulation.
	- print_step_and_lte is a boolean value. Is set to true, the step and the LTE of the first
	element of x will be printed out to step_and_lte.graph in the current directory.
	
	"""
    if data_filename == "stdout":
        verbose = 0
    _debug = False
    if _debug:
        print_step_and_lte = True
    else:
        print_step_and_lte = False

    HMAX = tstep

    #check parameters
    if tstart > tstop:
        printing.print_general_error("tstart > tstop")
        sys.exit(1)
    if tstep < 0:
        printing.print_general_error("tstep < 0")
        sys.exit(1)

    if verbose > 4:
        tmpstr = "Vea = %g Ver = %g Iea = %g Ier = %g max_time_iter = %g HMIN = %g" % \
        (options.vea, options.ver, options.iea, options.ier, options.transient_max_time_iter, options.hmin)
        printing.print_info_line((tmpstr, 5), verbose)

    locked_nodes = circ.get_locked_nodes()

    if print_step_and_lte:
        flte = open("step_and_lte.graph", "w")
        flte.write("#T\tStep\tLTE\n")

    printing.print_info_line(("Starting transient analysis: ", 3), verbose)
    printing.print_info_line(("Selected method: %s" % (method, ), 3), verbose)
    #It's a good idea to call transient with prebuilt MNA and N matrix
    #the analysis will be slightly faster (long netlists).
    if mna is None or N is None:
        (mna, N) = dc_analysis.generate_mna_and_N(circ)
        mna = utilities.remove_row_and_col(mna)
        N = utilities.remove_row(N, rrow=0)
    elif not mna.shape[0] == N.shape[0]:
        printing.print_general_error(
            "mna matrix and N vector have different number of columns.")
        sys.exit(0)
    if D is None:
        # if you do more than one tran analysis, output streams should be changed...
        # this needs to be fixed
        D = generate_D(circ, [mna.shape[0], mna.shape[0]])
        D = utilities.remove_row_and_col(D)

    # setup x0
    if x0 is None:
        printing.print_info_line(("Generating x(t=%g) = 0" % (tstart, ), 5),
                                 verbose)
        x0 = numpy.matrix(numpy.zeros((mna.shape[0], 1)))
        opsol = results.op_solution(x=x0, error=x0, circ=circ, outfile=None)
    else:
        if isinstance(x0, results.op_solution):
            opsol = x0
            x0 = x0.asmatrix()
        else:
            opsol = results.op_solution(x=x0,
                                        error=numpy.matrix(
                                            numpy.zeros((mna.shape[0], 1))),
                                        circ=circ,
                                        outfile=None)
        printing.print_info_line(
            ("Using the supplied op as x(t=%g)." % (tstart, ), 5), verbose)

    if verbose > 4:
        print "x0:"
        opsol.print_short()

    # setup the df method
    printing.print_info_line(
        ("Selecting the appropriate DF (" + method + ")... ", 5),
        verbose,
        print_nl=False)
    if method == IMPLICIT_EULER:
        import implicit_euler as df
    elif method == TRAP:
        import trap as df
    elif method == GEAR1:
        import gear as df
        df.order = 1
    elif method == GEAR2:
        import gear as df
        df.order = 2
    elif method == GEAR3:
        import gear as df
        df.order = 3
    elif method == GEAR4:
        import gear as df
        df.order = 4
    elif method == GEAR5:
        import gear as df
        df.order = 5
    elif method == GEAR6:
        import gear as df
        df.order = 6
    else:
        df = import_custom_df_module(method,
                                     print_out=(data_filename != "stdout"))
        # df is none if module is not found

    if df is None:
        sys.exit(23)

    if not df.has_ff() and use_step_control:
        printing.print_warning(
            "The chosen DF does not support step control. Turning off the feature."
        )
        use_step_control = False
        #use_aposteriori_step_control = False

    printing.print_info_line(("done.", 5), verbose)

    # setup the data buffer
    # if you use the step control, the buffer has to be one point longer.
    # That's because the excess point is used by a FF in the df module to predict the next value.
    printing.print_info_line(("Setting up the buffer... ", 5),
                             verbose,
                             print_nl=False)
    ((max_x, max_dx), (pmax_x, pmax_dx)) = df.get_required_values()
    if max_x is None and max_dx is None:
        printing.print_general_error("df doesn't need any value?")
        sys.exit(1)
    if use_step_control:
        thebuffer = dfbuffer(length=max(max_x, max_dx, pmax_x, pmax_dx) + 1,
                             width=3)
    else:
        thebuffer = dfbuffer(length=max(max_x, max_dx) + 1, width=3)
    thebuffer.add((tstart, x0, None))  #setup the first values
    printing.print_info_line(("done.", 5), verbose)  #FIXME

    #setup the output buffer
    if return_req_dict:
        output_buffer = dfbuffer(length=return_req_dict["points"], width=1)
        output_buffer.add((x0, ))
    else:
        output_buffer = None

    # import implicit_euler to be used in the first iterations
    # this is because we don't have any dx when we start, nor any past point value
    if (max_x is not None and max_x > 0) or max_dx is not None:
        import implicit_euler

    printing.print_info_line(("MNA (reduced):", 5), verbose)
    printing.print_info_line((str(mna), 5), verbose)
    printing.print_info_line(("D (reduced):", 5), verbose)
    printing.print_info_line((str(D), 5), verbose)

    # setup the initial values to start the iteration:
    x = None
    time = tstart
    nv = len(circ.nodes_dict)

    Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin,
                                                mna.shape[0], verbose)

    # lo step viene generato automaticamente, ma non superare mai quello fornito.
    if use_step_control:
        #tstep = min((tstop-tstart)/9999.0, HMAX, 100.0 * options.hmin)
        tstep = min((tstop - tstart) / 9999.0, HMAX)
    printing.print_info_line(("Initial step: %g" % (tstep, ), 5), verbose)

    if max_dx is None:
        max_dx_plus_1 = None
    else:
        max_dx_plus_1 = max_dx + 1
    if pmax_dx is None:
        pmax_dx_plus_1 = None
    else:
        pmax_dx_plus_1 = pmax_dx + 1

    # setup error vectors
    aerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
    aerror[:nv - 1, 0] = options.vea
    aerror[nv - 1:, 0] = options.vea
    rerror = numpy.mat(numpy.zeros((x0.shape[0], 1)))
    rerror[:nv - 1, 0] = options.ver
    rerror[nv - 1:, 0] = options.ier

    iter_n = 0  # contatore d'iterazione
    lte = None
    sol = results.tran_solution(circ,
                                tstart,
                                tstop,
                                op=x0,
                                method=method,
                                outfile=data_filename)
    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick = ticker.ticker(increments_for_step=1)
    tick.display(verbose > 1)
    while time < tstop:
        if iter_n < max(max_x, max_dx_plus_1):
            x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff = \
            implicit_euler.get_df((thebuffer.get_df_vector()[0],), tstep, \
            predict=(use_step_control and (iter_n >= max(pmax_x, pmax_dx_plus_1))))

        else:
            [x_coeff, const, x_lte_coeff, prediction, pred_lte_coeff] = \
            df.get_df(thebuffer.get_df_vector(), tstep, predict=use_step_control)

        if options.transient_prediction_as_x0 and use_step_control and prediction is not None:
            x0 = prediction
        elif x is not None:
            x0 = x

        (x1, error, solved,
         n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(x_coeff, D)),
                                        Ndc=N,
                                        Ntran=D * const,
                                        circ=circ,
                                        Gmin=Gmin_matrix,
                                        x0=x0,
                                        time=(time + tstep),
                                        locked_nodes=locked_nodes,
                                        MAXIT=options.transient_max_nr_iter,
                                        verbose=0)

        if solved:
            old_step = tstep  #we will modify it, if we're using step control otherwise it's the same
            # step control (yeah)
            if use_step_control:
                if x_lte_coeff is not None and pred_lte_coeff is not None and prediction is not None:
                    # this is the Local Truncation Error :)
                    lte = abs((x_lte_coeff / (pred_lte_coeff - x_lte_coeff)) *
                              (prediction - x1))
                    # it should NEVER happen that new_step > 2*tstep, for stability
                    new_step_coeff = 2
                    for index in xrange(x.shape[0]):
                        if lte[index, 0] != 0:
                            new_value = ((aerror[index, 0] + rerror[index, 0]*abs(x[index, 0])) / lte[index, 0]) \
                            ** (1.0 / (df.order+1))
                            if new_value < new_step_coeff:
                                new_step_coeff = new_value
                            #print new_value
                    new_step = tstep * new_step_coeff
                    if options.transient_use_aposteriori_step_control and new_step < options.transient_aposteriori_step_threshold * tstep:
                        #don't recalculate a x for a small change
                        tstep = check_step(new_step, time, tstop, HMAX)
                        #print "Apost. (reducing) step = "+str(tstep)
                        continue
                    tstep = check_step(new_step, time, tstop,
                                       HMAX)  # used in the next iteration
                    #print "Apriori tstep = "+str(tstep)
                else:
                    #print "LTE not calculated."
                    lte = None
            if print_step_and_lte and lte is not None:
                #if you wish to look at the step. We print just a lte
                flte.write(
                    str(time) + "\t" + str(old_step) + "\t" + str(lte.max()) +
                    "\n")
            # if we get here, either aposteriori_step_control is
            # disabled, or it's enabled and the error is small
            # enough. Anyway, the result is GOOD, STORE IT.
            time = time + old_step
            x = x1
            iter_n = iter_n + 1
            sol.add_line(time, x)

            dxdt = numpy.multiply(x_coeff, x) + const
            thebuffer.add((time, x, dxdt))
            if output_buffer is not None:
                output_buffer.add((x, ))
            tick.step(verbose > 1)
        else:
            # If we get here, Newton failed to converge. We need to reduce the step...
            if use_step_control:
                tstep = tstep / 5.0
                tstep = check_step(tstep, time, tstop, HMAX)
                printing.print_info_line(
                    ("At %g s reducing step: %g s (convergence failed)" %
                     (time, tstep), 5), verbose)
            else:  #we can't reduce the step
                printing.print_general_error("Can't converge with step " +
                                             str(tstep) + ".")
                printing.print_general_error(
                    "Try setting --t-max-nr to a higher value or set step to a lower one."
                )
                solved = False
                break
        if options.transient_max_time_iter and iter_n == options.transient_max_time_iter:
            printing.print_general_error("MAX_TIME_ITER exceeded (" +
                                         str(options.transient_max_time_iter) +
                                         "), iteration halted.")
            solved = False
            break

    if print_step_and_lte:
        flte.close()

    tick.hide(verbose > 1)

    if solved:
        printing.print_info_line(("done.", 3), verbose)
        printing.print_info_line(
            ("Average time step: %g" % ((tstop - tstart) / iter_n, ), 3),
            verbose)

        if output_buffer:
            ret_value = output_buffer.get_as_matrix()
        else:
            ret_value = sol
    else:
        print "failed."
        ret_value = None

    return ret_value
Пример #34
0
def main(filename, outfile="stdout", verbose=3):
    """This method allows calling ahkab from a Python script.
    """
    printing.print_info_line(
        ("This is ahkab %s running with:" % (__version__), 6), verbose)
    printing.print_info_line(
        ("  Python %s" % (sys.version.split('\n')[0],), 6), verbose)
    printing.print_info_line(("  Numpy %s" % (numpy.__version__), 6), verbose)
    printing.print_info_line(("  Sympy %s" % (sympy.__version__), 6), verbose)
    printing.print_info_line(
        ("  Matplotlib %s" % (matplotlib.__version__), 6), verbose)

    read_netlist_from_stdin = (filename is None or filename == "-")
    (circ, directives, postproc_direct) = netlist_parser.parse_circuit(
        filename, read_netlist_from_stdin)

    check, reason = dc_analysis.check_circuit(circ)
    if not check:
        printing.print_general_error(reason)
        printing.print_circuit(circ)
        sys.exit(3)

    if verbose > 3 or _print:
        print "Parsed circuit:"
        printing.print_circuit(circ)

    ic_list = netlist_parser.parse_ics(directives)
    _handle_netlist_ics(circ, an_list=[], ic_list=ic_list)
    results = {}
    for an in netlist_parser.parse_analysis(circ, directives):
        if 'outfile' not in an.keys() or not an['outfile']:
            an.update(
                {'outfile': outfile + ("." + an['type']) * (outfile != 'stdout')})
        if 'verbose' in an.keys() and (an['verbose'] is None or an['verbose'] < verbose) \
           or not 'verbose' in an.keys():
            an.update({'verbose': verbose})
        _handle_netlist_ics(circ, [an], ic_list=[])
        if verbose >= 4:
            printing.print_info_line(("Requested an.:", 4), verbose)
            printing.print_analysis(an)
        results.update(run(circ, [an]))

    postproc_list = netlist_parser.parse_postproc(circ, postproc_direct)
    if len(postproc_list) > 0 and len(results):
        process_postproc(postproc_list, circ.title, results, outfile)

    return results
Пример #35
0
def shooting(circ,
             period,
             step=None,
             mna=None,
             Tf=None,
             D=None,
             points=None,
             autonomous=False,
             data_filename='stdout',
             vector_norm=lambda v: max(abs(v)),
             verbose=3):
    """Performs a periodic steady state analysis based on the algorithm described in
	Brambilla, A.; D'Amore, D., "Method for steady-state simulation of 
	strongly nonlinear circuits in the time domain," Circuits and 
	Systems I: Fundamental Theory and Applications, IEEE Transactions on, 
	vol.48, no.7, pp.885-889, Jul 2001
	URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=933329&isnumber=20194
	
	The results have been computed again by me, the formulas are not exactly the 
	same, but the idea behind the shooting algorithm is.
	
	This method allows us to have a period with many points without having to
	invert a huge matrix (and being limited to the maximum matrix size).

	A tran is performed to initialize the solver.
	
	We compute the change in the last point, calculating several matrices in
	the process.
	From that, with the same matrices we calculate the changes in all points, 
	starting from 0 (which is the same as the last one), then 1, ...

	Key points:
	- Only not autonomous circuits are supported.
	- The time step is constant
	- Implicit euler is used as DF
	
	Parameters:
	circ is the circuit description class
	period is the period of the solution
	mna, D, Tf are not compulsory they will be computed if they're set to None
	step is the time step between consecutive points
	points is the number of points to be used
	step and points are mutually exclusive options:
	- if step is specified, the number of points will be automatically determined 
	- if points is set, the step will be automatically determined
	- if none of them is set, options.shooting_default_points will be used as points
	autonomous has to be False, autonomous circuits are not supported
	data_filename is the output filename. Defaults to stdout.
	verbose is set to zero (print errors only) if datafilename == 'stdout'.

	Returns: nothing
	"""

    if data_filename == "stdout":
        verbose = 0

    printing.print_info_line(("Starting periodic steady state analysis:", 3),
                             verbose)
    printing.print_info_line(("Method: shooting", 3), verbose)

    if mna is None or Tf is None:
        (mna, Tf) = dc_analysis.generate_mna_and_N(circ)
        mna = utilities.remove_row_and_col(mna)
        Tf = utilities.remove_row(Tf, rrow=0)
    elif not mna.shape[0] == Tf.shape[0]:
        printing.print_general_error(
            "mna matrix and N vector have different number of rows.")
        sys.exit(0)

    if D is None:
        D = transient.generate_D(circ, [mna.shape[0], mna.shape[0]])
        D = utilities.remove_row_and_col(D)
    elif not mna.shape == D.shape:
        printing.print_general_error(
            "mna matrix and D matrix have different sizes.")
        sys.exit(0)

    (points, step) = check_step_and_points(step, points, period)
    print "points", points
    print "step", step

    n_of_var = mna.shape[0]
    locked_nodes = circ.get_locked_nodes()

    printing.print_info_line((
        "Starting transient analysis for algorithm init: tstop=%g, tstep=%g... "
        % (10 * points * step, step), 3),
                             verbose,
                             print_nl=False)
    xtran = transient.transient_analysis(circ=circ, tstart=0, tstep=step, tstop=10*points*step, method="TRAP", x0=None, mna=mna, N=Tf, \
           D=D, use_step_control=False, data_filename=data_filename+".tran", return_req_dict={"points":points}, verbose=0)
    if xtran is None:
        print "failed."
        return None
    printing.print_info_line(("done.", 3), verbose)

    x = []
    for index in range(points):
        x.append(xtran[index * n_of_var:(index + 1) * n_of_var, 0])

    tick = ticker.ticker(increments_for_step=1)

    MAass_static, MBass = build_static_MAass_and_MBass(mna, D, step)

    # This contains
    # the time invariant part, Tf
    # time variable component: Tt this is always the same, since the time interval is the same
    # this holds all time-dependent sources (both V/I).
    Tass_static_vector = build_Tass_static_vector(circ, Tf, points, step, tick,
                                                  n_of_var, verbose)

    converged = False
    printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
    tick.reset()
    tick.display(verbose > 2)

    iteration = 0  # newton iteration counter
    conv_counter = 0

    while True:
        dx = []
        Tass_variable_vector = []
        MAass_variable_vector = []
        for index in range(points):
            if index == 0:
                xn_minus_1 = x[points - 1]
            else:
                xn_minus_1 = x[index - 1]
            MAass_variable, Tass_variable = get_variable_MAass_and_Tass(
                circ, x[index], xn_minus_1, mna, D, step, n_of_var)
            MAass_variable_vector.append(MAass_variable + MAass_static)
            Tass_variable_vector.append(Tass_variable +
                                        Tass_static_vector[index])

        dxN = compute_dxN(circ,
                          MAass_variable_vector,
                          MBass,
                          Tass_variable_vector,
                          n_of_var,
                          points,
                          verbose=verbose)
        td = dc_analysis.get_td(dxN, locked_nodes, n=-1)
        x[points - 1] = td * dxN + x[points - 1]

        for index in range(points - 1):
            if index == 0:
                dxi_minus_1 = dxN
            else:
                dxi_minus_1 = dx[index - 1]
            dx.append(
                compute_dx(MAass_variable_vector[index], MBass,
                           Tass_variable_vector[index], dxi_minus_1))
            td = dc_analysis.get_td(dx[index], locked_nodes, n=-1)
            x[index] = td * dx[index] + x[index]
        dx.append(dxN)

        if (vector_norm_wrapper(dx, vector_norm) <
                min(options.ver, options.ier) * vector_norm_wrapper(
                    x, vector_norm) + min(options.vea, options.iea)):  #\
            #and (dc_analysis.vector_norm(residuo) < options.er*dc_analysis.vector_norm(x) + options.ea):
            if conv_counter == 3:
                converged = True
                break
            else:
                conv_counter = conv_counter + 1
        elif vector_norm(dx[points - 1]) is numpy.nan:  #needs work fixme
            raise OverflowError
            #break
        else:
            conv_counter = 0
            tick.step(verbose > 2)

        if options.shooting_max_nr_iter and iteration == options.shooting_max_nr_iter:
            printing.print_general_error("Hitted SHOOTING_MAX_NR_ITER (" +
                                         str(options.shooting_max_nr_iter) +
                                         "), iteration halted.")
            converged = False
            break
        else:
            iteration = iteration + 1

    tick.hide(verbose > 2)
    if converged:
        printing.print_info_line(("done.", 3), verbose)
        t = numpy.mat(numpy.arange(points) * step)
        t = t.reshape((1, points))
        xmat = x[0]
        for index in xrange(1, points):
            xmat = numpy.concatenate((xmat, x[index]), axis=1)
        sol = results.pss_solution(circ=circ,
                                   method="shooting",
                                   period=period,
                                   outfile=data_filename,
                                   t_array=t,
                                   x_array=xmat)
        #print_results(circ, x, fdata, points, step)
    else:
        print "failed."
        sol = None
    return sol
Пример #36
0
def op_analysis(circ, x0=None, guess=True, outfile=None, verbose=3):
    """Runs an Operating Point (OP) analysis
    circ: the circuit instance on which the simulation is run
    x0: is the initial guess to be used to start the NR mdn_solver
    guess: if set to True and x0 is None, it will generate a 'smart' guess
    verbose: verbosity level from 0 (silent) to 6 (debug).

    Returns a Operation Point result, if successful, None otherwise.
    """
    if outfile == 'stdout':
        verbose = 0  # silent mode, print out results only.
    if not options.dc_use_guess:
        guess = False

    (mna, N) = generate_mna_and_N(circ, verbose=verbose)

    printing.print_info_line(("MNA matrix and constant term (complete):", 4),
                             verbose)
    printing.print_info_line((str(mna), 4), verbose)
    printing.print_info_line((str(N), 4), verbose)

    # lets trash the unneeded col & row
    printing.print_info_line(("Removing unneeded row and column...", 4),
                             verbose)
    mna = utilities.remove_row_and_col(mna)
    N = utilities.remove_row(N, rrow=0)

    printing.print_info_line(("Starting op analysis:", 2), verbose)

    if x0 is None and guess:
        x0 = dc_guess.get_dc_guess(circ, verbose=verbose)
    # if x0 is not None, use that

    printing.print_info_line(("Solving with Gmin:", 4), verbose)
    Gmin_matrix = build_gmin_matrix(circ, options.gmin, mna.shape[0],
                                    verbose - 2)
    (x1, error1, solved1, n_iter1) = dc_solve(mna,
                                              N,
                                              circ,
                                              Gmin=Gmin_matrix,
                                              x0=x0,
                                              verbose=verbose)

    # We'll check the results now. Recalculate them without Gmin (using previsious solution as initial guess)
    # and check that differences on nodes and current do not exceed the
    # tolerances.
    if solved1:
        op1 = results.op_solution(x1,
                                  error1,
                                  circ,
                                  outfile=outfile,
                                  iterations=n_iter1)
        printing.print_info_line(("Solving without Gmin:", 4), verbose)
        (x2, error2, solved2, n_iter2) = dc_solve(mna,
                                                  N,
                                                  circ,
                                                  Gmin=None,
                                                  x0=x1,
                                                  verbose=verbose)
    else:
        solved2 = False

    if solved1 and not solved2:
        printing.print_general_error("Can't solve without Gmin.")
        if verbose:
            print "Displaying latest valid results."
            op1.write_to_file(filename='stdout')
        opsolution = op1
    elif solved1 and solved2:
        op2 = results.op_solution(x2,
                                  error2,
                                  circ,
                                  outfile=outfile,
                                  iterations=n_iter1 + n_iter2)
        op2.gmin = 0
        badvars = results.op_solution.gmin_check(op2, op1)
        printing.print_result_check(badvars, verbose=verbose)
        check_ok = not (len(badvars) > 0)
        if not check_ok and verbose:
            print "Solution with Gmin:"
            op1.write_to_file(filename='stdout')
            print "Solution without Gmin:"
            op2.write_to_file(filename='stdout')
        opsolution = op2
    else:  # not solved1
        printing.print_general_error("Couldn't solve the circuit. Giving up.")
        opsolution = None

    if opsolution and outfile != 'stdout' and outfile is not None:
        opsolution.write_to_file()
    if opsolution and verbose > 2 and options.cli:
        opsolution.write_to_file(filename='stdout')

    return opsolution
Пример #37
0
Файл: ac.py Проект: vovkd/ahkab
def ac_analysis(circ, start, nsteps, stop, step_type, xop=None, mna=None,\
	AC=None, Nac=None, J=None, data_filename="stdout", verbose=3):
	"""Performs an AC analysis of the circuit (described by circ).
	"""
	
	if data_filename == 'stdout':
		verbose = 0

	#check step/start/stop parameters
	if start == 0:
		printing.print_general_error("AC analysis has start frequency = 0")
                sys.exit(5)
	if start > stop:
		printing.print_general_error("AC analysis has start > stop")
		sys.exit(1)
	if nsteps < 1:
		printing.print_general_error("AC analysis has number of steps <= 1")
		sys.exit(1)
	if step_type == options.ac_log_step:
		omega_iter = utilities.log_axis_iterator(stop, start, nsteps)
	elif step_type == options.ac_lin_step:
		omega_iter = utilities.lin_axis_iterator(stop, start, nsteps)
	else:
		printing.print_general_error("Unknown sweep type.") 
		sys.exit(1)
	
	tmpstr = "Vea =", options.vea, "Ver =", options.ver, "Iea =", options.iea, "Ier =", \
	options.ier, "max_ac_nr_iter =", options.ac_max_nr_iter
	printing.print_info_line((tmpstr, 5), verbose)
	del tmpstr
	
	printing.print_info_line(("Starting AC analysis: ", 1), verbose)
	tmpstr = "w: start = %g Hz, stop = %g Hz, %d steps" % (start, stop, nsteps)
	printing.print_info_line((tmpstr, 3), verbose)
	del tmpstr

	#It's a good idea to call AC with prebuilt MNA matrix if the circuit is big
	if mna is None:
		(mna, N) = dc_analysis.generate_mna_and_N(circ)
		del N
		mna = utilities.remove_row_and_col(mna)
	if Nac is None:
		Nac = generate_Nac(circ)
		Nac = utilities.remove_row(Nac, rrow=0)
	if AC is None:
		AC = generate_AC(circ, [mna.shape[0], mna.shape[0]])
		AC = utilities.remove_row_and_col(AC)

	
	if circ.is_nonlinear():
		if J is not None:
			pass
			# we used the supplied linearization matrix
		else:
			if xop is None:
				printing.print_info_line(("Starting OP analysis to get a linearization point...", 3), verbose, print_nl=False)
				#silent OP
				xop = dc_analysis.op_analysis(circ, verbose=0)
				if xop is None: #still! Then op_analysis has failed!
					printing.print_info_line(("failed.", 3), verbose)
					printing.print_general_error("OP analysis failed, no linearization point available. Quitting.") 
					sys.exit(3)
				else:
					printing.print_info_line(("done.", 3), verbose)
			printing.print_info_line(("Linearization point (xop):", 5), verbose)
			if verbose > 4: xop.print_short()
			printing.print_info_line(("Linearizing the circuit...", 5), verbose, print_nl=False)
			J = generate_J(xop=xop.asmatrix(), circ=circ, mna=mna, Nac=Nac, data_filename=data_filename, verbose=verbose)
			printing.print_info_line((" done.", 5), verbose)
			# we have J, continue
	else: #not circ.is_nonlinear()
		# no J matrix is required.
		J = 0
	
	printing.print_info_line(("MNA (reduced):", 5), verbose)
	printing.print_info_line((str(mna), 5), verbose)
	printing.print_info_line(("AC (reduced):", 5), verbose)
	printing.print_info_line((str(AC), 5), verbose)
	printing.print_info_line(("J (reduced):", 5), verbose)
	printing.print_info_line((str(J), 5), verbose)
	printing.print_info_line(("Nac (reduced):", 5), verbose)
	printing.print_info_line((str(Nac), 5), verbose)
	
	sol = results.ac_solution(circ, ostart=start, ostop=stop, opoints=nsteps, stype=step_type, op=xop, outfile=data_filename)

	# setup the initial values to start the iteration:
	nv = len(circ.nodes_dict)
	j = numpy.complex('j')

	Gmin_matrix = dc_analysis.build_gmin_matrix(circ, options.gmin, mna.shape[0], verbose)

	iter_n = 0  # contatore d'iterazione
	#printing.print_results_header(circ, fdata, print_int_nodes=options.print_int_nodes, print_omega=True)
	printing.print_info_line(("Solving... ", 3), verbose, print_nl=False)
	tick = ticker.ticker(increments_for_step=1)
	tick.display(verbose > 1)

	x = xop
	for omega in omega_iter:
		(x, error, solved, n_iter) = dc_analysis.dc_solve(mna=(mna + numpy.multiply(j*omega, AC) + J), \
		Ndc=Nac,  Ntran=0, circ=circuit.circuit(title="Dummy circuit for AC", filename=None), Gmin=Gmin_matrix, x0=x, \
		time=None, locked_nodes=None, MAXIT=options.ac_max_nr_iter, skip_Tt=True, verbose=0)
		if solved:
			tick.step(verbose > 1)
			iter_n = iter_n + 1
			# hooray!
			sol.add_line(omega, x)
		else:
			break
	
	tick.hide(verbose > 1)
	
	if solved:
		printing.print_info_line(("done.", 1), verbose)
		ret_value = sol
	else:
		printing.print_info_line(("failed.", 1), verbose)
		ret_value =  None
	
	return ret_value
Пример #38
0
def symbolic_analysis(circ,
                      source=None,
                      ac_enable=True,
                      r0s=False,
                      subs=None,
                      outfile=None,
                      verbose=3):
    """Attempt a symbolic solution of the circuit.
    circ: the circuit instance to be simulated.
    source: the name (string) of the source to be used as input for the transfer
           function. If None, no transfer function is evaluated.
    ac_enable: take frequency dependency into consideration (default: True)
    r0s: take transistors' output impedance into consideration (default: False)
    subs: a dictionary of sympy Symbols to be substituted. It makes solving the circuit
          easier. Eg. {R1:R2} - replace R1 with R2. It can be generated with
          parse_substitutions()
    outfile: output filename ('stdout' means print to stdout).
    verbose: verbosity level 0 (silent) to 6 (painful).

    Returns: a dictionary with the solutions.
    """
    if subs is None:
        subs = {}  # no subs by default

    if not ac_enable:
        printing.print_info_line(("Starting symbolic DC analysis...", 1),
                                 verbose)
    else:
        printing.print_info_line(("Starting symbolic AC analysis...", 1),
                                 verbose)

    printing.print_info_line(("Building symbolic MNA, N and x...", 3),
                             verbose,
                             print_nl=False)
    mna, N, subs_g = generate_mna_and_N(circ,
                                        opts={'r0s': r0s},
                                        ac=ac_enable,
                                        verbose=verbose)
    x = get_variables(circ)
    mna = mna[1:, 1:]
    N = N[1:, :]
    printing.print_info_line((" done.", 3), verbose)

    printing.print_info_line(("Performing variable substitutions...", 5),
                             verbose)
    mna, N = apply_substitutions(mna, N, subs)

    printing.print_info_line(("MNA matrix (reduced):", 5), verbose)
    printing.print_info_line((sympy.sstr(mna), 5), verbose)
    printing.print_info_line(("N matrix (reduced):", 5), verbose)
    printing.print_info_line((sympy.sstr(N), 5), verbose)

    printing.print_info_line(("Building equations...", 3), verbose)
    eq = []
    for i in to_real_list(mna * x + N):
        eq.append(sympy.Eq(i, 0))

    x = to_real_list(x)
    if verbose > 4:
        printing.print_symbolic_equations(eq)
        print "To be solved for:"
        print x
        # print "Matrix is singular: ", (mna.det() == 0)
    # print -1.0*mna.inv()*N #too heavy
    # print sympy.solve_linear_system(mna.row_join(-N), x)
    printing.print_info_line(("Performing auxiliary simplification...", 3),
                             verbose)
    eq, x, sol_h = help_the_solver(eq, x)

    if len(eq):
        printing.print_info_line(("Symplified sytem:", 3), verbose)
        if verbose > 3:
            printing.print_symbolic_equations(eq)
        printing.print_info_line(("To be solved for:", 3), verbose)
        printing.print_info_line((str(x), 3), verbose)
        printing.print_info_line(("Solving...", 1), verbose)

        if options.symb_internal_solver:
            sol = local_solve(eq, x)
        else:
            sol = sympy.solve(eq,
                              x,
                              manual=options.symb_sympy_manual_solver,
                              simplify=True)
        if sol is not None:
            sol.update(sol_h)
        else:
            sol = sol_h
    else:
        printing.print_info_line(
            ("Auxiliary simplification solved the problem.", 3), verbose)
        sol = sol_h

    for ks in sol.keys():
        sol.update({ks: sol[ks].subs(subs_g)})

    # sol = sol_to_dict(sol, x)

    if sol == {}:
        printing.print_warning("No solutions. Check the netlist.")
    else:
        printing.print_info_line(("Success!", 2), verbose)
        printing.print_info_line(("Results:", 1), verbose)
        if options.cli:
            printing.print_symbolic_results(sol)

    if source is not None:
        src = sympy.Symbol(source.upper(), real=True)
        printing.print_info_line(
            ("Calculating small-signal symbolic transfer functions (%s))..." %
             (str(src), ), 2),
            verbose,
            print_nl=False)
        tfs = calculate_gains(sol, src)
        printing.print_info_line(("done.", 2), verbose)
        printing.print_info_line(
            ("Small-signal symbolic transfer functions:", 1), verbose)
        if options.cli:
            printing.print_symbolic_transfer_functions(tfs)
    else:
        tfs = None

    # convert to a results instance
    sol = results.symbolic_solution(sol, subs, circ, outfile)
    if tfs:
        if outfile and outfile != 'stdout':
            outfile += ".tfs"
        tfs = results.symbolic_solution(tfs, subs, circ, outfile, tf=True)
    return sol, tfs
Пример #39
0
def main(filename, outfile="stdout", verbose=3):
    """This method allows calling ahkab from a Python script.
    """
    printing.print_info_line(
        ("This is ahkab %s running with:" % (__version__), 6), verbose)
    printing.print_info_line(
        ("  Python %s" % (sys.version.split('\n')[0], ), 6), verbose)
    printing.print_info_line(("  Numpy %s" % (numpy.__version__), 6), verbose)
    printing.print_info_line(("  Sympy %s" % (sympy.__version__), 6), verbose)
    printing.print_info_line(("  Matplotlib %s" % (matplotlib.__version__), 6),
                             verbose)

    read_netlist_from_stdin = (filename is None or filename == "-")
    (circ, directives,
     postproc_direct) = netlist_parser.parse_circuit(filename,
                                                     read_netlist_from_stdin)

    check, reason = dc_analysis.check_circuit(circ)
    if not check:
        printing.print_general_error(reason)
        printing.print_circuit(circ)
        sys.exit(3)

    if verbose > 3 or _print:
        print "Parsed circuit:"
        printing.print_circuit(circ)

    ic_list = netlist_parser.parse_ics(directives)
    _handle_netlist_ics(circ, an_list=[], ic_list=ic_list)
    results = {}
    for an in netlist_parser.parse_analysis(circ, directives):
        if 'outfile' not in an.keys() or not an['outfile']:
            an.update({
                'outfile':
                outfile + ("." + an['type']) * (outfile != 'stdout')
            })
        if 'verbose' in an.keys() and (an['verbose'] is None or an['verbose'] < verbose) \
           or not 'verbose' in an.keys():
            an.update({'verbose': verbose})
        _handle_netlist_ics(circ, [an], ic_list=[])
        if verbose >= 4:
            printing.print_info_line(("Requested an.:", 4), verbose)
            printing.print_analysis(an)
        results.update(run(circ, [an]))

    postproc_list = netlist_parser.parse_postproc(circ, postproc_direct)
    if len(postproc_list) > 0 and len(results):
        process_postproc(postproc_list, circ.title, results, outfile)

    return results