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
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
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
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