예제 #1
0
파일: test.py 프로젝트: Gigahawk/mech421
def step_resp(vpk_pk):
    vmax = vpk_pk / 2
    shutil.copyfile('PA13.LIB', '/tmp/PA13.LIB')
    shutil.copyfile('op27.cir', '/tmp/op27.cir')
    circuit = Circuit('Step Response')
    circuit.include('/tmp/PA13.LIB')
    circuit.include('/tmp/op27.cir')
    circuit.subcircuit(PA13Amplifier(Z_1, Z_2))
    circuit.subcircuit(OP27Amplifier(R_4, C_4))

    # V_Ir input
    circuit.PulseVoltageSource(
        'input',
        'vir',
        circuit.gnd,
        -vmax,
        vmax,
        pulse_width=0.05,  # 0.05s
        period=0.1,  # 0.1s, 10Hz
        rise_time=1e-9,
        fall_time=1e-9)  # From lab provided schematic
    circuit.R('r3', 'vir', 'vir2', Z_3)
    # Current controller stage
    circuit.X('curr', 'op27_amplifier', 'vir2', 'vr')
    # Voltage stage
    circuit.X('volt', 'pa13_amplifier', 'vr', 'vo')
    # Motor stage
    circuit.R('rm', 'vo', 'vm1', R_m)
    circuit.L('lm', 'vm1', 'vio', L_m)

    circuit.R('rs', 'vio', circuit.gnd, R_s)
    circuit.R('r5', 'vio', 'vir2', Z_5)

    simulator = circuit.simulator()
    # Force ngspice to have shorter time steps near sharp transitions
    simulator.options(trtol=0.00001)
    import pdb
    pdb.set_trace()
    analysis = simulator.transient(
        step_time=0.1,  # Lab schematic suggests 0.1s, this seems too slow
        end_time=0.045
    )  # Lab schematic stops at 1s, we only need the first step
    return analysis
예제 #2
0
import PySpice.Logging.Logging as Logging
logger = Logging.setup_logging()

####################################################################################################

from PySpice.Probe.Plot import plot
from PySpice.Spice.Netlist import Circuit
from PySpice.Unit import *

####################################################################################################

#r# We will drive the transmission line with a pulse source and use a standard 50 Ω load.

circuit = Circuit('Transmission Line')
circuit.PulseVoltageSource('pulse', 'input', circuit.gnd, 0 @ u_V, 1 @ u_V, 1 @ u_ns, 1 @ u_us)
circuit.LosslessTransmissionLine('delay', 'output', circuit.gnd, 'input', circuit.gnd,
                                 impedance=50, time_delay=40e-9)
circuit.R('load', 'output', circuit.gnd, 50 @ u_Ω)

simulator = circuit.simulator(temperature=25, nominal_temperature=25)
analysis = simulator.transient(step_time=1e-11, end_time=100e-9)

####################################################################################################

