Beispiel #1
0
def main():

    # Monkeypatch the exec_command() to not bail if it detects an 'error' in stderr,
    # these 'errors' don't seem to actually prevent the sim from working correctly
    Shared.NgSpiceShared.exec_command = exec_command

    libraries_path = find_libraries()
    spice_library = SpiceLibrary(libraries_path)

    directory_path = Path(__file__).resolve().parent
    kicad_netlist_path = directory_path.joinpath('simulation.cir')

    netlist_without_quotes_path = Path('./simulation-without-quotes.cir')
    remove_include_quotes(kicad_netlist_path, netlist_without_quotes_path)

    parser = SpiceParser(path=str(netlist_without_quotes_path))
    circuit = parser.build_circuit(ground=0)
    simulator = circuit.simulator(temperature=25, nominal_temperature=25)
    analysis = simulator.transient(step_time=100 @ u_ps, end_time=100 @ u_ns)

    v_out = analysis['OUT']

    fig, ax = plt.subplots(1, figsize=(10, 5))
    ax.plot(v_out.abscissa.as_ndarray() * 1e9, v_out.as_ndarray())
    ax.legend(('OUT', ), loc=(.8, .8))
    ax.grid()
    ax.set_xlabel('Time (ns)')
    ax.set_ylabel('Voltage (V)')

    plt.tight_layout()
    plt.savefig('out.png')
Beispiel #2
0
def main():

    # Monkeypatch the exec_command() to not bail if it detects an 'error' in stderr,
    # these 'errors' don't seem to actually prevent the sim from working correctly
    Shared.NgSpiceShared.exec_command = exec_command

    libraries_path = find_libraries()
    spice_library = SpiceLibrary(libraries_path)

    directory_path = Path(__file__).resolve().parent
    kicad_netlist_path = directory_path.joinpath(
        'wien-bridge-oscillator-sim.cir')
    parser = SpiceParser(path=str(kicad_netlist_path))
    circuit = parser.build_circuit(ground=0)
    simulator = circuit.simulator(temperature=25, nominal_temperature=25)
    analysis = simulator.transient(step_time=10 @ u_us, end_time=60 @ u_ms)

    v_sine_out = analysis['SINE_OUT']
    first_index_of_interest = np.where(
        v_sine_out.abscissa.as_ndarray() > 0.04)[0][0]

    fig, ax = plt.subplots(1, figsize=(10, 5))
    ax.plot(v_sine_out.abscissa.as_ndarray()[first_index_of_interest:],
            v_sine_out.as_ndarray()[first_index_of_interest:])
    ax.legend(('SINE_OUT', ), loc=(.8, .8))
    ax.grid()
    ax.set_xlabel('Time (s)')
    ax.set_ylabel('Voltage (V)')

    plt.tight_layout()
    plt.savefig('v-sine-out.png')
Beispiel #3
0
    def __init__(self, name):
        Circuit.__init__(self, name)
        libraries_path = 'C:\\Users\\micha\\PycharmProjects\\circuit_model\\component_libraries\\transistor'
        spice_library = SpiceLibrary(libraries_path)
        self.include(spice_library['ptm65nm_nmos'])
        self.include(spice_library['ptm65nm_pmos'])

        # input pair
        self.MOSFET(1, "vd_l", "inp", "vtail", self.gnd, model='ptm65nm_nmos', width=5e-6, length=0.65e-6)
        self.MOSFET(2, "vd_r", "inn", "vtail", self.gnd, model='ptm65nm_nmos', width=5e-6, length=0.65e-6)

        # active load
        self.MOSFET(3, "vd_l", "vd_l", "vdd", "vdd", model='ptm65nm_pmos', width=2.5e-6, length=0.65e-6)
        self.MOSFET(4, "vd_r", "vd_l", "vdd", "vdd", model='ptm65nm_pmos', width=2.5e-6, length=0.65e-6)

        # tail current
        self.MOSFET(5, "vtail", "vbias", self.gnd, self.gnd, model='ptm65nm_nmos', width=5e-6, length=1e-6)
        # input current mirror
        self.MOSFET(6, "vbias", "vbias", self.gnd, self.gnd, model='ptm65nm_nmos', width=5e-6, length=1e-6)

        # sources
        self.I(1, "vdd", "vbias", 1e-6)

        # load
        self.R('load', 'vd_r', self.gnd, 1e9)
        self.C('load', 'vd_r', self.gnd, 5e-12)
def test_buck_converter():
    spice_library = SpiceLibrary(os.path.abspath(os.path.dirname(__file__)))
    spice_library['1N4148']

    Vin = 20 @ u_V
    Vout = 15 @ u_V
    Vpulse = 5 @ u_V
    ratio = Vout / Vin

    clk_freq = 1 @ u_MHz
    clk_period = clk_freq.period

    sw_freq = 50 @ u_kHz
    sw_period = sw_freq.period

    sw_period_cnt = int(sw_period / clk_period)
    sw_width_cnt = int(sw_period_cnt * (1 - ratio))
    w_period = bitw(sw_period_cnt)

    def buck_converter(c, ins, outs):
        c.include(spice_library['1N4148'])
        ins.append(('gate', c.gnd))
        outs.append(('output', c.gnd))

        Rload = 3 @ u_Ohm
        L = 750 @ u_uH
        Cout = 0.47 @ u_uF

        c.V('input', 'vin', c.gnd, Vin)

        c.VCS(name='sw1',
              input_plus='gate',
              input_minus=c.gnd,
              output_minus='vin',
              output_plus='sw_out',
              model='SW',
              initial_state='off')
        c.model('SW', 'SW', Ron=1 @ u_mOhm, Roff=100 @ u_MOhm, Vt=1.1 @ u_V)

        c.X('D1', '1N4148', c.gnd, 'sw_out')
        c.L(1, 'sw_out', 'output', L)
        c.R(1, 'output', c.gnd, Rload)
        c.C(1, 'output', c.gnd, Cout)

    seq = [(sw_period_cnt, sw_width_cnt)] * 1000

    din = drv(t=Tuple[Uint[w_period], Uint[w_period]], seq=seq) \
        | pulse \
        | flatten \
        | Float

    din = din * int(Vpulse)

    dout = din | ngspice(f=buck_converter, init_x=0)

    dout | scope
    dout | shred

    verilate('/pulse')
    sim(timeout=4000, check_activity=False)
