####################################################################################################
#
# PySpice - A Spice Package for Python
# Copyright (C) 2014 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
"""This module implements SPICE circuit elements.
.. warning:: Some elements are partially implemented.
.. warning:: The API documentation generated by Sphinx is perfectible for this module. The source
code can be more informative.
.. note:: It would be nice to have a useful and working documentation in the interactive environment.
The element's parameters are internally implemented using class attributes and descriptors.
There are two types of parameters, positionals which are required and where the order mater, and
optional parameters which are passed as keyword arguments.
Parameters are registered with more expressive and longer names than their Spice counterparts. For
optional parameters, we can use both Spice and longer name for convenience.
See Ngspice documentation for details.
+--------------+------------------------------------------------------+
| First letter + Element description |
+--------------+------------------------------------------------------+
| A + XSPICE code model |
+--------------+------------------------------------------------------+
| B + Behavioral (arbitrary) source |
+--------------+------------------------------------------------------+
| C + Capacitor |
+--------------+------------------------------------------------------+
| D + Diode |
+--------------+------------------------------------------------------+
| E + Voltage-controlled voltage source (VCVS) |
+--------------+------------------------------------------------------+
| F + Current-controlled current source (CCCs) |
+--------------+------------------------------------------------------+
| G + Voltage-controlled current source (VCCS) |
+--------------+------------------------------------------------------+
| H + Current-controlled voltage source (CCVS) |
+--------------+------------------------------------------------------+
| I + Current source |
+--------------+------------------------------------------------------+
| J + Junction field effect transistor (JFET) |
+--------------+------------------------------------------------------+
| K + Coupled (Mutual) Inductors |
+--------------+------------------------------------------------------+
| L + Inductor |
+--------------+------------------------------------------------------+
| M + Metal oxide field effect transistor (MOSFET) |
+--------------+------------------------------------------------------+
| N + Numerical device for GSS |
+--------------+------------------------------------------------------+
| O + Lossy transmission line |
+--------------+------------------------------------------------------+
| P + Coupled multiconductor line (CPL) |
+--------------+------------------------------------------------------+
| Q + Bipolar junction transistor (BJT) |
+--------------+------------------------------------------------------+
| R + Resistor |
+--------------+------------------------------------------------------+
| S + Switch (voltage-controlled) |
+--------------+------------------------------------------------------+
| T + Lossless transmission line |
+--------------+------------------------------------------------------+
| U + Uniformly distributed RC line |
+--------------+------------------------------------------------------+
| V + Voltage source |
+--------------+------------------------------------------------------+
| W + Switch (current-controlled) |
+--------------+------------------------------------------------------+
| X + Subcircuit |
+--------------+------------------------------------------------------+
| Y + Single lossy transmission line (TXL) |
+--------------+------------------------------------------------------+
| Z + Metal semiconductor field effect transistor (MESFET) |
+--------------+------------------------------------------------------+
"""
####################################################################################################
import logging
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 .Element import (
AnyPinElement,
FixedPinElement,
NPinElement,
OptionalPin,
DipoleElement,
TwoPortElement,
)
from .ElementParameter import (
# KeyValueParameter,
BoolKeyParameter,
ElementNamePositionalParameter,
ExpressionKeyParameter,
ExpressionPositionalParameter,
FlagParameter,
FloatKeyParameter,
FloatPairKeyParameter,
FloatTripletKeyParameter,
FloatPositionalParameter,
InitialStatePositionalParameter,
IntKeyParameter,
ModelPositionalParameter,
)
####################################################################################################
_module_logger = logging.getLogger(__name__)
####################################################################################################
[docs]class SubCircuitElement(NPinElement):
"""This class implements a sub-circuit.
Spice syntax:
.. code-block:: none
XYYYYYY node1 node2 ... subcircuit_name parameter1=value1 ...
Attributes:
:attr:`subcircuit_name`
.. note:: As opposite to Spice, the circuit's name is specified before the nodes so as to act as `*args`.
"""
ALIAS = 'X'
PREFIX = 'X'
subcircuit_name = ElementNamePositionalParameter(position=0, key_parameter=False)
##############################################
def __init__(self, netlist, name, subcircuit_name, *nodes, **parameters):
super().__init__(netlist, name, nodes, subcircuit_name)
# Fixme: match parameters to subcircuit
self.parameters = parameters
# Fixme: investigate
# for key, value in parameters.items():
# parameter = KeyValueParameter(key)
# parameter.__set__(self, value)
# self.optional_parameters[key] = parameter
# setattr(self, key, parameter)
##############################################
[docs] def copy_to(self, netlist):
element = self.__class__(netlist, self._name, self.subcircuit_name, *self.node_names, **self.parameters)
# Element.copy_to(self, element)
return element
##############################################
####################################################################################################
#
# Elementary devices: Resistor, Capacitor, Inductor, Switch (VCSw/CCSw)
#
####################################################################################################
[docs]class Resistor(DipoleElement):
"""This class implements a resistor.
Spice syntax:
.. code-block:: none
RXXXXXXX n+ n- value <ac=val> <m=val> <scale=val> <temp=val> <dtemp=val> <noisy=0|1>
Keyword Parameters:
:attr:`ac`
:attr:`multiplier`
alias `m`
:attr:`scale`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
:attr:`noisy`
Attributes:
:attr:`resistance`
:attr:`ac`
:attr:`multiplier`
:attr:`scale`
:attr:`temperature`
:attr:`device_temperature`
:attr:`noisy`
"""
ALIAS = 'R'
PREFIX = 'R'
resistance = FloatPositionalParameter(position=0, key_parameter=False, unit=U_Ω)
ac = FloatKeyParameter('ac', unit=U_Ω)
multiplier = IntKeyParameter('m')
scale = FloatKeyParameter('scale')
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
noisy = BoolKeyParameter('noisy')
####################################################################################################
[docs]class SemiconductorResistor(DipoleElement):
"""This class implements a Semiconductor resistor.
Spice syntax:
.. code-block:: none
RXXXXXXX n+ n- <value> <mname> <l=length> <w=width> <temp=val> <dtemp=val> m=<val> <ac=val> <scale=val> <noisy=0|1>
Keyword Parameters:
:attr:`model`
:attr:`length`
alias `l`
:attr:`width`
alias `w`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
:attr:`multiplier`
alias `m`
:attr:`ac`
:attr:`scale`
:attr:`noisy`
Attributes:
:attr:`resistance`
:attr:`model`
:attr:`length`
:attr:`width`
:attr:`temperature`
:attr:`device_temperature`
:attr:`multiplier`
:attr:`ac`
:attr:`scale`
:attr:`noisy`
"""
ALIAS = 'SemiconductorResistor'
PREFIX = 'R'
resistance = FloatPositionalParameter(position=0, key_parameter=False, unit=U_Ω)
model = ModelPositionalParameter(position=1, key_parameter=True)
length = FloatKeyParameter('l', unit=U_m)
width = FloatKeyParameter('w', unit=U_m)
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
multiplier = IntKeyParameter('m')
ac = FloatKeyParameter('ac', unit=U_Ω)
scale = FloatKeyParameter('scale')
noisy = BoolKeyParameter('noisy')
####################################################################################################
[docs]class BehavioralResistor(DipoleElement):
# Behavioral / Behavioural
"""This class implements a behavioral resistor.
Spice syntax:
.. code-block:: none
RXXXXXXX n+ n- 'expression' <tc1=value> <tc2=value>
Rxxxxxxx n+ n- R='expression' <tc1=value> <tc2=value>
Keyword Parameters:
:attr:`tc1`
:attr:`tc2`
Attributes:
:attr:`resistance_expression`
:attr:`tc1`
:attr:`tc2`
"""
ALIAS = 'BehavioralResistor'
PREFIX = 'R'
resistance_expression = ExpressionPositionalParameter(position=0, key_parameter=False)
tc1 = FloatKeyParameter('tc1')
tc2 = FloatKeyParameter('tc2')
####################################################################################################
[docs]class Capacitor(DipoleElement):
"""This class implements a capacitor.
Spice syntax:
.. code-block:: none
CXXXXXXX n+ n- <value> <mname> <m=val> <scale=val> <temp=val> <dtemp=val> <ic=init_condition>
Keyword Parameters:
:attr:`model`
:attr:`multiplier`
alias `m`
:attr:`scale`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
:attr:`initial_condition`
alias `ic`
Attributes:
:attr:`capacitance`
:attr:`model`
:attr:`multiplier`
:attr:`scale`
:attr:`temperature`
:attr:`device_temperature`
:attr:`initial_condition`
"""
ALIAS = 'C'
PREFIX = 'C'
capacitance = FloatPositionalParameter(position=0, key_parameter=False, unit=U_F)
model = ModelPositionalParameter(position=1, key_parameter=True)
multiplier = IntKeyParameter('m')
scale = FloatKeyParameter('scale')
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
initial_condition = FloatKeyParameter('ic')
####################################################################################################
[docs]class SemiconductorCapacitor(DipoleElement):
"""This class implements a semiconductor capacitor.
Spice syntax:
.. code-block:: none
CXXXXXXX n+ n- <value> <mname> <l=length> <w=width> <m=val> <scale=val> <temp=val> <dtemp=val> <ic=init_condition>
Keyword Parameters:
:attr:`model`
:attr:`length`
alias `l`
:attr:`width`
alias `w`
:attr:`multiplier`
alias `m`
:attr:`scale`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
:attr:`initial_condition`
alias `ic`
Attributes:
:attr:`capacitance`
:attr:`model`
:attr:`length`
:attr:`width`
:attr:`multiplier`
:attr:`scale`
:attr:`temperature`
:attr:`device_temperature`
:attr:`initial_condition`
"""
ALIAS = 'SemiconductorCapacitor'
PREFIX = 'C'
capacitance = FloatPositionalParameter(position=0, key_parameter=False, unit=U_F)
model = ModelPositionalParameter(position=1, key_parameter=True)
length = FloatKeyParameter('l', unit=U_m)
width = FloatKeyParameter('w', unit=U_m)
multiplier = IntKeyParameter('m')
scale = FloatKeyParameter('scale')
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
initial_condition = FloatKeyParameter('ic')
####################################################################################################
[docs]class BehavioralCapacitor(DipoleElement):
"""This class implements a behavioral capacitor.
Spice syntax:
.. code-block:: none
CXXXXXXX n+ n- 'expression' <tc1=value> <tc2=value>
CXXXXXXX n+ n- C='expression' <tc1=value> <tc2=value>
Keyword Parameters:
:attr:`tc1`
:attr:`tc2`
Attributes:
:attr:`capacitance_expression`
:attr:`tc1`
:attr:`tc2`
"""
ALIAS = 'BehavioralCapacitor'
PREFIX = 'C'
capacitance_expression = ExpressionPositionalParameter(position=0, key_parameter=False)
tc1 = FloatKeyParameter('tc1')
tc2 = FloatKeyParameter('tc2')
####################################################################################################
[docs]class Inductor(DipoleElement):
"""This class implements an inductor.
Spice syntax:
.. code-block:: none
LYYYYYYY n+ n- <value> <mname> <nt=val> <m=val> <scale=val> <temp=val> <dtemp=val> <ic=init_condition>
Keyword Parameters:
:attr:`nt`
:attr:`multiplier`
alias `m`
:attr:`scale`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
:attr:`initial_condition`
alias `ic`
Attributes:
:attr:`inductance`
:attr:`model`
:attr:`nt`
:attr:`multiplier`
:attr:`scale`
:attr:`temperature`
:attr:`device_temperature`
:attr:`initial_condition`
"""
ALIAS = 'L'
PREFIX = 'L'
inductance = FloatPositionalParameter(position=0, key_parameter=False, unit=U_H)
model = ModelPositionalParameter(position=1, key_parameter=True)
nt = FloatKeyParameter('nt')
multiplier = IntKeyParameter('m')
scale = FloatKeyParameter('scale')
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
initial_condition = FloatKeyParameter('ic')
####################################################################################################
[docs]class BehavioralInductor(DipoleElement):
"""This class implements a behavioral inductor.
Spice syntax:
.. code-block:: none
LXXXXXXX n+ n- 'expression' <tc1=value> <tc2=value>
LXXXXXXX n+ n- L='expression' <tc1=value> <tc2=value>
Keyword Parameters:
:attr:`tc1`
:attr:`tc2`
Attributes:
:attr:`inductance_expression`
:attr:`tc1`
:attr:`tc2`
"""
ALIAS = 'BehavioralInductor'
PREFIX = 'L'
inductance_expression = ExpressionPositionalParameter(position=0, key_parameter=False)
tc1 = FloatKeyParameter('tc1')
tc2 = FloatKeyParameter('tc2')
####################################################################################################
[docs]class CoupledInductor(AnyPinElement):
"""This class implementss a coupled (mutual) inductors.
Spice syntax:
.. code-block:: none
KXXXXXXX LYYYYYYY LZZZZZZZ value
Keyword Parameters:
Attributes:
:attr:`inductor1`
:attr:`inductor2`
:attr:`coupling_factor`
"""
ALIAS = 'K'
PREFIX = 'K'
inductor1 = ElementNamePositionalParameter(position=0, key_parameter=False)
inductor2 = ElementNamePositionalParameter(position=1, key_parameter=False)
coupling_factor = FloatPositionalParameter(position=2, key_parameter=False)
_logger = _module_logger.getChild('CoupledInductor')
##############################################
def __init__(self, name, *args, **kwargs):
super().__init__(name, *args, **kwargs)
self._inductors = []
for inductor in (self.inductor1, self.inductor2):
try:
self.netlist.element(inductor)
except KeyError:
try:
inductor = 'L' + inductor
self.netlist.element(inductor)
self._logger.info('Prefixed element {}'.format(inductor))
except KeyError:
raise ValueError('Element with name {} not found'.format(inductor))
# Fixme: str or Element instance ?
self._inductors.append(inductor)
self.inductor1, self.inductor2 = self._inductors
####################################################################################################
[docs]class VoltageControlledSwitch(TwoPortElement):
"""This class implements a voltage controlled switch.
Spice syntax:
.. code-block:: none
SXXXXXXX n+ n- nc+ nc- model <on> <off>
Keyword Parameters:
:attr:`model`
:attr:`initial_state`
Attributes:
:attr:`model`
:attr:`initial_state`
"""
ALIAS = 'S'
LONG_ALIAS = 'VCS'
PREFIX = 'S'
model = ModelPositionalParameter(position=0, key_parameter=True)
initial_state = InitialStatePositionalParameter(position=1, key_parameter=True)
####################################################################################################
[docs]class CurrentControlledSwitch(DipoleElement):
"""This class implements a current controlled switch.
Spice syntax:
.. code-block:: none
WYYYYYYY n+ n- vname model <on> <off>
Keyword Parameters:
:attr:`source`
:attr:`model`
:attr:`initial_state`
Attributes:
:attr:`source`
:attr:`model`
:attr:`initial_state`
"""
ALIAS = 'W'
LONG_ALIAS = 'CCS'
PREFIX = 'W'
source = ElementNamePositionalParameter(position=0, key_parameter=True)
model = ModelPositionalParameter(position=1, key_parameter=True)
initial_state = InitialStatePositionalParameter(position=2, key_parameter=True)
####################################################################################################
#
# Voltage and Current Sources
#
####################################################################################################
[docs]class VoltageSource(DipoleElement):
"""This class implements an independent sources for voltage.
Spice syntax:
.. code-block:: none
VXXXXXXX n+ n- <<dc> dc/tran value> <ac <acmag <acphase>>> <distof1 <f1mag <f1phase>>> <distof2 <f2mag <f2phase>>>
Keyword Parameters:
Attributes:
:attr:`dc_value`
"""
ALIAS = 'V'
PREFIX = 'V'
# Fixme: ngspice manual doesn't describe well the syntax
dc_value = FloatPositionalParameter(position=0, key_parameter=False, unit=U_V)
####################################################################################################
[docs]class CurrentSource(DipoleElement):
"""This class implements an independent sources for current.
Spice syntax:
.. code-block:: none
IYYYYYYY n+ n- <<dc> dc/tran value> <ac <acmag <acphase>>> <distof1 <f1mag <f1phase>>> <distof2 <f2mag <f2phase>>>
Keyword Parameters:
Attributes:
:attr:`dc_value`
"""
ALIAS = 'I'
PREFIX = 'I'
# Fixme: ngspice manual doesn't describe well the syntax
dc_value = FloatPositionalParameter(position=0, key_parameter=False, unit=U_A)
####################################################################################################
[docs]class VoltageControlledCurrentSource(TwoPortElement):
"""This class implements a linear voltage-controlled current sources (VCCS).
Spice syntax:
.. code-block:: none
Gxxx n+ n- nc+ nc- value <m=val>
Keyword Parameters:
:attr:`multiplier`
alias `m`
Attributes:
:attr:`transconductance`
"""
ALIAS = 'VCCS'
PREFIX = 'G'
transconductance = ExpressionPositionalParameter(position=0, key_parameter=False)
multiplier = IntKeyParameter('m')
####################################################################################################
[docs]class VoltageControlledVoltageSource(TwoPortElement):
"""This class implements a linear voltage-controlled voltage sources (VCVS).
Spice syntax:
.. code-block:: none
EXXXXXXX n+ n- nc+ nc- value
Keyword Parameters:
Attributes:
:attr:`voltage_gain`
"""
ALIAS = 'VCVS'
PREFIX = 'E'
voltage_gain = ExpressionPositionalParameter(position=0, key_parameter=False)
####################################################################################################
[docs]class CurrentControlledCurrentSource(DipoleElement):
"""This class implements a linear current-controlled current sources (CCCS).
Spice syntax:
.. code-block:: none
FXXXXXXX n+ n- vname value <m=val>
Keyword Parameters:
:attr:`multiplier`
alias `m`
Attributes:
:attr:`source`
:attr:`current_gain`
"""
ALIAS = 'F'
LONG_ALIAS = 'CCCS'
PREFIX = 'F'
source = ElementNamePositionalParameter(position=0, key_parameter=False)
current_gain = ExpressionPositionalParameter(position=1, key_parameter=False)
multiplier = IntKeyParameter('m')
####################################################################################################
[docs]class CurrentControlledVoltageSource(DipoleElement):
"""This class implements a linear current-controlled voltage sources (CCVS).
Spice syntax:
.. code-block:: none
HXXXXXXX n+ n- vname value
Keyword Parameters:
Attributes:
:attr:`source`
:attr:`transresistance`
"""
ALIAS = 'H'
LONG_ALIAS = 'CCVS'
PREFIX = 'H'
source = ElementNamePositionalParameter(position=0, key_parameter=False)
transresistance = ExpressionPositionalParameter(position=1, key_parameter=False)
####################################################################################################
#
# Non-Linear Dependent Sources (Behavioral Sources)
#
####################################################################################################
[docs]class BehavioralSource(DipoleElement):
"""This class implements a behavioral source.
Spice syntax:
.. code-block:: none
BXXXXXXX n+ n- <i=expr> <v=expr> <tc1=value> <tc2=value> <temp=value> <dtemp=value>
Keyword Parameters:
:attr:`current_expression`
alias `i`
:attr:`voltage_expression`
alias `v`
:attr:`tc1`
:attr:`tc2`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
Attributes:
:attr:`current_expression`
:attr:`voltage_expression`
:attr:`tc1`
:attr:`tc2`
:attr:`temperature`
:attr:`device_temperature`
"""
ALIAS = 'B'
PREFIX = 'B'
current_expression = ExpressionKeyParameter('i')
voltage_expression = ExpressionKeyParameter('v')
tc1 = FloatKeyParameter('tc1')
tc2 = FloatKeyParameter('tc2')
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
####################################################################################################
[docs]class NonLinearVoltageSource(DipoleElement):
"""This class implements a non-linear voltage source.
.. warning:: Partially implemented
Spice syntax:
.. code-block:: none
Exxx n+ n- vol='expr'
Exxx n+ n- value={expr}
Exxx n1 n2 TABLE {expression}=(x0,y0) (x1,y1) (x2,y2)
Exxx n+ n- ( POLY (nd) ) nc1+ nc1- ( nc2+ nc2- ... ) p0 ( p1 ... )
Laplace
Keyword Parameters:
Attributes:
"""
ALIAS = 'NonLinearVoltageSource'
PREFIX = 'E'
# Fixme:
VALID_KWARGS = ('expression', 'table')
##############################################
def __init__(self, name, *args, **kwargs):
super().__init__(name, *args, **kwargs)
self.expression = kwargs.get('expression', None)
self.table = kwargs.get('table', None)
##############################################
def __str__(self):
spice_element = self.format_node_names()
# Fixme: expression
if self.table is not None:
# TABLE {expression} = (x0, y0) (x1, y1) ...
table = ['({}, {})'.format(str_spice(x), str_spice(y)) for x, y in self.table]
spice_element += ' TABLE {%s} = %s' % (self.expression, join_list(table))
return spice_element
####################################################################################################
[docs]class NonLinearCurrentSource(DipoleElement):
"""This class implements a non-linear current sources.
.. warning:: Partially implemented
Spice syntax:
.. code-block:: none
Gxxx n+ n- value={expr}
Gxxx n1 n2 TABLE {expression}=(x0,y0) (x1,y1) (x2,y2)
Gxxx n+ n- ( POLY (nd) ) nc1+ nc1- ( nc2+ nc2- ... ) p0 ( p1 ... )
Laplace
Keyword Parameters:
Attributes:
:attr:`transconductance`
"""
ALIAS = 'NonLinearCurrentSource'
PREFIX = 'G'
transconductance = ExpressionPositionalParameter(position=0, key_parameter=False)
####################################################################################################
#
# Diode
#
####################################################################################################
[docs]class Diode(FixedPinElement):
"""This class implements a junction diode.
Spice syntax:
.. code-block:: none
DXXXXXXX n+ n- mname <area=val> <m=val> <pj=val> <off> <ic=vd> <temp=val> <dtemp=val>
Keyword Parameters:
:attr:`model`
:attr:`area`
:attr:`multiplier`
alias `m`
:attr:`pj`
:attr:`off`
:attr:`ic`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
Attributes:
:attr:`model`
:attr:`area`
:attr:`multiplier`
:attr:`pj`
:attr:`off`
:attr:`ic`
:attr:`temperature`
:attr:`device_temperature`
"""
ALIAS = 'D'
PREFIX = 'D'
PINS = (('cathode', 'plus'), ('anode', 'minus'))
model = ModelPositionalParameter(position=0, key_parameter=True)
area = FloatKeyParameter('area')
multiplier = IntKeyParameter('m')
pj = FloatKeyParameter('pj')
off = FlagParameter('off')
ic = FloatPairKeyParameter('ic')
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
####################################################################################################
#
# BJTs
#
####################################################################################################
[docs]class BipolarJunctionTransistor(FixedPinElement):
"""This class implements a bipolar junction transistor.
Spice syntax:
.. code-block:: none
QXXXXXXX nc nb ne <ns> mname <area=val> <areac=val> <areab=val> <m=val> <off> <ic=vbe,vce> <temp=val> <dtemp=val>
Keyword Parameters:
:attr:`model`
:attr:`area`
:attr:`areac`
:attr:`areab`
:attr:`multiplier`
alias `m`
:attr:`off`
:attr:`ic`
:attr:`temperature`
alias `temp`
:attr:`device_temperature`
alias `dtemp`
Attributes:
:attr:`model`
:attr:`area`
:attr:`areac`
:attr:`areab`
:attr:`multiplier`
:attr:`off`
:attr:`ic`
:attr:`temperature`
:attr:`device_temperature`
"""
# Fixme: off doesn't fit in kwargs !
ALIAS = 'Q'
LONG_ALIAS = 'BJT'
PREFIX = 'Q'
PINS = ('collector', 'base', 'emitter', OptionalPin('substrate'))
model = ModelPositionalParameter(position=0, key_parameter=True)
area = FloatKeyParameter('area')
areac = FloatKeyParameter('areac')
areab = FloatKeyParameter('areab')
multiplier = IntKeyParameter('m')
off = FlagParameter('off')
ic = FloatPairKeyParameter('ic')
temperature = FloatKeyParameter('temp', unit=U_Degree)
device_temperature = FloatKeyParameter('dtemp', unit=U_Degree)
####################################################################################################
#
# JFETs
#
####################################################################################################
[docs]class JfetElement(FixedPinElement):
PINS = ('drain', 'gate', 'source')
[docs]class JunctionFieldEffectTransistor(JfetElement):
"""This class implements a bipolar junction transistor.
Spice syntax:
.. code-block:: none
JXXXXXXX nd ng ns mname <area> <off> <ic=vds,vgs> <temp=t>
Keyword Parameters:
:attr:`model`
:attr:`area`
:attr:`off`
:attr:`ic`
:attr:`temperature`
alias `temp`
Attributes:
:attr:`model`
:attr:`area`
:attr:`off`
:attr:`ic`
:attr:`temperature`
"""
# Fixme: off doesn't fit in kwargs !
ALIAS = 'J'
LONG_ALIAS = 'JFET'
PREFIX = 'J'
model = ModelPositionalParameter(position=0, key_parameter=True)
area = FloatKeyParameter('area')
multiplier = IntKeyParameter('m')
off = FlagParameter('off')
ic = FloatPairKeyParameter('ic')
temperature = FloatKeyParameter('temp', unit=U_Degree)
####################################################################################################
#
# MESFETs
#
####################################################################################################
[docs]class Mesfet(JfetElement):
"""This class implements a Metal Semiconductor Field Effect Transistor.
Spice syntax:
.. code-block:: none
ZXXXXXXX nd ng ns mname <area> <off> <ic=vds,vgs>
Keyword Parameters:
:attr:`model`
:attr:`area`
:attr:`off`
:attr:`ic`
Attributes:
:attr:`model`
:attr:`area`
:attr:`off`
:attr:`ic`
"""
# Fixme: off doesn't fit in kwargs !
ALIAS = 'Z'
LONG_ALIAS = 'MESFET'
PREFIX = 'Z'
model = ModelPositionalParameter(position=0, key_parameter=True)
area = FloatKeyParameter('area')
multiplier = IntKeyParameter('m')
off = FlagParameter('off')
ic = FloatPairKeyParameter('ic')
####################################################################################################
#
# MOSFETs
#
####################################################################################################
[docs]class Mosfet(FixedPinElement):
"""This class implements a Metal Oxide Field Effect Transistor.
Spice syntax:
.. code-block:: none
MXXXXXXX nd ng ns nb mname <m=val> <l=val> <w=val>
+ <ad=val> <as=val> <pd=val> <ps=val> <nrd=val>
+ <nrs=val> <off> <ic=vds,vgs,vbs> <temp=t>
Keyword Parameters:
:attr:`model`
:attr:`multiplier`
alias `m`
:attr:`length`
alias `l`
:attr:`width`
alias `w`
:attr:`nfin`
only for Xyce
:attr:`drain_area`
alias `ad`
:attr:`source_area`
alias `as`
:attr:`drain_perimeter`
alias `pd`
:attr:`source_perimeter`
alias `ps`
:attr:`drain_number_square`
alias `nrd`
:attr:`source_number_square`
alias `nrs`
:attr:`off`
:attr:`ic`
:attr:`temperature`
alias `temp`
Attributes:
:attr:`model`
:attr:`multiplier`
:attr:`length`
:attr:`width`
:attr:`nfin`
only for Xyce
:attr:`drain_area`
:attr:`source_area`
:attr:`drain_perimeter`
:attr:`source_perimeter`
:attr:`drain_number_square`
:attr:`source_number_square`
:attr:`off`
:attr:`ic`
:attr:`temperature`
"""
# Fixme: off doesn't fit in kwargs !
ALIAS = 'M'
LONG_ALIAS = 'MOSFET'
PREFIX = 'M'
PINS = ('drain', 'gate', 'source', ('bulk', 'substrate'))
model = ModelPositionalParameter(position=0, key_parameter=True)
multiplier = IntKeyParameter('m')
length = FloatKeyParameter('l', unit=U_m)
width = FloatKeyParameter('w', unit=U_m)
drain_area = FloatKeyParameter('ad')
source_area = FloatKeyParameter('as')
drain_perimeter = FloatKeyParameter('pd')
source_perimeter = FloatKeyParameter('ps')
drain_number_square = FloatKeyParameter('nrd')
source_number_square = FloatKeyParameter('nrs')
off = FlagParameter('off')
ic = FloatTripletKeyParameter('ic')
temperature = FloatKeyParameter('temp', unit=U_Degree)
# only for Xyce
nfin = IntKeyParameter('nfin')
####################################################################################################
#
# Transmission Lines
#
####################################################################################################
[docs]class LosslessTransmissionLine(TwoPortElement):
"""This class implements a lossless transmission line.
Spice syntax:
.. code-block:: none
TXXXXXXX N1 N2 N3 N4 Z0=VALUE <TD=VALUE> <F=FREQ <NL=NRMLEN>> <IC=V1, I1, V2, I2>
where TD or F, NL must be specified.
Keyword Parameters:
:attr:`impedance`
alias:`Z0`
is the characteristic impedance
:attr:`time_delay`
alias:`TD`
is the transmission delay
:attr:`frequency`
alias:`F`
:attr:`normalized_length`
alias:`NL`
Attributes:
:attr:`impedance`
:attr:`time_delay`
:attr:`frequency`
:attr:`normalized_length`
The transmission delay, `td`, may be specified directly (as `td=10ns`, for example).
Alternatively, a frequency `f` may be given, together with `nl`, the normalized electrical
length of the transmission line with respect to the wavelength in the line at the frequency
`f`. If a frequency is specified but `nl` is omitted, 0.25 is assumed (that is, the frequency is
assumed to be the quarter-wave frequency). Note that although both forms for expressing the line
length are indicated as optional, one of the two must be specified.
Note: Either time_delay or frequency must be given.
"""
ALIAS = 'TransmissionLine'
PREFIX = 'T'
impedance = FloatKeyParameter('Z0', default=50, unit=U_Ω)
time_delay = FloatKeyParameter('TD', unit=U_s)
frequency = FloatKeyParameter('F', unit=U_Hz)
normalized_length = FloatKeyParameter('NL')
##############################################
def __init__(self, name, *args, **kwargs):
super().__init__(name, *args, **kwargs)
if not (self.has_parameter('time_delay') or
(self.has_parameter('frequency') and self.has_parameter('normalized_length'))):
raise NameError('Either TD or F, NL must be specified')
####################################################################################################
[docs]class LossyTransmission(TwoPortElement):
"""This class implements lossy transmission lines.
Spice syntax:
.. code-block:: none
OXXXXXXX n1 n2 n3 n4 model
Attributes:
:attr:`model`
.. note:: As opposite to Spice, the model is specified before the nodes so as to act as `*args`.
"""
ALIAS = 'O'
PREFIX = 'O'
model = ModelPositionalParameter(position=0, key_parameter=True)
####################################################################################################
[docs]class CoupledMulticonductorLine(NPinElement):
"""This class implements coupled multiconductor lines.
Spice syntax:
.. code-block:: none
PXXXXXXX NI1 NI2 ... NIX GND1 NO1 NO2 ... NOX GND2 model <len=length>
Attributes:
:attr:`model`
:attr:`length`
alias `len`
length of the line in meters
.. note:: As opposite to Spice, the model is specified before the nodes so as to act as `*args`.
"""
ALIAS = 'P'
PREFIX = 'P'
model = ModelPositionalParameter(position=0, key_parameter=True)
length = FloatKeyParameter('len', unit=U_m)
##############################################
def __init__(self, netlist, name, *nodes, **parameters):
super().__init__(netlist, name, nodes, **parameters)
####################################################################################################
####################################################################################################
[docs]class SingleLossyTransmissionLine(TwoPortElement):
# Fixme: special TwoPortElement
"""This class implements single lossy transmission lines.
Spice syntax:
.. code-block:: none
YXXXXXXX N1 0 N2 0 model <len=length>
Attributes:
:attr:`model`
:attr:`length`
alias `len`
length of the line in meters
.. note:: As opposite to Spice, the model is specified before the nodes so as to act as `*args`.
"""
ALIAS = 'Y'
PREFIX = 'Y'
model = ModelPositionalParameter(position=0, key_parameter=True)
length = FloatKeyParameter('len', unit=U_m)
####################################################################################################
#
# XSPICE
#
####################################################################################################
[docs]class XSpiceElement(NPinElement):
"""This class implements a XSpice element.
Spice syntax:
.. code-block:: none
AXXXXXXX <%v ,%i ,%vd ,%id ,%g,%gd ,%h,%hd , or %d>
+ <[> <~><%v ,%i ,%vd ,%id ,%g,%gd ,%h,%hd , or %d>
+ <NIN1 or +NIN1 -NIN1 or "null">
+ <~>...< NIN2 .. <]> >
+ <%v ,%i ,%vd ,%id ,%g,%gd ,%h,%hd ,%d or %vnam >
+ <[> <~><%v ,%i ,%vd ,%id ,%g,%gd ,%h,%hd ,
or %d>< NOUT1 or +NOUT1 -NOUT1 >
+ <~>...< NOUT2 .. <]>>
+ MODELNAME
. MODEL MODELNAME MODELTYPE
+ <( PARAMNAME1 = <[> VAL1 <VAL2 ... <]>> PARAMNAME2 ..>)>
Attributes:
:attr:`model`
.. note:: As opposite to Spice, the model is specified before the nodes so as to act as `*args`.
.. warning:: Partially implemented.
"""
ALIAS = 'A'
PREFIX = 'A'
model = ModelPositionalParameter(position=0, key_parameter=True)
##############################################
def __init__(self, netlist, name, *nodes, **parameters):
# Fixme: ok ???
super().__init__(netlist, name, nodes, **parameters)
####################################################################################################
#
# GSS
#
####################################################################################################
[docs]class GSSElement(NPinElement):
"""This class implements GSS device.
.. warning:: Not implemented
"""
ALIAS = 'N'
PREFIX = 'N'
##############################################
def __init__(self):
raise NotImplementedError