figure = plt.figure(None, (20, 6))
plot(analysis['input'])
plot(analysis['output'])
plt.xlabel('Time [s]')
plt.ylabel('Voltage (V)')
plt.grid()
def do_monte_carlo_sim(tech, put, step_time, num_sims, plot_result, cvs, logger):
    # initialisar el generador alatoria usando el tiempo del sistema
    random.seed()

    # Abrir el archivo de .cvs
    if (cvs != None):
        try:
            cvs_handle = open(cvs,"w+")
        except:
            logger.error("Failed to open %s for writing, aborting", cvs)
            return


    logger.info("Running Monte Carlo simulation with path %s, tech %s, with step_time %e, num_sims %d", put.name(), tech.NAME, step_time, num_sims)

    # ==================
    # Generar el netlist
    # ==================
    libraries_path = find_libraries()
    circuit = Circuit("Monte_Carlo_Sim_"+put.name()+"_"+tech.NAME)
    circuit.include(libraries_path + "/" + tech.LIB_NAME)   #.inclcude "foo.lib"

    vdd = circuit.V('dd', 'Vdd', circuit.gnd, tech.VDD)     # Fuente de tensión Vdd

    # Fuente de tensión de pulses que usamos como la entrada de la ruta
    vin = circuit.PulseVoltageSource("In", "In", circuit.gnd, initial_value=0, pulsed_value=tech.VDD, pulse_width=1e-9, period=2e-9, delay_time=10e-12, rise_time=20e-12, fall_time=20e-12)

    # La ruta que queremos probar
    put.add_to_circuit(circuit, 'Vdd', 'In', 'Out')

    # ======================
    # Hacer las simulaciones
    # ======================

    # Comienza simulando por 100ps
    sim_time = 100e-12

    ts = time.time();

    # if simulation times out without seeing the transition, increase sim time by ...
    sim_time_step = 100e-12
    # Once we've seen a succesfull transisition (sim time was long enough)
    # we reduce simulation time to bestResult.tp + 50ps
    succesfull_run = False

    # Hay varios resultados con el mismo (o muy parecido) Tp
    # Si una simulación da un Tp un poco peor (1%?) peor usa menos area, deberíamos
    # usar esto resultado cómo el mejor.
    TP_FLEX_PERCENT = 1.0

    # guardamos el mejor resultado
    bestResult = Result(100.0, put.get_widths())

    # Y guardamos un array de todos los resultados
    allResults = []

    for l in range(1,num_sims+1):

        widths = put.get_widths()
        totalWidth = sum(widths)

        logger.debug("Running simulation with widths: [%s], sim_time %e, step_time %e", _get_widths_str(widths), sim_time, step_time)

        tp = _get_tp(circuit, tech, put, sim_time, step_time, logger)
        if (tp < 0):
            # La duración de simulación no estuvo suficiente largo
            # Si vimos una transición antes, entonces es claro que esto no puede ser mejor.
            # Pero si nunca vimos una transición antes, incrementamos la duración
            if (not succesfull_run):
                sim_time += sim_time_step
                logger.verbose("Out never transititons, increasing simulation time to %e", sim_time)
            else:
                logger.debug("Out never transititons")
        else:
            succesfull_run = True

            logger.verbose("tp: %e, widths: [%s], totalWidth: %e", tp, _get_widths_str(widths), totalWidth)

            allResults.append(Result(tp, widths))

            # este resultado tiene menor tp que el corriente mejor?
            if (tp < bestResult.tp):
                logger.verbose("  New Best Tp")
                bestResult = Result(tp, widths)

                # reducir la duración de la simulación a tp + 50ps
                sim_time = tp + 50e-12

        # =====================
        # Actualizar los anchos
        # =====================

        # Usamos los mejores anchos que encontramos como base
        widths = list(bestResult.widths)    # tomar una copia

        #-------------------------------------------------------------------
        # Método 1: Cambiar todos los ancho aleatoriamente
        #-------------------------------------------------------------------
        #for idx in range(1, len(widths)):
        #    width = random.uniform(tech.W_MIN, put.get_max_width())
        #    widths[idx] = width

        #----------------------------------------------------------------
        # Método 2: Cambiar un ancho aleatoriamente adentro todo el rango
        #----------------------------------------------------------------

        # Generar un ancho aleatoriamente entre tech.W_MIN y put.get_max_width()
        #width = random.uniform(tech.W_MIN, put.get_max_width())

        # Elegir cual ancho cambiar (no elegimos el primero)
        #idx = random.randint(1, len(widths)-1)
        #widths[idx] = width

        #----------------------------------------------------------------------
        # Método 3: Cambiar todos los ancho aleatoriamente en el rango de 0.5w
        #           a 2w. Dónde w es el ancho actual.
        #----------------------------------------------------------------------
        for idx in range(1, len(widths)):
            minWidth = max(tech.W_MIN, widths[idx]/2)
            maxWidth = min(put.get_max_width(), widths[idx]*2)
            width = random.uniform(minWidth, maxWidth)

            logger.debug("curr_width %e, minWidth %e, maxWidth %e, new width %e",
                          widths[idx], minWidth, maxWidth, width)

            widths[idx] = width

        # Hazlo
        put.set_widths(widths)

        if (l % 100 == 0):
            logger.info("Ran %d / %d (%.1f%%)", l, num_sims, (100.0 * l)/num_sims)

    te = time.time();

    # ======================
    # Mostrar los resultados
    # ======================
    logger.info("Took %ds to run %d simulations", int(te - ts), num_sims);
    logger.info("Best Tp %e, Widths [%s]", bestResult.tp, _get_widths_str(bestResult.widths))

    # ============================================
    # Encontrar el Tp optimo usando logical effort
    # ============================================
    LEwidths= put.get_logical_effort_optimal_widths()
    if (LEwidths == None):
        logger.warning("Optimal case not supported by this path")
    else:
        logger.info("Running test with optimal widths calculated via logical effort: [%s]", _get_widths_str(LEwidths))
        put.set_widths(LEwidths)
        LEtp = _get_tp(circuit, tech, put, sim_time, step_time, logger)

        if (LEtp <= 0):
            logger.info("Optimal Case: Out never transititons")
        else:
            logger.info("Optimal Case: %e, widths: [%s]", LEtp, _get_widths_str(LEwidths))

    # ================================================
    # Escribir los resultados al .cvs
    # ================================================
    if (cvs != None):
        # Comenzamos con un comentario
        cvs_handle.write("#%s: Step time %.1e, Num sims %d, path: %s, tech: %s, load: %.2f\n" %
                         (datetime.now().strftime("%Y/%m/%d %H:%M:%S"), step_time,
                          num_sims, put.name(), tech.NAME, put.get_load()))

        # La simulación de LE (comentario)
        if (LEwidths == None):
            cvs_handle.write("#Logical Effort not supported by this path\n")
        elif (LEtp <= 0):
            cvs_handle.write("#Logical Effort: out never transititons\n")
        else:
            cvs_handle.write("#Logical Effort: %e, widths: [%s]\n" %
                             (LEtp, _get_widths_str(LEwidths)))

        # El titulo de los columnos:
        widthHeadings = ""
        for i in range(len(widths)):
            widthHeadings += "width[%d], " % i

        ratioHeadings = ""
        for i in range(len(widths) - 1):
            ratioHeadings += "ratio %d to %d, " % (i, i+1)
        ratioHeadings += "ratio %d to load, " % (i+1)

        cvs_handle.write("Tp, " + widthHeadings + "load width, Total width, " + ratioHeadings + "Average ratio (not including load), Average ratio (including load)\n")

        # Y los resultados
        for r in allResults:

            ratios = []
            for i in range(len(r.widths) - 1):
                ratios.append(r.widths[i+1] / r.widths[i])

            avgWithoutLoad = sum(ratios)/len(ratios)

            ratios.append(put.get_load() * tech.W_MIN / r.widths[i+1])
            avgWithLoad = sum(ratios)/len(ratios)

            ratiosStr = ""
            for i, ratio in enumerate(ratios):
                if (i != 0):
                    ratiosStr += ", "
                ratiosStr += "%.2f" % ratio

            cvs_handle.write("%e, %s, %e, %e, %s, %.2f, %.2f\n" %
                             (r.tp,
                              _get_widths_str(r.widths),
                              put.get_load() * tech.W_MIN,
                              sum(r.widths),
                              ratiosStr,
                              avgWithoutLoad,
                              avgWithLoad))

        cvs_handle.close()

    # ================================================
    # Finalmente simula una vez más con anchos mejores
    # que encontramos y plotear el resultado
    # ================================================
    if (plot_result and (bestResult.tp > 0.0) and (bestResult.tp < 1.0)):
        put.set_widths(bestResult.widths)
        simulator = circuit.simulator(temperature=27, nominal_temperature=27)
        analysis = simulator.transient(end_time=sim_time*1.5, step_time=step_time)
        put.plot(analysis, 'In', 'Out')