Beispiel #5
0
def test_half_rect():
    spice_library = SpiceLibrary(os.path.abspath(os.path.dirname(__file__)))
    spice_library['1N4148']

    def half_rect(c, ins, outs):
        c.include(spice_library['1N4148'])
        ins.append(('in', c.gnd))
        outs.append(('output', c.gnd))

        c.X('D1', '1N4148', 'in', 'output')
        c.R('load', 'output', c.gnd, 100)
        c.C('1', 'output', c.gnd, 1e-3)

    def sinus(a, w, th, t_step):
        t = 0
        while True:
            yield a * math.sin(w * t + th)
            t += t_step

    clk_freq = 1e6

    drv(t=Float, seq=sinus(a=10, w=2*math.pi*50, th=0, t_step=1 / clk_freq)) \
        | ngspice(f=half_rect, init_x=0) \
        | scope

    sim(timeout=40000)
Beispiel #6
0
def create_circuit(genome, config):
    libraries_path = '/home/alan/ngspice/libraries'  # os.path.join(os.path.dirname(os.path.dirname(__file__)), 'libraries')
    spice_library = SpiceLibrary(libraries_path)

    circuit = Circuit('NEAT')
    circuit.include(spice_library['1N4148'])

    Vbase = circuit.V('base', 'input1', circuit.gnd, 2)
    Vcc = circuit.V('cc', 'input2', circuit.gnd, 5)
    Vgnd = circuit.V('gnd', 'input3', circuit.gnd, 0)
    #circuit.R('test1', 'node0', circuit.gnd, 1e6)
    #circuit.R('test2', 'node0', 'input1', 1e6)
    ridx = 1
    xidx = 1
    for key, c in iteritems(genome.connections):
        if c.component == 'resistor':
            pin0, pin1 = get_pins(key)
            R = 10**c.value
            circuit.R(ridx, pin1, pin0, R)
            ridx += 1
        elif c.component == 'diode':
            pin0, pin1 = get_pins(key)
            circuit.X(xidx, '1N4148', pin1, pin0)
            xidx += 1

    return circuit
Beispiel #7
0
def init():
    logger = Logging.setup_logging()
    # libraries_path = find_libraries()
    libraries_path = '/home/anurag/Workspace/DTU/CourseProj/AE/website/DTU-VLAB/dtuvlab/lab/simulations/libraries'
    print(libraries_path)
    spice_library = SpiceLibrary(libraries_path)
    print(spice_library)
    circuit = Circuit('Diode Characteristic Curve')
    circuit.include(spice_library['1N4148'])
    print(spice_library['1N4148'])
    return circuit
Beispiel #8
0
def main():

    # Monkeypatch the exec_command() to not bail if it detects an 'error' in stderr,
    # these 'errors' don't seem to actually prevent the sim from working correctly
    Shared.NgSpiceShared.exec_command = exec_command

    libraries_path = find_libraries()
    spice_library = SpiceLibrary(libraries_path)

    directory_path = Path(__file__).resolve().parent
    kicad_netlist_path = directory_path.joinpath('schematic.cir')

    netlist_without_quotes_path = Path('./simulation-without-quotes.cir')
    remove_include_quotes(kicad_netlist_path, netlist_without_quotes_path)

    parser = SpiceParser(path=str(netlist_without_quotes_path))
    circuit = parser.build_circuit(ground=0)
    simulator = circuit.simulator(temperature=25, nominal_temperature=25)
    # analysis = simulator.transient(step_time=100@u_us, end_time=1000@u_ms)
    analysis = simulator.ac(start_frequency=100@u_mHz, stop_frequency=10@u_kHz, number_of_points=50,  variation='dec')

    v_out = analysis['v_out']
    mag = 20*np.log10(np.abs(v_out.as_ndarray()))
    print(mag)
    freq = analysis.frequency.as_ndarray()

    r1_Ohms = 2e3
    r2_Ohms = 10e3
    ratio = r2_Ohms / (r1_Ohms + r2_Ohms)
    ratio_dB = 20*np.log10(ratio)
    ratio_dB = -1.75
    r_parallel = (r1_Ohms * r2_Ohms) / (r1_Ohms + r2_Ohms)
    c_F = 10e-6
    fc = 1 / (2*np.pi*r_parallel*c_F)
    print(ratio_dB)

    fig, ax = plt.subplots(1, figsize=(10, 7))
    ax.plot(freq, mag, label='$V_{OUT}$')
    # ax.legend(('$V_{OUT}$',), loc=(.8,.8))
    ax.grid()
    ax.set_xscale('log')
    ax.set_xlabel('Frequency (Hz)')
    ax.set_ylabel('Voltage Magnitude (dB)')
    ax.axvline(fc, color='C2', label='$f_c$')
    ax.axhline(ratio_dB, color='C1', label=f'{ratio_dB:.2f}dB (DC gain)')
    ax.axhline(ratio_dB - 3.0, color='C1', label=f'{ratio_dB - 3:.2f}dB (DC gain - 3dB)')
    ax.legend()
    plt.tight_layout()
    plt.savefig('out.png')
Beispiel #9
0
def main():

    # Monkeypatch the exec_command() to not bail if it detects an 'error' in stderr,
    # these 'errors' don't seem to actually prevent the sim from working correctly
    Shared.NgSpiceShared.exec_command = exec_command

    libraries_path = find_libraries()
    spice_library = SpiceLibrary(libraries_path)

    directory_path = Path(__file__).resolve().parent
    kicad_netlist_path = directory_path.joinpath('schematic.cir')

    netlist_without_quotes_path = Path('./simulation-without-quotes.cir')
    remove_include_quotes(kicad_netlist_path, netlist_without_quotes_path)

    parser = SpiceParser(path=str(netlist_without_quotes_path))
    circuit = parser.build_circuit(ground=0)
    simulator = circuit.simulator(temperature=25, nominal_temperature=25)
    analysis = simulator.transient(step_time=1 @ u_us, end_time=1000 @ u_us)
    # analysis = simulator.ac(start_frequency=100@u_mHz, stop_frequency=10@u_kHz, number_of_points=50,  variation='dec')

    v_in = analysis['/v_in']
    v_out = analysis['v_out']

    fig, ax = plt.subplots(1, figsize=(7, 5))
    ax.plot(v_in.abscissa.as_ndarray() * 1e6,
            v_in.as_ndarray(),
            label='$v_{in}$')
    ax.plot(v_out.abscissa.as_ndarray() * 1e6,
            v_out.as_ndarray(),
            label='$v_{out}$')
    ax.axhline(-5.0, ls='--', color='C0')
    ax.axhline(5.0, ls='--', color='C0')
    ax.axhline(0, ls='--', color='C1')
    ax.axhline(3.3, ls='--', color='C1')
    ax.grid()
    ax.set_xlabel('Time [us]')
    ax.set_ylabel('Voltage [V]')
    ax.legend()
    plt.tight_layout()
    plt.savefig('out.png')
