diff --git a/PySpice/Spice/BasicElement.py b/PySpice/Spice/BasicElement.py index ddc01b201..e4470d3d6 100644 --- a/PySpice/Spice/BasicElement.py +++ b/PySpice/Spice/BasicElement.py @@ -99,7 +99,8 @@ from ..Tools.StringTools import str_spice, join_list, join_dict from ..Unit import U_m, U_s, U_A, U_V, U_Degree, U_Ω, U_F, U_H, U_Hz -from .Netlist import (Element, AnyPinElement, FixedPinElement, NPinElement, OptionalPin) +from .Netlist import (Element, AnyPinElement, FixedPinElement, NPinElement, + OptionalPin, Pin, PinDefinition) from .ElementParameter import ( # KeyValueParameter, BoolKeyParameter, @@ -116,6 +117,8 @@ ModelPositionalParameter, ) +import SchemDraw as schem + #################################################################################################### class DipoleElement(FixedPinElement): @@ -153,12 +156,11 @@ class SubCircuitElement(NPinElement): ############################################## - def __init__(self, netlist, name, subcircuit_name, *nodes, **parameters): - - super().__init__(netlist, name, nodes, subcircuit_name) + def __init__(self, netlist, name, subcircuit_name, *nodes, **kwargs): + schematic_kwargs = kwargs.pop('schematic_kwargs', {}) # Fixme: match parameters to subcircuit - self.parameters = parameters + self.parameters = kwargs # Fixme: investigate # for key, value in parameters.items(): @@ -166,6 +168,14 @@ def __init__(self, netlist, name, subcircuit_name, *nodes, **parameters): # parameter.__set__(self, value) # self.optional_parameters[key] = parameter # setattr(self, key, parameter) + + subcircuit = netlist._subcircuits.get(subcircuit_name) + + self._pins = [Pin(self, PinDefinition(position, name=subcircuit.__pins__[position]), netlist.get_node(node, True)) + for position, node in enumerate(nodes)] + + super().__init__(netlist, name, nodes, subcircuit_name, + schematic_kwargs=schematic_kwargs) ############################################## @@ -239,6 +249,8 @@ class Resistor(DipoleElement): __alias__ = 'R' __prefix__ = 'R' + + schematic = schem.elements.RES resistance = FloatPositionalParameter(position=0, key_parameter=False, unit=U_Ω) ac = FloatKeyParameter('ac', unit=U_Ω) @@ -761,6 +773,8 @@ class VoltageSource(DipoleElement): __alias__ = 'V' __prefix__ = 'V' + + schematic = schem.elements.SOURCE_V # Fixme: ngspice manual doesn't describe well the syntax dc_value = FloatPositionalParameter(position=0, key_parameter=False, unit=U_V) diff --git a/PySpice/Spice/Netlist.py b/PySpice/Spice/Netlist.py index 462db633a..ba6bff4b2 100644 --- a/PySpice/Spice/Netlist.py +++ b/PySpice/Spice/Netlist.py @@ -82,7 +82,9 @@ def __init__(self, **kwargs): import logging import os -# import networkx +import networkx +import SchemDraw +import numpy as np #################################################################################################### @@ -337,14 +339,14 @@ class Resistor(metaclass=ElementParameterMetaClass): """ - #: Dictionary for SPICE prefix -> [cls,] + #: Dictionary for SPICE prefix -> [cls,] __classes__ = {} _logger = _module_logger.getChild('ElementParameterMetaClass') ############################################## - def __new__(meta_cls, class_name, base_classes, namespace): + def __new__(cls, class_name, base_classes, namespace): # __new__ is called for the creation of a class depending of this metaclass, i.e. at module loading # It customises the namespace of the new class @@ -428,15 +430,15 @@ def getter(self): else: _module_logger.debug("{} don't define a __pins__ attribute".format(class_name)) - return type.__new__(meta_cls, class_name, base_classes, namespace) + return type.__new__(cls, class_name, base_classes, namespace) ############################################## - def __init__(meta_cls, class_name, base_classes, namespace): + def __init__(cls, class_name, base_classes, namespace): # __init__ is called after the class is created (__new__) - type.__init__(meta_cls, class_name, base_classes, namespace) + type.__init__(cls, class_name, base_classes, namespace) # Collect basic element classes if '__prefix__' in namespace: @@ -444,9 +446,9 @@ def __init__(meta_cls, class_name, base_classes, namespace): if prefix is not None: classes = ElementParameterMetaClass.__classes__ if prefix in classes: - classes[prefix].append(meta_cls) + classes[prefix].append(cls) else: - classes[prefix] = [meta_cls] + classes[prefix] = [cls] ############################################## @@ -454,33 +456,37 @@ def __init__(meta_cls, class_name, base_classes, namespace): # e.g. Resistor.number_of_pins or Resistor.__class__.number_of_pins @property - def number_of_pins(cls): + def number_of_pins(self): #! Fixme: many pins ??? - number_of_pins = len(cls.__pins__) - if cls.__number_of_optional_pins__: - return slice(number_of_pins - cls.__number_of_optional_pins__, number_of_pins +1) + number_of_pins = len(self.__pins__) + if self.__number_of_optional_pins__: + return slice(number_of_pins - self.__number_of_optional_pins__, number_of_pins +1) else: return number_of_pins @property - def number_of_positional_parameters(cls): - return len(cls.__positional_parameters__) + def number_of_positional_parameters(self): + return len(self.__positional_parameters__) @property - def positional_parameters(cls): - return cls.__positional_parameters__ + def positional_parameters(self): + return self.__positional_parameters__ @property - def optional_parameters(cls): - return cls.__optional_parameters__ + def optional_parameters(self): + return self.__optional_parameters__ @property - def parameters_from_args(cls): - return cls.__parameters_from_args__ + def parameters_from_args(self): + return self.__parameters_from_args__ @property - def spice_to_parameters(cls): - return cls.__spice_to_parameters__ + def spice_to_parameters(self): + return self.__spice_to_parameters__ + +# @property +# def schematic(self): +# return self.__schematic__ #################################################################################################### @@ -501,6 +507,8 @@ class Element(metaclass=ElementParameterMetaClass): #: SPICE element prefix __prefix__ = None + + schematic = None ############################################## @@ -510,6 +518,7 @@ def __init__(self, netlist, name, *args, **kwargs): self._name = str(name) self.raw_spice = '' self.enabled = True + #self._pins = kwargs.pop('pins',()) # Process remaining args if len(self.__parameters_from_args__) < len(args): @@ -524,8 +533,10 @@ def __init__(self, netlist, name, *args, **kwargs): elif key in self.__positional_parameters__ or key in self.__optional_parameters__: setattr(self, key, value) - self._pins = () - netlist._add_element(self) + schematic_kwargs = kwargs.pop('schematic_kwargs', {}) + self.schematic_kwargs = schematic_kwargs + + netlist._add_element(self, **schematic_kwargs) ############################################## @@ -690,10 +701,13 @@ def __init__(self, netlist, name, *args, **kwargs): raise NameError("Node '{}' is missing for element {}".format(pin_definition.name, self.name)) pin_definition_nodes.append((pin_definition, node)) - super().__init__(netlist, name, *args, **kwargs) + self._pins = [Pin(self, pin_definition, netlist.get_node(node, True)) for pin_definition, node in pin_definition_nodes] + + + super().__init__(netlist, name, *args, **kwargs) ############################################## @@ -715,9 +729,6 @@ def __init__(self, netlist, name, nodes, *args, **kwargs): super().__init__(netlist, name, *args, **kwargs) - self._pins = [Pin(self, PinDefinition(position), netlist.get_node(node, True)) - for position, node in enumerate(nodes)] - ############################################## def copy_to(self, netlist): @@ -826,6 +837,8 @@ def __init__(self): self._ground_name = 0 self._nodes = {} + self._graph = networkx.Graph() + self._schematic = SchemDraw.Drawing() self._ground_node = self._add_node(self._ground_name) self._subcircuits = OrderedDict() # to keep the declaration order @@ -834,7 +847,6 @@ def __init__(self): self.raw_spice = '' - # self._graph = networkx.Graph() ############################################## @@ -890,6 +902,14 @@ def subcircuits(self): @property def subcircuit_names(self): return self._subcircuits.keys() + + @property + def graph(self): + return self._graph + + @property + def schematic(self): + return self._schematic ############################################## @@ -922,6 +942,10 @@ def _add_node(self, node_name): if node_name not in self._nodes: node = Node(self, node_name) self._nodes[node_name] = node + self._graph.add_node(node, name=node_name) + + #if(node_name == str(self._ground_name)): + # self.schematic.add(SchemDraw.elements.GND) return node else: raise ValueError("Node {} is already defined".format(node_name)) @@ -960,12 +984,43 @@ def has_ground_node(self): ############################################## - def _add_element(self, element): + def _add_element(self, element, **schematic_kwargs): """Add an element.""" - if element.name not in self._elements: self._elements[element.name] = element + + if len(element.nodes) == 2: + self.graph.add_edge(element.nodes[0], element.nodes[1], + x=element, name=element.name) + + #print(schematic_kwargs) + schematic = schematic_kwargs.pop('schematic', element.schematic) + if(schematic): + element.schematic = schematic + #label = schematic_kwargs.pop('label', element.name) + schematic_element = self.schematic.add(schematic, + **schematic_kwargs) + element.schematic_element = schematic_element + + show_start = schematic_kwargs.pop('show_start', False) + show_end = schematic_kwargs.pop('show_end', False) + + if(show_start): + start_label = schematic_kwargs.pop('start_label',{}) + + self.schematic.add(SchemDraw.elements.DOT_OPEN, + xy=schematic_element.start, + **start_label) + + if(show_end): + end_label = schematic_kwargs.pop('end_label',{}) + self.schematic.add(SchemDraw.elements.DOT_OPEN, + xy=schematic_element.end, + **end_label) + #if(element.pins[1].node == self.get_node(0, False)): + # self.schematic.add(SchemDraw.elements.GND) + else: raise NameError("Element name {} is already defined".format(element.name)) @@ -1138,6 +1193,7 @@ class SubCircuitFactory(SubCircuit): __name__ = None __nodes__ = None + __pins__ = None ############################################## diff --git a/PySpice/Spice/NgSpice/SimulationType.py b/PySpice/Spice/NgSpice/SimulationType.py index e5df5da74..b896aebb7 100644 --- a/PySpice/Spice/NgSpice/SimulationType.py +++ b/PySpice/Spice/NgSpice/SimulationType.py @@ -81,3 +81,4 @@ ) SIMULATION_TYPE[28] = SIMULATION_TYPE[27] +SIMULATION_TYPE[29] = SIMULATION_TYPE[28] diff --git a/examples/ctia_readout/ctia_readout.ipynb b/examples/ctia_readout/ctia_readout.ipynb new file mode 100644 index 000000000..c77ed304c --- /dev/null +++ b/examples/ctia_readout/ctia_readout.ipynb @@ -0,0 +1,3020 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.6/dist-packages/matplotlib/__init__.py:908: MatplotlibDeprecationWarning: The backend.qt4 rcParam was deprecated in version 2.2. In order to force the use of a specific Qt binding, either import that binding first, or set the QT_API environment variable.\n", + " mplDeprecation)\n", + "/usr/local/lib/python3.6/dist-packages/matplotlib/__init__.py:908: MatplotlibDeprecationWarning: The backend.qt4 rcParam was deprecated in version 2.2. In order to force the use of a specific Qt binding, either import that binding first, or set the QT_API environment variable.\n", + " mplDeprecation)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1;32m2018-11-26 18:08:39,871\u001b[0m - \u001b[1;34mPySpice.Doc.ExampleTools.find_libraries\u001b[0m - \u001b[1;31mINFO\u001b[0m - SPICE library path is ~/Projects/ROIC/src/PySpice/examples/libraries\n" + ] + } + ], + "source": [ + "%matplotlib inline\n", + "%config InlineBackend.figure_format = 'svg'\n", + "####################################################################################################\n", + "\n", + "import os\n", + "\n", + "import numpy as np\n", + "import pylab as pb\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.ticker as ticker\n", + "import networkx as nx\n", + "import SchemDraw as schem\n", + "\n", + "####################################################################################################\n", + "import PySpice\n", + "import PySpice.Logging.Logging as Logging\n", + "logger = Logging.setup_logging()\n", + "\n", + "####################################################################################################\n", + "\n", + "\n", + "from PySpice.Doc.ExampleTools import find_libraries\n", + "from PySpice.Spice.Netlist import Circuit\n", + "from PySpice.Spice.Library import SpiceLibrary\n", + "from PySpice.Unit import *\n", + "from PySpice.Physics.SemiConductor import ShockleyDiode\n", + "from PySpice.Spice.Netlist import SubCircuitFactory\n", + "\n", + "os.environ['PySpiceLibraryPath'] = '~/Projects/ROIC/src/PySpice/examples/libraries'\n", + "\n", + "####################################################################################################\n", + "\n", + "libraries_path = find_libraries()\n", + "spice_library = SpiceLibrary(libraries_path)\n", + "####################################################################################################" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from math import pi\n", + "#cgs units\n", + "cm = 1.0\n", + "m = 100.0\n", + "mum = 1e-6*m\n", + "nm = 1e-9*m\n", + "g = 1.0\n", + "kg = 1000.0*g\n", + "\n", + "s = 1.0\n", + "ms = 1e-3*s\n", + "ns = 1e-9*s\n", + "mus = 1e-6*s\n", + "\n", + "Hertz = Hz = 1.0/s\n", + "\n", + "erg = g*cm**2/s**2\n", + "Joule = kg*m**2/s**2\n", + "\n", + "Watt = Joule/s\n", + "mW = 1e-3*Watt\n", + "\n", + "Coulomb = 1.0\n", + "Ampere = Coulomb/s\n", + "mA = 1e-3*Ampere\n", + "nA = 1e-9*Ampere\n", + "Kelvin = 1.0\n", + "\n", + "eps0 = 8.854187817620e-12*Ampere**2*s**4/kg/m**3\n", + "h_planck = 6.62606885e-27*erg*s\n", + "hbar_planck = h_planck/2.0/pi\n", + "q_e = 1.6021766208e-19*Coulomb\n", + "k_b = 1.38064852e-16*erg/Kelvin\n", + "\n", + "eV =q_e*Joule/Coulomb\n", + "Volt = Joule/Coulomb\n", + "mV = 1e-3*Volt\n", + "\n", + "Ohm = Volt/Ampere\n", + "kOhm = 1e3*Ohm\n", + "MOhm = 1e6*Ohm \n", + "\n", + "Farad = Coulomb/Volt\n", + "uF = 1e-6*Farad\n", + "nF = 1e-9*Farad\n", + "pF = 1e-12*Farad" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "PySpice.__file__" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "class BasicOperationalAmplifier(SubCircuitFactory):\n", + "\n", + " __name__ = 'BasicOperationalAmplifier'\n", + " __nodes__ = ('non_inverting_input', 'inverting_input', 'output')\n", + " __pins__ = ('plus', 'minus', 'out')\n", + "\n", + "\n", + " def __init__(self):\n", + "\n", + " super().__init__()\n", + "\n", + " # Input impedance\n", + " RIN = self.R('input', 'non_inverting_input', 'inverting_input', 10@u_MΩ,\n", + " schematic_kwargs={'schematic': schem.elements.RES,\n", + " 'label': r'$R_{in}$', 'd': 'up',\n", + " 'show_start': True, 'start_label': {'lftlabel': r'$v_+$'},\n", + " 'show_end': True, 'end_label': {'lftlabel': r'$v_-$'},\n", + " }\n", + " )\n", + " self.RIN = RIN\n", + " #self._schematic.add(schem.elements.RES,label=r'$R_in$')\n", + "\n", + " # dc gain=100k and pole1=100hz\n", + " # unity gain = dcgain x pole1 = 10MHZ\n", + " self.schematic.add(schem.elements.LINE, d ='right', l=1.0)\n", + " vcvs_in = self.VCVS('gain', 1, self.gnd, 'non_inverting_input', 'inverting_input', voltage_gain=kilo(100),\n", + " schematic_kwargs={'schematic': schem.elements.SOURCE_CONT_V,\n", + " 'anchor':'in1',#'d':'right',\n", + " 'show_end': True, 'end_label': {'toplabel': r'$v_1 = A(v_+ - v_-)$'},\n", + " #'rgtlabel': r'$A(v_+ - v_-)$',\n", + " #'l': RIN.schematic_element.dy,\n", + " })\n", + " self.vcvs_in = vcvs_in\n", + " self.schematic.add(schem.elements.GND, xy=vcvs_in.schematic_element.start)\n", + " self.schematic.add(schem.elements.DOT_OPEN, xy=vcvs_in.schematic_element.in2, rgtlabel=r'$v_+$')\n", + " \n", + " #self.schematic.add(schem.elements.LINE, xy=vcvs_in.schematic_element.end, d='right', l=1.5)\n", + " RP1 = self.R('P1', 1, 2, 1@u_kΩ,\n", + " schematic_kwargs={'schematic': schem.elements.RES,\n", + " 'd':'right',\n", + " 'xy': vcvs_in.schematic_element.end,\n", + " 'botlabel': r'$RP1$',\n", + " 'l':5.5\n", + " })\n", + " CP1 = self.C('P1', 2, self.gnd, 1.5915@u_uF, \n", + " schematic_kwargs={'schematic': schem.elements.CAP,\n", + " 'd':'down',\n", + " 'botlabel': r'$CP1$',\n", + " 'show_start': True, 'start_label': {'toplabel': r'$v_2$'},\n", + " })\n", + " self.schematic.add(schem.elements.GND, xy=CP1.schematic_element.end)\n", + "\n", + " # Output buffer and resistance\n", + " self.schematic.add(schem.elements.LINE, xy=CP1.schematic_element.start, d='right', l=2.0)\n", + " vcvs_out = self.VCVS('buffer', 3, self.gnd, 2, self.gnd, 1,\n", + " schematic_kwargs={'schematic': schem.elements.SOURCE_CONT_V,\n", + " 'anchor':'in1',#'d':'right',\n", + " 'show_end': True, 'end_label': {'toplabel': r'$v_3 = v_2$'}}\n", + " )\n", + " self.vcvs_out = vcvs_out\n", + " self.schematic.add(schem.elements.GND, xy=vcvs_out.schematic_element.start)\n", + " self.schematic.add(schem.elements.GND, xy=vcvs_out.schematic_element.in2)\n", + " \n", + " \n", + " ROUT = self.R('out', 3, 'output', 10@u_Ω,\n", + " schematic_kwargs={'schematic': schem.elements.RES,\n", + " 'label': r'$R_{out}$', 'd': 'right',\n", + " 'show_end': True, 'end_label': {'rgtlabel': r'$v_{o}$'},\n", + " 'l': 3.5\n", + " }\n", + " )\n", + " self.ROUT = ROUT\n", + " \n", + "opamp = BasicOperationalAmplifier()\n", + "opamp.schematic.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#r# For this purpose, we use the common high-speed diode 1N4148. The diode is driven by a variable\n", + "#r# voltage source through a limiting current resistance.\n", + "\n", + "#f# circuit_macros('diode-characteristic-curve-circuit.m4')\n", + "\n", + "circuit = Circuit('Capacitive Transimpedance Amplifier (CTIA) readout')\n", + "\n", + "#circuit.include(spice_library['1N4148'])\n", + "\n", + "\n", + "DD = circuit.D('sensor', 'anode', 'Vd',\n", + " schematic_kwargs={'schematic': schem.elements.PHOTODIODE, \n", + " 'd': 'left', 'show_end': True, 'end_label': {'lftlabel': r'$V_d$'},\n", + " 'flip': True,\n", + " 'botlabel': r'$D_d$'\n", + " }\n", + " )\n", + "#circuit.schematic.add(schem.elements.LINE, xy=DD.schematic_element.start, d ='down', l=1.5)\n", + "#CD = circuit.C('d', 'anode', 'Vd', 1@u_uF,\n", + "# schematic_kwargs={'schematic': schem.elements.CAP, 'botlabel': r'$C_d$',\n", + "# 'd': 'left', 'l': DD.schematic_element.dx}\n", + "# )\n", + "#circuit.schematic.add(schem.elements.LINE, xy=CD.schematic_element.end, to=DD.schematic_element.end)\n", + "\n", + "circuit.subcircuit(opamp)\n", + "seg = circuit.schematic.add(schem.elements.LINE, xy=DD.schematic_element.start, d ='right', l=2.0)\n", + "circuit.schematic.labelI(seg, arrowlen=1.0, reverse=False, arrowofst=0.5,\n", + " label=r'$i_S(t)$', top=True)\n", + "\n", + "XA = circuit.X('A', 'BasicOperationalAmplifier', 'Vcom', 'anode', 'Aout',\n", + " schematic_kwargs={'schematic': schem.elements.OPAMP, 'anchor': 'in1', \n", + " 'd': 'right', 'flip':False,\n", + " #'xy': CD.schematic_element.start\n", + " })\n", + "circuit.schematic.add(schem.elements.DOT, lftlabel =r'$V_{com}$', xy=XA.schematic_element.in2)\n", + "\n", + "circuit.schematic.add(schem.elements.LINE, xy=XA.schematic_element.in1, d ='up', l=2.0)\n", + "CINT = circuit.C('int', 'anode', 'Aout', 1@u_uF,\n", + " schematic_kwargs={'schematic': schem.elements.CAP, 'toplabel': r'$C_{int}$',\n", + " 'd': 'right', 'l': XA.schematic_element.dx}\n", + " )\n", + "circuit.schematic.add(schem.elements.LINE, xy=XA.schematic_element.out, d ='up', \n", + " to=CINT.schematic_element.end)\n", + "\n", + "\n", + "circuit.schematic.add(schem.elements.LINE, xy=CINT.schematic_element.start, d ='up', l=2.0)\n", + "RF = circuit.R('F', 'anode', 'Aout', 1@u_MOhm,\n", + " schematic_kwargs={'schematic': schem.elements.RES, 'toplabel': r'$R_F$',\n", + " 'd': 'right', 'l': XA.schematic_element.dx}\n", + " )\n", + "circuit.schematic.add(schem.elements.LINE, xy=CINT.schematic_element.end, d ='up', l=2.0)\n", + "\n", + "circuit.schematic.add(schem.elements.LINE, xy=XA.schematic_element.out, d ='right', l=2.0)\n", + "circuit.schematic.add(schem.elements.DOT_OPEN, label =r'$v_S(t)$')\n", + "\n", + "circuit.schematic.draw()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\\begin{gather}\n", + "v_C(t) \\equiv V_{com}-v_S(t) = V_C + \\frac{1}{C_{int}}\\int_0^{\\tau_{int}}{i_C(t)dt} \\\\\n", + "i_C = i_S - (V_{com}-v_S)/R_F\n", + "\\end{gather}\n", + "\n", + "\\begin{align}\n", + "v_S &= V_{com}-V_C-\\frac{1}{C_{int}}\\int_0^{\\tau_{int}}{i_C(t)dt} \\\\\n", + "&= V_{com}-V_C-\\frac{1}{C_{int}}\\int_0^{\\tau_{int}}{i_S(t)dt} + \\frac{1}{C_{int}}\\int_0^{\\tau_{int}}{\\frac{V_{com}-v_S}{R_F}dt} \\\\\n", + "&= V_{com}-V_C-\\frac{1}{C_{int}}\\int_0^{\\tau_{int}}{i_S(t)dt} + \\frac{V_{com}\\tau_{int}}{R_FC_{int}}\n", + "-\\frac{1}{R_FC_{int}}\\int_0^{\\tau_{int}}{v_S(t)dt}\n", + "\\end{align}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Thus the signal voltage $v_S$ is defined by the differential equation,\n", + "\n", + "\\begin{equation}\n", + "\\frac{dv_S}{dt} + \\frac{v_S}{R_FC_{int}} + \\frac{i_S}{C_{int}} = 0\n", + "\\end{equation}\n", + "\n", + "which can be solved as,\n", + "\n", + "\\begin{gather}\n", + "\\mu = e^{\\frac{t}{R_FC_{int}}} \\\\\n", + "\\mu\\left[v_S^\\prime + \\frac{v_S}{R_FC_{int}}\\right] + \\frac{\\mu i_S}{C_{int}} \\\\\n", + "(\\mu v_S)^\\prime = \\mu v_S^\\prime + \\mu^\\prime v_S \\\\\n", + "\\mu^\\prime = \\frac{\\mu}{R_FC_{int}} \\\\\n", + "(\\mu v_S)^\\prime + \\frac{\\mu i_S}{C_{int}} = 0 \\\\\n", + "v_S(\\tau_{int}) = v_S(0) -\\frac{e^{\\frac{-\\tau_{int}}{R_FC_{int}}}}{R_FC_{int}} \\int_0^{\\tau_{int}}{e^{\\frac{t}{R_FC_{int}}} R_F i_S dt}\\\\\n", + "v_S(\\tau_{int}) = v_S(0) -\\frac{1}{R_FC_{int}} \\int_0^{\\tau_{int}}{e^{\\frac{t-\\tau_{int}}{R_FC_{int}}} R_F i_S dt}\\\\\n", + "v_S(\\infty) \\equiv R_F i_S(\\infty) \\\\\n", + "\\lim_{\\tau_{int}\\to\\infty}\\int_0^{\\tau_{int}}{e^{\\frac{t-\\tau_{int}}{R_FC_{int}}} R_F i_S dt} = R_F C_{int} \\left[ v_S(0)-v_S(\\infty) \\right]\n", + "\\end{gather}" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def i_S(t):\n", + " t_off = np.argwhere(np.logical_or(t>i_S.t1, t<=i_S.t0))\n", + " t_on = np.argwhere(np.logical_and(t<=i_S.t1, t>i_S.t0))\n", + " i = np.zeros_like(t)\n", + " i[t_on] = i_S.val #i_S.tramp*t[t_pos]\n", + " \n", + " return i\n", + "\n", + "\n", + "R_F = 1.0*MOhm\n", + "C_INT = 0.1*nF\n", + "rc_delay = R_F*C_INT\n", + "\n", + "i_S.val = -100.0*nA\n", + "i_S.t0 = 0.0\n", + "i_S.t1 = 0.5*rc_delay\n", + "i_S.tramp = 0.1*mA/mus\n", + "\n", + "def v_S(tau_int, RF=R_F, CINT=C_INT, v0=0.0*Volt):\n", + " \n", + " v = np.zeros_like(tau_int)\n", + " for j, tau in enumerate(tau_int):\n", + " t = np.linspace(0,tau, 500)\n", + " i = i_S(t)\n", + " f = np.exp((t-tau)/RF/CINT)*RF*i\n", + " I = np.trapz(f,x=t)\n", + " v[j] = v0 - I/RF/CINT\n", + " \n", + " return v\n", + "\n", + "\n", + "t = np.linspace(0, 4.0*rc_delay,100)\n", + "\n", + "pb.plot(t/rc_delay, i_S(t)/nA, ls='--', c='b')\n", + "ax1 = pb.gca()\n", + "ax2 = pb.twinx(ax1)\n", + "tau_int = np.linspace(0.0, 4.0*rc_delay, 100)\n", + "pb.plot(tau_int/rc_delay, v_S(tau_int)/mV, c='b')\n", + "i_S.val = -200.0*nA\n", + "i_S.tramp = 0.2*mA/mus\n", + "ax1.plot(t/rc_delay, i_S(t)/nA, ls='--', c='r')\n", + "ax2.plot(tau_int/rc_delay, v_S(tau_int)/mV, c='r')\n", + "ax2.axvline(rc_delay/rc_delay, c='k', ls='--')\n", + "\n", + "ax1.set_xlabel('Time ($RC$)')\n", + "ax1.set_ylabel('$i_S$ ($nA$)')\n", + "ax2.set_ylabel('$v_S$ ($mV$)')\n", + "ax2.set_yscale('linear')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.trapz?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/diode/diode-characteristic-curve.ipynb b/examples/diode/diode-characteristic-curve.ipynb new file mode 100644 index 000000000..9c0758bc5 --- /dev/null +++ b/examples/diode/diode-characteristic-curve.ipynb @@ -0,0 +1,2292 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "%config InlineBackend.figure_format = 'svg'\n", + "####################################################################################################\n", + "\n", + "import os\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.ticker as ticker\n", + "import networkx as nx\n", + "import SchemDraw as schem\n", + "\n", + "####################################################################################################\n", + "\n", + "import PySpice.Logging.Logging as Logging\n", + "logger = Logging.setup_logging()\n", + "\n", + "####################################################################################################\n", + "\n", + "from PySpice.Doc.ExampleTools import find_libraries\n", + "from PySpice.Spice.Netlist import Circuit\n", + "from PySpice.Spice.Library import SpiceLibrary\n", + "from PySpice.Unit import *\n", + "from PySpice.Physics.SemiConductor import ShockleyDiode\n", + "\n", + "os.environ['PySpiceLibraryPath'] = '~/Projects/ROIC/src/PySpice/examples/libraries'\n", + "\n", + "####################################################################################################\n", + "\n", + "libraries_path = find_libraries()\n", + "spice_library = SpiceLibrary(libraries_path)\n", + "####################################################################################################" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#r# For this purpose, we use the common high-speed diode 1N4148. The diode is driven by a variable\n", + "#r# voltage source through a limiting current resistance.\n", + "\n", + "#f# circuit_macros('diode-characteristic-curve-circuit.m4')\n", + "\n", + "circuit = Circuit('Diode Characteristic Curve')\n", + "\n", + "circuit.include(spice_library['1N4148'])\n", + "\n", + "circuit.schematic.add(schem.elements.GND)\n", + "V =circuit.V('input', 'Vin', circuit.gnd, 10@u_V,\n", + " schematic_kwargs={'show_plus': True}\n", + " )\n", + "R = circuit.R('1', 'Vin', 'Vout', 1@u_Ω,\n", + " schematic_kwargs={'d':'right', 'show_minus': True}\n", + " ) # not required for simulation\n", + "X = circuit.X('D1', '1N4148', 'Vout', circuit.gnd,\n", + " schematic_kwargs={'schematic': schem.elements.DIODE, 'd':'down'},\n", + " )\n", + "circuit.schematic.add(schem.elements.GND)\n", + "circuit.schematic.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "#pos = nx.spectral_layout(circuit.graph)\n", + "#nx.draw(circuit.graph, pos=pos, with_labels=True, node_size=1200, node_shape='s',\n", + "# width=2.0)\n", + "#edge_labels = nx.get_edge_attributes(circuit.graph,'name')\n", + "#nx.draw_networkx_edge_labels(circuit.graph, pos, edge_labels=edge_labels)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "#r# We simulate the circuit at these temperatures: 0, 25 and 100 °C.\n", + "\n", + "# Fixme: Xyce ???\n", + "temperatures = [0, 25, 100]@u_Degree\n", + "analyses = {}\n", + "for temperature in temperatures:\n", + " simulator = circuit.simulator(temperature=temperature, nominal_temperature=temperature)\n", + " analysis = simulator.dc(Vinput=slice(-2, 5, .01))\n", + " analyses[float(temperature)] = analysis\n", + "\n", + "####################################################################################################" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(1,-100,'Forward Biased Region')" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#r# We plot the characteristic curve and compare it to the Shockley diode model:\n", + "#r#\n", + "#r# .. math::\n", + "#r#\n", + "#r# I_d = I_s \\left( e^{\\frac{V_d}{n V_T}} - 1 \\right)\n", + "#r#\n", + "#r# where :math:`V_T = \\frac{k T}{q}`\n", + "#r#\n", + "#r# In order to scale the reverse biased region, we have to do some hack with Matplotlib.\n", + "#r#\n", + "\n", + "silicon_forward_voltage_threshold = .7\n", + "\n", + "shockley_diode = ShockleyDiode(Is=4.0@u_nA, degree=25)\n", + "\n", + "def two_scales_tick_formatter(value, position):\n", + " if value >= 0:\n", + " return '{} mA'.format(value)\n", + " else:\n", + " return '{} nA'.format(value/100)\n", + "formatter = ticker.FuncFormatter(two_scales_tick_formatter)\n", + "\n", + "figure = plt.figure(1, (10, 5))\n", + "\n", + "axe = plt.subplot(121)\n", + "axe.set_title('1N4148 Characteristic Curve ')\n", + "axe.set_xlabel('Voltage [V]')\n", + "axe.set_ylabel('Current')\n", + "axe.grid()\n", + "axe.set_xlim(-2, 2)\n", + "axe.axvspan(-2, 0, facecolor='green', alpha=.2)\n", + "axe.axvspan(0, silicon_forward_voltage_threshold, facecolor='blue', alpha=.1)\n", + "axe.axvspan(silicon_forward_voltage_threshold, 2, facecolor='blue', alpha=.2)\n", + "#axe.set_ylim(-500, 750) # Fixme: round\n", + "#axe.yaxis.set_major_formatter(formatter)\n", + "Vd = analyses[25].Vout\n", + "# compute scale for reverse and forward region\n", + "forward_region = Vd >= 0@u_V\n", + "reverse_region = np.invert(forward_region)\n", + "scale = reverse_region*1e11 + forward_region*1e3\n", + "#?# check temperature\n", + "for temperature in temperatures:\n", + " analysis = analyses[float(temperature)]\n", + " axe.plot(Vd, np.abs(- analysis.Vinput))\n", + "axe.plot(Vd, np.abs(shockley_diode.I(Vd)), 'black')\n", + "axe.set_ylim(1e-9, 1e3)\n", + "axe.set_yscale('log')\n", + "axe.legend(['@ {}'.format(temperature)\n", + " for temperature in temperatures] + ['Shockley Diode Model Is = 4 nA'],\n", + " loc=2, fontsize=10)\n", + "axe.axvline(x=0, color='black')\n", + "axe.axhline(y=0, color='black')\n", + "axe.axvline(x=silicon_forward_voltage_threshold, color='red')\n", + "axe.text(-1, -100, 'Reverse Biased Region', ha='center', va='center')\n", + "axe.text( 1, -100, 'Forward Biased Region', ha='center', va='center')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/setup.py b/setup.py index 7c518ba0b..80ea122f7 100755 --- a/setup.py +++ b/setup.py @@ -48,8 +48,8 @@ #################################################################################################### -exec(compile(open('setup_data.py').read(), 'setup_data.py', 'exec')) - +#exec(compile(open('setup_data.py').read(), 'setup_data.py', 'exec')) +from setup_data import setup_dict #################################################################################################### setup_dict.update(dict( @@ -83,6 +83,8 @@ 'numpy', 'ply', 'scipy', + 'networkx', + 'SchemDraw' ], ))