예제 #4
0
print('Cout =', Cout)
print('Cint =', Cin)

circuit.V('in', 'in', circuit.gnd, Vin)
circuit.C('in', 'in', circuit.gnd, Cin)

# Fixme: out drop from 12V to 4V
# circuit.VCS('switch', 'gate', circuit.gnd, 'in', 'source', model='Switch', initial_state='off')
# circuit.PulseVoltageSource('pulse', 'gate', circuit.gnd, 0@u_V, Vin, duty_cycle, period)
# circuit.model('Switch', 'SW', ron=1@u_mΩ, roff=10@u_MΩ)

# Fixme: Vgate => Vout ???
circuit.X('Q', 'irf150', 'in', 'gate', 'source')
# circuit.PulseVoltageSource('pulse', 'gate', 'source', 0@u_V, Vin, duty_cycle, period)
circuit.R('gate', 'gate', 'clock', 1@u_Ohm)
circuit.PulseVoltageSource('pulse', 'clock', circuit.gnd, 0@u_V, 2.*Vin, duty_cycle, period)

circuit.X('D', '1N5822', circuit.gnd, 'source')
circuit.L(1, 'source', 1, L)
circuit.R('L', 1, 'out', RL)
circuit.C(1, 'out', circuit.gnd, Cout) # , initial_condition=0@u_V
circuit.R('load', 'out', circuit.gnd, Rload)