Beispiel #10
0
from PySpice.Spice.Library import SpiceLibrary

spice_library = SpiceLibrary('../examples/libraries')
# print list(spice_library.iter_on_subcircuits())
# print list(spice_library.iter_on_models())
print(list(spice_library.subcircuits))
print(list(spice_library.models))
Beispiel #11
0
Rh = 0.5 * 7.4 @ u_Ω  # Internal hub resistance, halved to compensate for 10 years
# of innovation.
Rhp = 2 * 76.6 @ u_Ω  # Internal hub resistance (parasitic), doubled to compensate
# for 10 years of innovation.

# Load model
Pl = -1 @ u_W  # constant power sink value.  Use -1W for one red LED at full power.
C = 200 @ u_uF  # input capacitor

# You need to clone the PySpice git repo somewhere and set the
# PYSPICE_EXAMPLES_PATH environment variable to the examples subdirectory.
# TODO: just import a diode model for the diodes we actually intend on using,
# e.g. schottky.
pyspice_examples_libraries_path = os.path.join(
    os.environ['PYSPICE_EXAMPLES_PATH'], 'libraries')
pyspice_examples_spice_library = SpiceLibrary(pyspice_examples_libraries_path)

# My own custom spice libraries, already next to this script.
custom_libraries_path = os.path.join(
    os.path.dirname(os.path.realpath(__file__)), 'libraries')
custom_spice_library = SpiceLibrary(custom_libraries_path)

circuit = Circuit('dynamo hub LED driver')
circuit.include(pyspice_examples_spice_library['1N4148'])  # standard diode
circuit.include(custom_spice_library['CONSTANT_POWER_LOAD']
                )  # models a switching regulator

# Hub dynamo model
source = circuit.Sinusoidal('input',
                            'in',
                            circuit.gnd,
Beispiel #12
0
def _gen_netlist_(self, **kwargs):
    """
    Return a PySpice Circuit generated from a SKiDL circuit.

    Args:
        title: String containing the title for the PySpice circuit.
        libs: String or list of strings containing the paths to directories
            containing SPICE models.
    """

    if USING_PYTHON2:
        return None

    # Create an empty PySpice circuit.
    title = kwargs.pop('title', '')  # Get title and remove it from kwargs.
    circuit = PySpiceCircuit(title)

    # Initialize set of libraries to include in the PySpice circuit.
    includes = set()

    # Add any models used by the parts.
    models = set([getattr(part, 'model', None) for part in self.parts])
    models.discard(None)
    lib_dirs = set(flatten([kwargs.get('libs', None)]))
    lib_dirs.discard(None)
    spice_libs = [SpiceLibrary(dir) for dir in lib_dirs]
    for model in models:
        for spice_lib in spice_libs:
            try:
                includes.add(spice_lib[model])
            except KeyError:
                pass
            else:
                break
        else:
            logger.error('Unknown SPICE model: {}'.format(model))

    # Add any subckt libraries used by the parts.
    part_names = set([
        getattr(part, 'name', None) for part in self.parts
        if getattr(part, 'filename', None)
    ])
    lib_files = set([getattr(part, 'filename', None) for part in self.parts])
    lib_files.discard(None)
    lib_dirs = [os.path.dirname(f) for f in lib_files]
    spice_libs = [SpiceLibrary(dir) for dir in lib_dirs]
    for part_name in part_names:
        for spice_lib in spice_libs:
            try:
                includes.add(spice_lib[part_name])
            except KeyError:
                pass
            else:
                break
        else:
            logger.error('Unknown SPICE subckt: {}'.format(part_name))

    # Add the models and subckt libraries to the PySpice circuit.
    for inc in includes:
        circuit.include(inc)

    # Add each part in the SKiDL circuit to the PySpice circuit.
    for part in sorted(self.parts, key=lambda p: str(p.ref)):
        # Add each part. All PySpice parts have an add_to_spice attribute
        # and can be added directly. Other parts are added as subcircuits.
        try:
            add_func = part.pyspice['add']
        except (AttributeError, KeyError):
            logger.error('Part has no SPICE model: {}'.format(part))
        else:
            add_func(part, circuit)

    return circuit
Beispiel #13
0
import PySpice.Logging.Logging as Logging
logger = Logging.setup_logging()

from PySpice.Doc.ExampleTools import find_libraries
from PySpice.Probe.Plot import plot
from PySpice.Spice.Library import SpiceLibrary
from PySpice.Spice.Netlist import Circuit
from PySpice.Spice.Parser import SpiceParser
from PySpice.Spice.Netlist import SubCircuitFactory
from PySpice.Unit import *


####################################################################################################
# IMPORT SPICE NETLIST OF CIRCUIT:

spice_library = SpiceLibrary('../libraries/')
netlist_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'NAND2.sp')
parser = SpiceParser(path=netlist_path)
circuit = parser.build_circuit()
circuit.include(spice_library['NAND2'])


####################################################################################################
# CONFIGURE VOLTAGE SOURCES

supply = 1@u_V
circuit.V('supply', 'vdd', 'vss', supply)
circuit.V('ground', 'vss', circuit.gnd, circuit.gnd)


####################################################################################################
Beispiel #14
0
def _load_sch_lib_(self, filename=None, lib_search_paths_=None, lib_section=None):
    """
    Load the .subckt I/O from a SPICE library file.

    Args:
        filename: The name of the SPICE library file.
        lib_search_paths_ : List of directories to search for the file.
    """

    from ..skidl import lib_suffixes
    from ..part import Part
    from ..pin import Pin

    if os.path.isdir(filename):
        # A directory was given, so just use that.
        spice_lib_path = os.path.abspath(filename)
    else:
        # A file name was given, so find the absolute file path in the search paths.
        fp, spice_lib_path = find_and_open_file(
            filename=filename,
            paths=lib_search_paths_,
            ext=lib_suffixes[SPICE],
            exclude_binary=True,
            descend=-1,
        )
        fp.close()  # Close the file pointer. We just need the path to the file.

    # Read the Spice library from the given path.
    spice_lib = SpiceLibrary(
        root_path=spice_lib_path, recurse=True, section=lib_section
    )

    # Get the unique set of files referenced by the subcircuits in the Spice library.
    lib_files = set([str(spice_lib[subcirc]) for subcirc in spice_lib.subcircuits])

    # Go through the files and create a SKiDL Part for each subcircuit.
    for lib_file in lib_files:
        with open(lib_file) as f:

            # Read the definition of each part line-by-line and then create
            # a Part object that gets stored in the part list.
            for statement in _gather_statement(f):

                # Look for the start of a part definition.
                if statement[0] == ".subckt":

                    # Create an un-filled part template.
                    part = Part(part_defn="don't care", tool=SPICE, dest=LIBRARY)
                    part.fplist = []
                    part.aliases = []
                    part.num_units = 1
                    part.ref_prefix = "X"
                    part._ref = None
                    part.filename = ""
                    part.name = ""
                    part.pins = []
                    part.pyspice = {
                        "name": "X",
                        "add": add_subcircuit_to_circuit,
                        "lib": spice_lib,
                        "lib_path": spice_lib_path,
                        "lib_section": lib_section,
                    }

                    # Flesh-out the part.
                    # Parse the part definition.
                    pieces = statement
                    try:
                        # part defn: .subckt part_name pin1, pin2, ... pinN.
                        part.name = pieces[1]
                        part.pins = [Pin(num=p, name=p) for p in pieces[2:]]
                        part.associate_pins()
                    except IndexError:
                        logger.warn(
                            "Misformatted SPICE subcircuit: {}".format(part.part_defn)
                        )
                    else:
                        # Now find a symbol file for the part to assign names to the pins.
                        # First, check for LTSpice symbol file.
                        sym_file, sym_file_path = find_and_open_file(
                            part.name,
                            lib_search_paths_,
                            ".asy",
                            allow_failure=True,
                            exclude_binary=True,
                            descend=-1,
                        )
                        if sym_file:
                            pin_names = []
                            pin_indices = []
                            for sym_line in sym_file:
                                if not sym_line:
                                    continue
                                if sym_line.lower().startswith("pinattr pinname"):
                                    pin_names.append(sym_line.split()[2])
                                elif sym_line.lower().startswith("pinattr spiceorder"):
                                    pin_indices.append(sym_line.split()[2])
                                elif sym_line.lower().startswith("symattr description"):
                                    part.description = " ".join(sym_line.split()[2:])
                            sym_file.close()

                            # Pin names and indices should be matched by the order they
                            # appeared in the symbol file. Each index should match the
                            # order of the pins in the .subckt file.
                            for index, name in zip(pin_indices, pin_names):
                                part.pins[int(index) - 1].name = name
                        else:
                            # No LTSpice symbol file, so check for PSPICE symbol file.
                            sym_file, sym_file_path = find_and_open_file(
                                filename,
                                lib_search_paths_,
                                ".slb",
                                allow_failure=True,
                                exclude_binary=True,
                                descend=-1,
                            )
                            if sym_file:
                                pin_names = []
                                active = False
                                for sym_line in sym_file:
                                    sym_line = sym_line.strip()
                                    if not sym_line:
                                        continue
                                    line_parts = sym_line.lower().split()
                                    if line_parts[0] == "*symbol":
                                        active = line_parts[1] == part.name.lower()
                                    if active:
                                        if line_parts[0] == "p":
                                            pin_names.append(line_parts[6])
                                        elif line_parts[0] == "d":
                                            part.description = " ".join(line_parts[1:])
                                sym_file.close()

                                pin_indices = list(range(len(pin_names)))
                                for pin, name in zip(part.pins, pin_names):
                                    pin.name = name

                    # Add subcircuit part to the library.
                    self.add_parts(part)
Beispiel #15
0
def _gen_netlist_(self, **kwargs):
    """
    Return a PySpice Circuit generated from a SKiDL circuit.

    Args:
        title: String containing the title for the PySpice circuit.
        libs: String or list of strings containing the paths to directories
            containing SPICE models.
    """

    from ..skidl import lib_search_paths

    if USING_PYTHON2:
        return None

    # Replace any special chars in all net names because Spice won't like them.
    # Don't use self.get_nets() because that only returns a single net from a
    # group of attached nets so the other nets won't get renamed.
    for net in self.nets:
        net.replace_spec_chars_in_name()

    # Create an empty PySpice circuit.
    title = kwargs.pop("title", "")  # Get title and remove it from kwargs.
    circuit = PySpiceCircuit(title)

    # Default SPICE libraries will be read-in down below if needed.
    default_libs = []

    # Initialize set of libraries to include in the PySpice circuit.
    model_paths = set()  # Paths to the model files that have been used.
    lib_paths = set()  # Paths to the library files that have been used.
    lib_ids = set()  # A lib_id is a tuple of the path to the lib file and a section.

    for part in self.parts:
        try:
            pyspice = part.pyspice
        except AttributeError:
            continue

        model = getattr(part, "model", None)
        if model:
            if isinstance(model, (XspiceModel, DeviceModel)):
                circuit.model(*model.args, **model.kwargs)
            else:
                try:
                    path = pyspice["lib"][model]
                except KeyError:
                    # The part doesn't contain the library with the model, so look elsewhere.
                    if not default_libs:
                        # Read the default SPICE libraries.
                        for path in lib_search_paths[SPICE]:
                            default_libs.append(
                                SpiceLibrary(root_path=path, recurse=True)
                            )

                    # Search for the model in the default libraries.
                    path = None
                    for lib in default_libs:
                        try:
                            path = lib[model]
                            break
                        except KeyError:
                            pass
                    if path == None:
                        logger.error(
                            "Unable to find model {} for part {}".format(
                                model, part.ref
                            )
                        )

                # Include the model file if it hasn't been included yet.
                if path != None and path not in model_paths:
                    circuit.include(path)
                    model_paths.add(path)

        try:
            path, section = pyspice["lib_path"], pyspice["lib_section"]
        except KeyError:
            continue
        if not section:
            # Libraries without a section are added as include files.
            if path not in lib_paths:
                circuit.include(path)
                lib_paths.add(path)
        else:
            lib_id = (path, section)
            if lib_id not in lib_ids:
                circuit.lib(*lib_id)
                lib_ids.add(lib_id)

    # Add each part in the SKiDL circuit to the PySpice circuit.
    # TODO: Make sure self.parts is processed in order that parts were created so ngspice doesn't get references to parts before they exist.
    for part in self.parts:
        # Add each part using its add function which will be either
        # add_part_to_circuit() or add_subcircuit_to_circuit().
        try:
            add_func = part.pyspice["add"]
        except (AttributeError, KeyError):
            logger.error("Part has no SPICE model: {}".format(part))
        else:
            add_func(part, circuit)

    return circuit