#####
# Simulation parameters
#####

simulator = circuit.simulator(temperature=25, nominal_temperature=25)
analysis = simulator.transient(step_time=period/300, end_time=period*150)

예제 #5
0
#r# We will now drive the diode with a pulse generator and perform a transient analysis.

#f# circuit_macros('diode-characteristic-curve-circuit-pulse.m4')

frequency = 1 @ u_MHz

circuit = Circuit('Diode')
circuit.include(spice_library['BAV21'])
# source = circuit.SinusoidalVoltageSource('input', 'in', circuit.gnd,
#                             dc_offset=dc_offset, offset=dc_offset,
#                             amplitude=ac_amplitude,
#                             frequency=frequency)
source = circuit.PulseVoltageSource('input',
                                    'in',
                                    circuit.gnd,
                                    initial_value=dc_offset - ac_amplitude,
                                    pulsed_value=dc_offset + ac_amplitude,
                                    pulse_width=frequency.period / 2,
                                    period=frequency.period)
circuit.R(1, 'in', 'out', 1 @ u_kΩ)
circuit.D('1', 'out', circuit.gnd, model='BAV21')

simulator = circuit.simulator(temperature=25, nominal_temperature=25)
analysis = simulator.transient(step_time=source.period / 1e3,
                               end_time=source.period * 4)

axe = plt.subplot(313)
# Fixme: axis, x scale
# plot(analysis['in'] - dc_offset + quiescent_points[0]['quiescent_voltage'], axis=axe)
# plot(analysis.out, axis=axe)
axe.plot(analysis.out.abscissa * 1e6, analysis.out)
# r# We will fit from the simulation output the time constant of each circuit and compare it to the
#r# theoretical value.

figure = plt.figure(1, (20, 10))

element_types = ('capacitor', 'inductor')

for element_type in ('capacitor', 'inductor'):

    circuit = Circuit(element_type.title())
    # Fixme: compute value
    source = circuit.PulseVoltageSource('input',
                                        'in',
                                        circuit.gnd,
                                        initial_value=0 @ u_V,
                                        pulsed_value=10 @ u_V,
                                        pulse_width=10 @ u_ms,
                                        period=20 @ u_ms)
    circuit.R(1, 'in', 'out', 1 @ u_kΩ)
    if element_type == 'capacitor':
        element = circuit.C
        value = 1 @ u_uF
        # tau = RC = 1 ms
    else:
        element = circuit.L
        # Fixme: force component value to an Unit instance ?
        value = 1 @ u_H
        # tau = L/R = 1 ms
    element(1, 'out', circuit.gnd, value)
    # circuit.R(2, 'out', circuit.gnd, kilo(1)) # for debug
예제 #7
0
####################################################################################################

libraries_path = find_libraries()
spice_library = SpiceLibrary(libraries_path)

####################################################################################################

#?# #cm# relay.m4

period = 50@u_ms
pulse_width = period / 2

circuit = Circuit('Relay')

# circuit.V('digital', 'Vdigital', circuit.gnd, 5@u_V)
circuit.PulseVoltageSource('clock', 'clock', circuit.gnd, 0@u_V, 5@u_V, pulse_width, period, rise_time=5@u_ms, fall_time=5@u_ms)
circuit.R('base', 'clock', 'base', 100@u_Ω)
circuit.BJT(1, 'collector', 'base', circuit.gnd, model='bjt') # Q is mapped to BJT !
circuit.model('bjt', 'npn', bf=80, cjc=pico(5), rb=100)
circuit.V('analog', 'VccAnalog', circuit.gnd, 8@u_V)
circuit.R('relay', 'VccAnalog', 1, 50@u_Ω)
circuit.L('relay', 1, 'collector', 100@u_mH)
circuit.include(spice_library['1N5822']) # Schottky diode
diode = circuit.X('D', '1N5822', 'collector', 'VccAnalog')
# Fixme: subcircuit node
# diode.minus.add_current_probe(circuit)