Beispiel #16
0
def test_pyspice_envelope():
    times, dt = np.linspace(0, 100e-9, 2048, endpoint=False, retstep=True)
    pulse = pyrex.AskaryanSignal(times=times, energy=1e8, theta=45*np.pi/180,
                                 n=1.75, t0=20e-9)

    performance_test("pyrex.Signal(pulse.times, pulse.envelope)", number=1000,
                     setup="import pyrex", use_globals={"pulse": pulse})

    spice_library = SpiceLibrary("/Users/bhokansonfasig/Documents/IceCube/"+
                                 "scalable_radio_array/spice_models")

    class NgSpiceSharedSignal(NgSpiceShared):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self._signal = None

        def get_vsrc_data(self, voltage, time, node, ngspice_id):
            self._logger.debug('ngspice_id-{} get_vsrc_data @{} node {}'.format(ngspice_id, time, node))
            voltage[0] = np.interp(time, self._signal.times, self._signal.values)
            return 0

    ngspice_shared = NgSpiceSharedSignal()

    class NgSpiceSignal:
        def __init__(self, signal, shared=ngspice_shared):
            self.shared = ngspice_shared
            self.shared._signal = signal

    def setup_circuit(kind="biased"):
        if kind=="biased":
            circuit = Circuit('Biased Envelope Circuit')
            circuit.include(spice_library['hsms'])

            circuit.V('in', 'input', circuit.gnd, 'dc 0 external')
            # bias portion
            circuit.C(2, 'input', 1, 10@u_nF)
            circuit.R(2, 1, 2, 1@u_kOhm)
            circuit.X('D2', 'hsms', 2, circuit.gnd)
            circuit.R(3, 2, 'bias', 1@u_kOhm)
            circuit.V('bias', 'bias', circuit.gnd, 5@u_V)
            # envelope portion
            circuit.X('D1', 'hsms', 1, 'output')
            circuit.C(1, 'output', circuit.gnd, 220@u_pF)
            circuit.R(1, 'output', circuit.gnd, 50@u_Ohm)
            return circuit

        elif kind=="basic":
            circuit = Circuit('Biased Envelope Circuit')
            circuit.include(spice_library['hsms'])

            circuit.V('in', 'input', circuit.gnd, 'dc 0 external')
            # envelope portion
            circuit.X('D1', 'hsms', 'input', 'output')
            circuit.C(1, 'output', circuit.gnd, 220@u_pF)
            circuit.R(1, 'output', circuit.gnd, 50@u_Ohm)
            return circuit

        elif kind=="diode":
            circuit = Circuit('Diode Output')
            circuit.include(spice_library['hsms'])
            
            circuit.V('in', 'input', circuit.gnd, 'dc 0 external')
            circuit.X('D1', 'hsms', 'input', 'output')
            return circuit

    performance_test("ng_in = NgSpiceSignal(pulse); "+
                     "simulator = circuit.simulator(temperature=25, "+
                     "nominal_temperature=25, ngspice_shared=ng_in.shared); "+
                     "analysis = simulator.transient(step_time=dt, "+
                     "end_time=pulse.times[-1]); "+
                     "pyrex.Signal(analysis.output.abscissa, analysis.output)",
                     number=10,
                     setup="import pyrex; circuit = setup_circuit()",
                     use_globals={"pulse": pulse, "dt": dt,
                                  "setup_circuit": setup_circuit,
                                  "NgSpiceSignal": NgSpiceSignal},
                     alternate_title="pyrex.Signal(analysis.output.abscissa, "+
                                     "analysis.output)")


    def envelope_circuit(signal, cap=220e-12, res=50):
        v_c = 0
        v_out = []

        r_d = 25
        i_s = 3e-6
        n = 1.06
        v_t = 26e-3

        charge_exp = np.exp(-signal.dt/(res*cap))
        discharge = i_s*res*(1-charge_exp)
        lambert_factor = n*v_t*res/r_d*(1-charge_exp)
        frac = i_s*r_d/n/v_t

        lambert_exponent = np.log(frac) + frac

        for v_in in signal.values:
            a = lambert_exponent + (v_in - v_c)/n/v_t
            if a>100:
                b = np.log(a)
                lambert_term = a - b + b/a
            else:
                lambert_term = np.real(lambertw(np.exp(a)))
                if np.isnan(lambert_term):
                    lambert_term = 0
            v_c = v_c*charge_exp - discharge + lambert_factor*lambert_term
            v_out.append(v_c)

        return pyrex.Signal(signal.times, v_out,
                            value_type=pyrex.Signal.ValueTypes.voltage)


    performance_test("envelope(pulse)",
                     number=100,
                     use_globals={"pulse": pulse, "envelope": envelope_circuit},
                     alternate_title="analytic circuit simulation")
import matplotlib.pyplot as plt


import PySpice.Logging.Logging as Logging
logger = Logging.setup_logging()


from PySpice.Doc.ExampleTools import find_libraries
from PySpice.Probe.Plot import plot
from PySpice.Spice.Library import SpiceLibrary
from PySpice.Spice.Netlist import Circuit
from PySpice.Unit import *

# ===== Create circuit =====

spice_library = SpiceLibrary("libraries")
circuit = Circuit('Transistor')

Vbase = circuit.V('base', '1', circuit.gnd, 1@u_V)
circuit.R('base', 1, 'base', 1@u_kΩ)
Vcollector = circuit.V('collector', '2', circuit.gnd, 0@u_V)
circuit.R('collector', 2, 'collector', 1@u_kΩ)
# circuit.BJT(1, 'collector', 'base', circuit.gnd, model='generic')
# circuit.model('generic', 'npn')
circuit.include(spice_library['2n2222a'])
circuit.BJT(1, 'collector', 'base', circuit.gnd, model='2n2222a')
print(circuit)

# ===== Run simulation =====

simulator = circuit.simulator(temperature=25, nominal_temperature=25)
Beispiel #18
0
    def define_circuit(self):
        logger = Logging.setup_logging()
        circuit_lab = self.circuit
        circuit = Circuit(circuit_lab["name"])

        # for complex circuit elements that requires SPICE library
        # libraries_path = find_libraries()

        python_file = os.path.abspath(sys.argv[0])
        examples_root = parent_directory_of(python_file)
        libraries_path = os.path.join(examples_root, 'libraries')

        spice_library = SpiceLibrary(libraries_path)

        # return message
        message = ""

        # add all elements to the PySpice circuit
        for element in circuit_lab:
            if element == "V":
                for dc_voltage_source in circuit_lab["V"]:
                    circuit.V(
                        dc_voltage_source["id"],
                        circuit.gnd if dc_voltage_source["node1"] == "gnd" else
                        dc_voltage_source["node1"],
                        circuit.gnd if dc_voltage_source["node2"] == "gnd" else
                        dc_voltage_source["node2"],
                        dc_voltage_source["value"] @ u_V)

            elif element == "VA":
                for ac_voltage_source in circuit_lab["VA"]:
                    circuit.SinusoidalVoltageSource(
                        ac_voltage_source["id"],
                        circuit.gnd if ac_voltage_source["node1"] == "gnd" else
                        ac_voltage_source["node1"],
                        circuit.gnd if ac_voltage_source["node2"] == "gnd" else
                        ac_voltage_source["node2"],
                        amplitude=ac_voltage_source["amplitude"] @ u_V,
                        frequency=ac_voltage_source["frequency"] @ u_Hz,
                        offset=ac_voltage_source["offset"] @ u_V)

            elif element == "I":
                for dc_current_source in circuit_lab["I"]:
                    circuit.I(
                        dc_current_source["id"],
                        circuit.gnd if dc_current_source["node1"] == "gnd" else
                        dc_current_source["node1"],
                        circuit.gnd if dc_current_source["node2"] == "gnd" else
                        dc_current_source["node2"],
                        dc_current_source["value"] @ u_A)

            elif element == "IA":
                for ac_current_source in circuit_lab["IA"]:
                    circuit.SinusoidalCurrentSource(
                        ac_current_source["id"],
                        circuit.gnd if ac_current_source["node1"] == "gnd" else
                        ac_current_source["node1"],
                        circuit.gnd if ac_current_source["node2"] == "gnd" else
                        ac_current_source["node2"],
                        amplitude=ac_current_source["amplitude"] @ u_A,
                        frequency=ac_current_source["frequency"] @ u_Hz,
                        offset=ac_current_source["offset"] @ u_A)

            elif element == "R":
                for resistor in circuit_lab["R"]:
                    circuit.R(
                        resistor["id"], circuit.gnd if resistor["node1"]
                        == "gnd" else resistor["node1"], circuit.gnd
                        if resistor["node2"] == "gnd" else resistor["node2"],
                        resistor["value"] @ u_Ω)

            elif element == "L":
                for inductor in circuit_lab["L"]:
                    circuit.L(
                        inductor["id"], circuit.gnd if inductor["node1"]
                        == "gnd" else inductor["node1"], circuit.gnd
                        if inductor["node2"] == "gnd" else inductor["node2"],
                        inductor["value"] @ u_H)

            elif element == "C":
                for capacitor in circuit_lab["C"]:
                    circuit.C(
                        capacitor["id"], circuit.gnd if capacitor["node1"]
                        == "gnd" else capacitor["node1"], circuit.gnd
                        if capacitor["node2"] == "gnd" else capacitor["node2"],
                        capacitor["value"] @ u_F)

            elif element == "D":
                for diode in circuit_lab["D"]:
                    try:
                        circuit.include(spice_library[diode["modelType"]])
                        circuit.X(
                            diode["id"], diode["modelType"], circuit.gnd
                            if diode["node1"] == "gnd" else diode["node1"],
                            circuit.gnd
                            if diode["node2"] == "gnd" else diode["node2"])
                    except KeyError as e:
                        message += " " + str(e)

            elif element == "nBJT":
                for nBJT in circuit_lab["nBJT"]:
                    try:
                        circuit.include(spice_library[nBJT["modelType"]])
                        circuit.BJT(nBJT["id"],
                                    circuit.gnd if nBJT["node1"] == "gnd" else
                                    nBJT["node1"],
                                    circuit.gnd if nBJT["node2"] == "gnd" else
                                    nBJT["node2"],
                                    circuit.gnd if nBJT["node3"] == "gnd" else
                                    nBJT["node3"],
                                    model=nBJT["modelType"])
                    except KeyError as e:
                        message += " " + str(e)

            elif element == "pBJT":
                for pBJT in circuit_lab["pBJT"]:
                    try:
                        circuit.include(spice_library[pBJT["modelType"]])
                        circuit.BJT(pBJT["id"],
                                    circuit.gnd if pBJT["node3"] == "gnd" else
                                    pBJT["node3"],
                                    circuit.gnd if pBJT["node2"] == "gnd" else
                                    pBJT["node2"],
                                    circuit.gnd if pBJT["node1"] == "gnd" else
                                    pBJT["node1"],
                                    model=pBJT["modelType"])
                    except KeyError as e:
                        message += " " + str(e)

            elif element == "NMOS":
                for NMOS in circuit_lab["NMOS"]:
                    try:
                        circuit.include(spice_library[NMOS["modelType"]])
                        # nodes are: drain, gate, source, bulk
                        circuit.MOSFET(NMOS["id"],
                                       circuit.gnd if NMOS["node4"] == "gnd"
                                       else NMOS["node4"],
                                       circuit.gnd if NMOS["node2"] == "gnd"
                                       else NMOS["node2"],
                                       circuit.gnd if NMOS["node3"] == "gnd"
                                       else NMOS["node3"],
                                       circuit.gnd if NMOS["node1"] == "gnd"
                                       else NMOS["node1"],
                                       model=NMOS["modelType"])
                    except KeyError as e:
                        message += " " + str(e)

            elif element == "PMOS":
                for PMOS in circuit_lab["PMOS"]:
                    try:
                        circuit.include(spice_library[PMOS["modelType"]])
                        # nodes are: source, gate, drain, bulk
                        circuit.MOSFET(PMOS["id"],
                                       circuit.gnd if PMOS["node1"] == "gnd"
                                       else PMOS["node1"],
                                       circuit.gnd if PMOS["node2"] == "gnd"
                                       else PMOS["node2"],
                                       circuit.gnd if PMOS["node3"] == "gnd"
                                       else PMOS["node3"],
                                       circuit.gnd if PMOS["node4"] == "gnd"
                                       else PMOS["node4"],
                                       model=PMOS["modelType"])
                    except KeyError as e:
                        message += " " + str(e)

            # add ammeter as a 0 volt voltage source
            elif element == "AM":
                for ammeter in circuit_lab["AM"]:
                    circuit.V(
                        ammeter["id"], circuit.gnd if ammeter["node1"] == "gnd"
                        else ammeter["node1"], circuit.gnd if ammeter["node2"]
                        == "gnd" else ammeter["node2"], ammeter["value"] @ u_V)

        if not message:
            self.spice = circuit
            return message
        return "Undefined model type:" + message