####################################################################################################

figure = plt.figure(1, (20, 10))
예제 #8
0
from PySpice.Unit import *

####################################################################################################

from PySpice.Spice.NgSpice.Shared import NgSpiceShared

####################################################################################################

libraries_path = find_libraries()
spice_library = SpiceLibrary(libraries_path)

####################################################################################################

circuit = Circuit('Basic Switch')

circuit.PulseVoltageSource('pulse', 'sw_drive', circuit.gnd, 0@u_V, 10@u_V, 1@u_ms, 2@u_ms,)

circuit.V('input', 'input', circuit.gnd, 20@u_V)
circuit.R('load', circuit.gnd, 'sw_node', 5@u_Ohm)

# circuit.VoltageControlledSwitch('input', 'sw_node', 'sw_drive', circuit.gnd, 'sw1', model=None)

# circuit.VoltageControlledSwitch('sw1', 'sw_node', 'sw_drive', circuit.gnd, 'sw1', model=None, initial_state=True)
# circuit.VoltageControlledSwitch('sw2', 'sw_node', 'sw_drive', circuit.gnd, 'sw1', model=None, initial_state=False)
# circuit.VoltageControlledSwitch('sw3', input_plus='sw_drive', input_minus=circuit.gnd, output_minus='sw_node', output_plus='input', model='SW')

circuit.VoltageControlledSwitch('input', 'sw_node', 'sw_drive', circuit.gnd, 'sw1', model='switch1')
circuit.model('switch1', 'SW',  Ron=.002@u_Ohm,  Roff=1@u_MOhm,  Vt=3.0@u_V)

print(circuit)
#####
# Buck LC output and diode
#####
circuit.X('D', '1N5822', circuit.gnd, 'pch_drain')
circuit.L(1, 'pch_drain', 1, L)
circuit.R('L', 1, 'out', RL)
circuit.C(1, 'out', circuit.gnd, Cout) # , initial_condition=0@u_V
circuit.R('load', 'out', circuit.gnd, Rload)



# This clock is used for NGspice mixed signal simulation.
# The python code runs every clock edge, both positive and negative
# clock speed: 20MHz
# clock cycle length: 50ns
circuit.PulseVoltageSource('clk', 'clk', circuit.gnd, 0@u_V, 1@u_V, 0.05@u_us, 0.1@u_us)


#####
# Add a step load
#####
# ~ circuit.PulseVoltageSource('name', n1, n2, v_low, v_high, t_high, t_period, t_delay,t_rise,t_fall)
circuit.PulseVoltageSource('load_sw', 'gate_drive2', circuit.gnd, 0@u_V, 10@u_V, 1@u_s,1@u_s,0.8@u_ms,10@u_ns)

# load switch
circuit.X('Q2', 'irf150', 'out', 'gate2', 'source2')
circuit.R('gate2', 'gate2', 'gate_drive2', 1@u_Ohm)
circuit.R('load_on','source2', circuit.gnd,Rload)

#####
# Simulation parameters
예제 #10
0
# Cout = 22@u_uF
# ESR = 20@u_mOhm
# ESL = 0

# parameters on input to buck
# circuit.V('input', 'input', circuit.gnd, Vin)
# circuit.C('input', 'input', circuit.gnd, Cin)

circuit.C(1, 'esr', circuit.gnd, 22 @ u_uF)  # , initial_condition=0@u_V
circuit.R(1, 'sense_net_2', 'esr', 10 @ u_Ohm)

# This clock is used for NGspice mixed signal simulation.
# The python code runs every clock edge, both positive and negative
# clock speed: 2.5MHz
# clock cycle length: 40ns
circuit.PulseVoltageSource('clk', 'clk', circuit.gnd, 0 @ u_V, 1 @ u_V,
                           20 @ u_ns, 40 @ u_ns)

#####
# Simulation parameters
#####
# Python block input constants
amplitude = 10 @ u_V

# Call the MyNgSpiceShared
ngspice_shared = MyNgSpiceShared(amplitude=amplitude, send_data=True)

simulator = circuit.simulator(temperature=25,
                              nominal_temperature=25,
                              simulator='ngspice-shared',
                              ngspice_shared=ngspice_shared)