Beispiel #19
0
NODELIST.update({i: i for i in range(0, N_NODES)})
VCC_V = '5V'
VDD_V = '-5V'
HISTORY = {}

ELEMLIST = [0, 1, 2, 3, 6]
#print(NODELIST_keys)


def target(inp):
    return abs(inp)


def evaluator(inp, outp):
    return (1 / math.sqrt(1 + (abs(target(inp) - outp) * 20))) * (
        (abs(inp - (outp)) > abs(inp * 0.05)))


if __name__ == "__main__":
    toolbox = deap.base.Toolbox()
    toolbox.register("evaluator", evaluator)
    s = spicega.SpiceGA(toolbox,
                        nodelist=NODELIST,\
                        elemlist=ELEMLIST,\
                        ngen=NGEN,\
                        popsize=POPSIZE,\
                        n_nodes = 20,
                        mutationpb = MUTPB,\
                        spice_library=SpiceLibrary(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'libraries')))
    s.run()
Beispiel #20
0
from pathlib import Path
from PySpice.Spice.Library import SpiceLibrary

library_path = Path(__file__).resolve().parents[1].joinpath('examples', 'libraries')
print(library_path)
spice_library = SpiceLibrary(library_path)
# print list(spice_library.iter_on_subcircuits())
# print list(spice_library.iter_on_models())
print(list(spice_library.subcircuits))
print(list(spice_library.models))
Beispiel #21
0
def _gen_netlist_(self, **kwargs):
    """
    Return a PySpice Circuit generated from a SKiDL circuit.

    Args:
        title: String containing the title for the PySpice circuit.
        libs: String or list of strings containing the paths to directories
            containing SPICE models.
    """

    if USING_PYTHON2:
        return None

    # Create an empty PySpice circuit.
    title = kwargs.pop("title", "")  # Get title and remove it from kwargs.
    circuit = PySpiceCircuit(title)

    # Initialize set of libraries to include in the PySpice circuit.
    includes = set()

    # Add any models used by the parts.
    models = set([getattr(part, "model", None) for part in self.parts])
    models.discard(None)
    lib_dirs = set(flatten([kwargs.get("libs", None)]))
    lib_dirs.discard(None)
    spice_libs = [SpiceLibrary(dir) for dir in lib_dirs]
    for model in models:
        if isinstance(model, (XspiceModel, DeviceModel)):
            circuit.model(*model.args, **model.kwargs)
        else:
            for spice_lib in spice_libs:
                try:
                    includes.add(spice_lib[model])
                except KeyError:
                    pass
                else:
                    break
            else:
                logger.error("Unknown SPICE model: {}".format(model))

    # Add any subckt libraries used by the parts.
    part_names = set(
        [
            getattr(part, "name", None)
            for part in self.parts
            if getattr(part, "filename", None)
        ]
    )
    lib_files = set([getattr(part, "filename", None) for part in self.parts])
    lib_files.discard(None)
    lib_dirs = [os.path.dirname(f) for f in lib_files]
    spice_libs = [SpiceLibrary(dir) for dir in lib_dirs]
    for part_name in part_names:
        for spice_lib in spice_libs:
            try:
                includes.add(spice_lib[part_name])
            except KeyError:
                pass
            else:
                break
        else:
            logger.error("Unknown SPICE subckt: {}".format(part_name))

    # Add the models and subckt libraries to the PySpice circuit.
    for inc in includes:
        circuit.include(inc)

    # Add each part in the SKiDL circuit to the PySpice circuit.
    for part in sorted(self.parts, key=lambda p: str(p.ref)):
        # Add each part using its add function which will be either
        # add_part_to_circuit() or add_subcircuit_to_circuit().
        try:
            add_func = part.pyspice["add"]
        except (AttributeError, KeyError):
            logger.error("Part has no SPICE model: {}".format(part))
        else:
            add_func(part, circuit)

    return circuit
####################################################################################################

import PySpice.Logging.Logging as Logging
logger = Logging.setup_logging()

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

from PySpice.Spice.Netlist import Circuit
from PySpice.Spice.Library import SpiceLibrary
from PySpice.Unit import *
from PySpice.Physics.SemiConductor import ShockleyDiode

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

libraries_path = os.path.join(os.environ['PySpice_examples_path'], 'libraries')
spice_library = SpiceLibrary(libraries_path)

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

#!# For this purpose, we use the common high-speed diode 1N4148.  The diode is driven by a variable
#!# voltage source through a limiting current resistance.

#cm# diode-characteristic-curve-circuit.m4

circuit = Circuit('Diode Characteristic Curve')

circuit.include(spice_library['1N4148'])

circuit.V('input', 'in', circuit.gnd, 10 @ u_V)
circuit.R(1, 'in', 'out', 1 @ u_Ω)  # not required for simulation
circuit.X('D1', '1N4148', 'out', circuit.gnd)
Beispiel #23
0
def script():
    logger = Logging.setup_logging()
    libraries_path = find_libraries()
    print(libraries_path)
    spice_library = SpiceLibrary(libraries_path)
    print(spice_library)
    circuit = Circuit('Diode Characteristic Curve')
    circuit.include(spice_library['1N4148'])
    print(spice_library['1N4148'])

    # def defaultCircuitParams():
    circuit.V('input', 'in', circuit.gnd, 10 @ u_V)
    circuit.R(1, 'in', 'out', 1 @ u_Ω)  # not required for simulation
    circuit.X('D1', '1N4148', 'out', circuit.gnd)

    # Voltage and Resistance in 10e-06, X is diode type
    # def setCircuitParams(V, R, X):
    #     circuit.V('input', 'in', circuit.gnd, V@u_V)
    #     circuit.R(1, 'in', 'out', R@u_Ω) # not required for simulation
    #     circuit.X('D1', X, 'out', circuit.gnd)

    #r# We simulate the circuit at these temperatures: 0, 25 and 100 °C.

    # Fixme: Xyce ???
    temperatures = [0, 25, 100] @ u_Degree
    analyses = {}

    # def simulateTemp():
    for temperature in temperatures:
        simulator = circuit.simulator(temperature=temperature,
                                      nominal_temperature=temperature)
        analysis = simulator.dc(Vinput=slice(-2, 5, .01))
        analyses[float(temperature)] = analysis

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

    #r# We plot the characteristic curve and compare it to the Shockley diode model:
    #r#
    #r# .. math::
    #r#
    #r#     I_d = I_s \left( e^{\frac{V_d}{n V_T}} - 1 \right)
    #r#
    #r# where :math:`V_T = \frac{k T}{q}`
    #r#
    #r# In order to scale the reverse biased region, we have to do some hack with Matplotlib.
    #r#
    silicon_forward_voltage_threshold = .7

    shockley_diode = ShockleyDiode(Is=4e-9, degree=25)

    def two_scales_tick_formatter(value, position):
        if value >= 0:
            return '{} mA'.format(value)
        else:
            return '{} nA'.format(value / 100)

    formatter = ticker.FuncFormatter(two_scales_tick_formatter)

    figure, (ax1, ax2) = plt.subplots(2, figsize=(20, 10))

    ax1.set_title('1N4148 Characteristic Curve ')
    ax1.set_xlabel('Voltage [V]')
    ax1.set_ylabel('Current')
    ax1.grid()
    ax1.set_xlim(-2, 2)
    ax1.axvspan(-2, 0, facecolor='green', alpha=.2)
    ax1.axvspan(0,
                silicon_forward_voltage_threshold,
                facecolor='blue',
                alpha=.1)
    ax1.axvspan(silicon_forward_voltage_threshold,
                2,
                facecolor='blue',
                alpha=.2)
    ax1.set_ylim(-500, 750)  # Fixme: round
    ax1.yaxis.set_major_formatter(formatter)
    Vd = analyses[25].out
    # compute scale for reverse and forward region
    forward_region = Vd >= 0 @ u_V
    reverse_region = np.invert(forward_region)
    scale = reverse_region * 1e11 + forward_region * 1e3
    #?# check temperature
    for temperature in temperatures:
        analysis = analyses[float(temperature)]
        ax1.plot(Vd, -analysis.Vinput * scale)
    ax1.plot(Vd, shockley_diode.I(Vd) * scale, 'black')
    ax1.legend(['@ {} °C'.format(temperature)
                for temperature in temperatures] +
               ['Shockley Diode Model Is = 4 nA'],
               loc=(.02, .8))
    ax1.axvline(x=0, color='black')
    ax1.axhline(y=0, color='black')
    ax1.axvline(x=silicon_forward_voltage_threshold, color='red')
    ax1.text(-1, -100, 'Reverse Biased Region', ha='center', va='center')
    ax1.text(1, -100, 'Forward Biased Region', ha='center', va='center')

    #r# Now we compute and plot the static and dynamic resistance.
    #r#
    #r# .. math::
    #r#
    #r#   \frac{d I_d}{d V_d} = \frac{1}{n V_T}(I_d + I_s)
    #r#
    #r# .. math::
    #r#
    #r#   r_d = \frac{d V_d}{d I_d} \approx \frac{n V_T}{I_d}

    ax2.set_title('Resistance @ 25 °C')
    ax2.grid()
    ax2.set_xlim(-2, 3)
    ax2.axvspan(-2, 0, facecolor='green', alpha=.2)
    ax2.axvspan(0,
                silicon_forward_voltage_threshold,
                facecolor='blue',
                alpha=.1)
    ax2.axvspan(silicon_forward_voltage_threshold,
                3,
                facecolor='blue',
                alpha=.2)
    analysis = analyses[25]
    static_resistance = -analysis.out / analysis.Vinput
    dynamic_resistance = np.diff(-analysis.out) / np.diff(analysis.Vinput)
    ax2.semilogy(analysis.out, static_resistance, basey=10)
    ax2.semilogy(analysis.out[10:-1], dynamic_resistance[10:], basey=10)
    ax2.axvline(x=0, color='black')
    ax2.axvline(x=silicon_forward_voltage_threshold, color='red')
    ax2.axhline(y=1, color='red')
    ax2.text(-1.5, 1.1, 'R limitation = 1 Ω', color='red')
    ax2.legend(['{} Resistance'.format(x) for x in ('Static', 'Dynamic')],
               loc=(.05, .2))
    ax2.set_xlabel('Voltage [V]')
    ax2.set_ylabel('Resistance [Ω]')

    plt.tight_layout()
    plt.show()