Example #1
0
    def process_params(self):

        if self.is_set('f'):
            # Nonlinear source
            if self.is_set('g'):
                raise cir.CircuitError(
                    '{0}: can not specify both g and f'.format(
                        self.instanceName))
            # test f expression to make sure it is valid
            try:
                vc = .5
                result = eval(self.f)
            except Exception as e:
                raise cir.CircuitError(
                    '{0}: Invalid expression: {1} ({2})'.format(
                        self.instanceName, self.f, e))
            try:
                abs(result)
            except TypeError:
                raise cir.CircuitError(
                    '{0}: Invalid expression: {1} result not a number)'.format(
                        self.instanceName, self.m))
            # Set nonlinear attributes
            self.isNonlinear = True
            self.controlPorts = [(2, 3)]
            self.csOutPorts = [(0, 1)]
            self.qsOutPorts = []

        else:
            # linear source
            self.linearVCCS = [((2,3), (0,1), self.g)]
Example #2
0
    def process_params(self):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.

        # remove any existing internal connections
        self.clean_internal_terms()

        # Test parameters
        if not self.rleak:
            raise cir.CircuitError(self.instanceName 
                                   + ': leackage resistance can not be zero')
        if not self.c:
            raise cir.CircuitError(self.instanceName 
                                   + ': capacitance can not be zero')
        # test m expression to make sure it is valid
        try:
            q = .5
            result = eval(self.m)
        except Exception as e:
            raise cir.CircuitError(
                '{0}: Invalid expression: {1} ({2})'.format(self.instanceName, 
                                                            self.m, e))
        try:
            abs(result)
        except TypeError:
            raise cir.CircuitError(
                '{0}: Invalid expression: {1} (result not a number)'.format(
                    self.instanceName, self.m))

        # Connect internal terminal
        tim = self.add_internal_term('im', '{0} A'.format(glVar.gyr)) 
        tvc = self.add_internal_term('vc', 'V') 
        tref = self.add_reference_term() 
        # Set up source if q0 is given
        if self.q0 != 0.:
            self.isDCSource = True
            self.sourceOutput = (tref, tvc)
            self._i0 = self.q0 / self.c / self.rleak

        # Setup gyrator
        # Access to global variables is through the glVar 
        self.linearVCCS = [((0,1), (tref, tim), glVar.gyr), 
                           ((tim, tref), (0,1), glVar.gyr),
                           ((tim, tref), (tref, tvc), glVar.gyr),
                           ((tvc, tref), (tvc, tref), 1./self.rleak)]
        self.linearVCQS = [((tvc, tref), (tvc, tref), self.c)]

        self.controlPorts = [(tim, tref), (tvc, tref)]
        self.csOutPorts = [(tim, tref)]
        self.qsOutPorts = []
Example #3
0
    def process_params(self, thermal=False):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.
        ad.delete_tape(self)
        if self.type == 'n':
            self._tf = 1.
        elif self.type == 'p':
            self._tf = -1.
        else:
            raise cir.CircuitError(
                '{0}: unrecognized type: {1}. Valid types are "n" or "p"'.
                format(self.instanceName, self.type))

        # Make sure vth is positive for calculations
        self._vth = abs(self.vth)
        self._tcv = np.abs(self.tcv)

        # Nominal abs temperature
        self._Tn = const.T0 + self.tnom
        # Nominal Thermal voltage
        self._Vtn = const.k * self._Tn / const.q
        self._mu = self.isq * 2. / (self.n * self.cox * self._Vtn**2)
        if not thermal:
            # Calculate temperature-dependent variables
            self.set_temp_vars(self.temp)
Example #4
0
    def process_params(self):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.

        # Access to global variables is through the glVar 
        if not self.c:
            raise cir.CircuitError(self.instanceName 
                                   + ': Capacitance can not be zero')

        # Adjust according to temperature (not needed so far)
        # self.set_temp_vars(self.temp)
        self.linearVCQS = [((0, 1), (0, 1), self.c)]
Example #5
0
    def process_params(self):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.

        # remove any existing internal connections
        self.clean_internal_terms()

        if not self.l:
            raise cir.CircuitError(self.instanceName 
                                   + ': Inductance can not be zero')
        # Connect internal terminal
        til = self.add_internal_term('il', '{0} A'.format(glVar.gyr)) 
        tref = self.add_reference_term() 
        # Setup gyrator
        # Access to global variables is through the glVar 
        self.linearVCCS = [((0,1), (tref, til), glVar.gyr), 
                           ((til, tref), (0,1), glVar.gyr)]
        cap = self.l * glVar.gyr**2
        self.linearVCQS = [((til, tref), (til, tref), cap)]
Example #6
0
    def process_params(self, thermal=False):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.

        # Delete AD tape (if any)
        ad.delete_tape(self)
        # Access to global variables is through the glVar
        if not self.r and not (self.rsh and self.l and self.w):
            raise cir.CircuitError(self.instanceName +
                                   ': Resistance can not be zero')

        if self.r != 0.:
            # if R is given it overrides rsh et ale
            self.g = 1. / self.r
        else:
            self.g = (self.w - self.narrow) / (self.l - self.narrow) / self.rsh

        if not thermal:
            # Adjust according to temperature
            self.set_temp_vars(self.temp)
Example #7
0
    def process_params(self, thermal=False):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.
        ad.delete_tape(self)

        if self.type == 'n':
            self._tf = 1.
        elif self.type == 'p':
            self._tf = -1.
        else:
            raise cir.CircuitError(
                '{0}: unrecognized type: {1}. Valid types are "n" or "p"'.
                format(self.instanceName, self.type))

        # Nominal abs temperature
        self._Tn = const.T0 + self.tnom

        if not thermal:
            # Calculate temperature-dependent variables
            self.set_temp_vars(self.temp)
Example #8
0
    def process_params(self):
        """
        This should be called each time parameter values are changed
        """
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.

        # Use the following to make sure connections to internal
        # terminals are not repeated if this process_params is called
        # many times. 
        self.clean_internal_terms()
        # Calculate the capacitance per unit length
        # k = epsilon_eff
        self.c = np.sqrt(self.k) / (self.z0mag * const.c0)

        # Calculate the inductance per unit length
        self.l = (self.z0mag * self.z0mag) * self.c

        # convert alpha from db/m to nepers/m
        self.alpha_nepers = self.alpha / const.Np2dB

        # If nsect (number of sections) is set then use a
        # multi-section model for the transmisison line.  The strategy
        # is to expand the transmission line into a number of RLGC
        # sections. A circuit is built up with series L's and shunt
        # C's (which support series resistance and shunt capacitance)
        if self.nsect:
            # No longer a frequency-defined element
            self.isFreqDefined = False
            # Need to check that the local reference terminals are the
            # same as this is required by the sectional model.
            if self.connection[1] != self.connection[3]:
                raise cir.CircuitError('{1}: nsect > 0 but sectional model requires port references to be the same node'.format(self.instanceName)) 

            # Use discrete approximation.  Find the number of
            # subsections and the RLCG parameters of each.  First get
            # the length of each subsection.
            delta_x = self.length / self.nsect
            # Scale attenuation if fscale and fopt given
            if self.fscale * self.fopt != 0.:
                alphaf = self.alpha_nepers * np.sqrt(self.fopt / self.fscale)
            else:
                alphaf = self.alpha_nepers
            # Now get the R, L, G and C of each subsection.
            R = 2.0 * alphaf * self.z0mag * delta_x
            if self.fopt * self.tand != 0.:
                G = self.tand * 2. * np.pi * self.fopt * self.c * delta_x
            else:
                G = 0.

            L = self.l * delta_x
            C = self.c * delta_x

            # Gyrated inductor cap
            indcap = L * glVar.gyr * glVar.gyr
            # Reference for all gyrators
            tref = self.add_reference_term()
            # nps: nodes added by one section
            if R:
                nps = 3
            else:
                nps = 2
            # Initialize empty lists
            self.linearVCCS = list()
            self.linearVCQS = list()
            # Expand transmission line sections
            for i in xrange(self.nsect):
                # input node number
                if i:
                    inn = nps*i + tref
                else:
                    inn = 0
                # add gyrator node
                gnn = self.add_internal_term('il{0}'.format(i), 
                                             '{0} A'.format(glVar.gyr))
                # The last section does not add cap node
                if i < self.nsect - 1:
                    # Add capacitor terminal
                    cnn = self.add_internal_term('c{0}'.format(i), 'V')
                else:
                    cnn = 2
                if R:
                    # add resistor node
                    rnn = self.add_internal_term('r{0}'.format(i), 'V')
                    # Add gyrator
                    self.linearVCCS += [((inn, rnn), (tref, gnn), glVar.gyr), 
                                        ((gnn, tref), (inn, rnn), glVar.gyr)]
                    # Add resistor
                    self.linearVCCS.append(((rnn, cnn), (rnn, cnn), 1./R))
                else:
                    # Add gyrator
                    self.linearVCCS += [((inn, cnn), (tref, gnn), glVar.gyr), 
                                        ((gnn, tref), (inn, cnn), glVar.gyr)]
                # Add inductor
                self.linearVCQS.append(((gnn, tref), (gnn, tref), indcap))
                # Add capacitor
                self.linearVCQS.append(((cnn, 1), (cnn, 1), C))
                if G:
                    # Add conductor
                    self.linearVCCS.append(((cnn, 1), (cnn, 1), G))
Example #9
0
    def process_params(self, thermal=False):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.
        # import pdb; pdb.set_trace()

        # Delete AD tape (if any)
        ad.delete_tape(self)
        # Any value other than zero uses the simple function
        if self.ekvint:
            self.interp = f_simple
        else:
            self.interp = f_accurate
        # Set Constants
        self.Tref = 300.15
        self._Tn = self.tnom + const.T0
        vtTref = (const.k * self.Tref) / const.q
        self.egTref = 1.16 - 0.000702 * self.Tref * self.Tref \
            / (self.Tref + 1108.)
        vtTnom = (const.k * self._Tn) / const.q
        self.egTnom = 1.16 - .000702 * self._Tn * self._Tn / (self._Tn + 1108.)
        niTnom = 1.45e10 * (self._Tn / self.Tref) \
            * np.exp(self.egTref / (2. * vtTref) - self.egTnom / (2. * vtTnom))
        # For N/P channel
        self._tcv = np.abs(self.tcv)
        if self.type == 'n':
            self.eta = 0.5
            self._tf = 1.
        elif self.type == 'p':
            self.eta = 1. / 3.
            self._tf = -1.
        else:
            raise cir.CircuitError(
                '{0}: unrecognized type: {1}. Valid types are "n" or "p"'.
                format(self.instanceName, self.type))
        #---------------------------------------------------------------
        # Calculate any missing parameters from user-defined settings
        # COX
        if (not self.is_set('cox')) and self.tox != None:
            self.cox = const.epOx / self.tox
        # GAMMA
        if (not self.is_set('gamma')) and self.nsub != None:
            self.gamma = np.sqrt(
                2. * const.q * const.epSi * self.nsub * 1.e6) / self.cox
        # PHI
        if (not self.is_set('phi')) and self.nsub != None:
            self.phi = 2. * vtTnom * np.log(self.nsub / niTnom)
        # VT0: if specified, must be with the correct sign, otherwise
        # we have to adjust for P-channel
        if (not self.is_set('vt0')):
            if self.vfb != None:
                self.vt0 = self._tf * (self.vfb + self.phi +
                                       self.gamma * np.sqrt(self.phi))
            else:
                self.vt0 *= self._tf
        # Make sure vt0 is positive for calculations
        self._vt0 = abs(self.vt0)
        # KP
        if (not self.is_set('kp')) and self.u0 != None:
            self.kp = self.u0 * 1.e-4 * self.cox  # /*(m^2/cm^2)*/
        # UCRIT
        if (not self.is_set('ucrit')) and (self.vmax != None) and \
                (self.u0 != None):
            self.ucrit = self.vmax / (self.u0 * 1.e-4)
        # E0: no need for anything since theta != 0 triggers simple
        # mobility model

        # Initialize more variables
        self._weff = self.w + self.dw
        self._leff = self.l + self.dl
        # sqrt gate area
        self._sga = np.sqrt(self.np * self._weff * self.ns * self._leff)
        self._gammaa = self.gamma + self.agamma / self._sga
        # Clip to zero if negative
        if self._gammaa < 0.:
            self._gammaa = 0.
        cEps = 0.001936  #  was: 4. * pow(22.e-3, 2)
        cA = 0.028
        xi = cA * (10. * self._leff / self.lk - 1.)
        self._deltavRSCE = 2. * self.q0 / \
            (self.cox * pow(1. + 0.5 * (xi + np.sqrt(xi*xi + cEps)), 2))

        # constants used in eval_c1qs()
        self._lc = np.sqrt(const.epSi * self.xj / self.cox)
        self._lmin = self.ns * self._leff / 10.
        self._Cox = self.cox * self.np * self._weff * self.ns * self._leff

        if not thermal:
            # Calculate temperature-dependent variables
            self.set_temp_vars(self.temp)
Example #10
0
    def process_params(self, thermal = False):
        # Called once the external terminals have been connected and
        # the non-default parameters have been set. Make sanity checks
        # here. Internal terminals/devices should also be defined
        # here.  Raise cir.CircuitError if a fatal error is found.
        ad.delete_tape(self)
        if self.type == 'n':
            self._tf = 1.
        elif self.type == 'p':
            self._tf = -1.
            # Change parameter default values
            if not self.is_set('u0'):
                self.u0 = 250
        else:
            raise cir.CircuitError(
                '{0}: unrecognized type: {1}. Valid types are "n" or "p"'.format(self.instanceName, self.type))

        # Nominal abs temperature
        self._Tn = const.T0 + self.tnom
        # Nominal Thermal voltage
        self._Vtn = const.k * self._Tn / const.q

        self.factor1 = np.sqrt(const.epSi / const.epOx * self.tox)
        Eg0 = 1.16 - 7.02e-4 * (self._Tn**2) / (self._Tn + 1108.0)
        ni = 1.45e10 * (self._Tn / 300.15) * np.sqrt(self._Tn / 300.15) \
            * np.exp(21.5565981 - Eg0 / (2. * self._Vtn))
        #self.esi = 11.7 * const.epsilon0 (replaced by const.epSi)
        self.ldrn = self.l
        self.wdrn = self.w
        
        t0 = pow(self.ldrn, self.lln)
        t1 = pow(self.wdrn, self.lwn)
        tmp1 = self.ll / t0 + self.lw / t1 + self.lwl / (t0 * t1)
        self.dl = self.lint + tmp1
        #tmp2 = llc / t0 + lwc / t1 + lwlc / (t0 * t1)
        #self.dlc = dlc + tmp2  # ???
        
        t2 = pow(self.ldrn, self.wln)
        t3 = pow(self.wdrn, self.wwn)
        tmp3 = self.wl / t2 + self.ww / t3 + self.wwl / (t2 * t3)
        self.dw = self.wint + tmp3
        #tmp4 = wlc / t2 + wwc / t3 + wwlc / (t2 * t3)
        #self.dwc = dwc + tmp4 # ???
        
        self.leff = self.l - 2.0 * self.dl
        self.weff = self.w - 2.0 * self.dw

        self.AbulkCVfactor = (1. + pow(self.clc/self.leff, self.cle))

        #self.leffCV = l - 2.0 * dlc
        #self.t11 = leffCV * leffCV

        # was epOx = 3.453133e-11
        self.cox = const.epOx / self.tox

        self.phi = 2. * self._Vtn * np.log(self.nch / ni)
        self.sqrtPhi = np.sqrt(self.phi)
        self.phis3 = self.sqrtPhi * self.phi

        self.Xdep0 = np.sqrt(2. * const.epSi / 
                          (const.q * self.nch * 1e6)) * self.sqrtPhi
        self.litl = np.sqrt(3. * self.xj * self.tox)
        self.vbi = self._Vtn * np.log(1.0e20 * self.nch / (ni**2))
        self.cdep0 = np.sqrt(const.q * const.epSi * self.nch * 1e6 
                          / 2. / self.phi)

        if not self.is_set('toxm'):
            self.toxm = self.tox
        if not self.is_set('dsub'):
            self.dsub = self.drout

        self.ldeb = np.sqrt(const.epSi * self._Vtn
                           / (const.q * self.nch * 1e6)) / 3.
        
        #import pdb; pdb.set_trace()
        if (self.k1enable != 0.) and \
                not (self.is_set('k1') or self.is_set('k2')):
            vbx = self.phi - 7.7348e-4  * self.nch * self.xt**2
            # From ngspice
            vbx = -abs(vbx)
            Vbm = -abs(self.vbm)
            gamma1 = 5.753e-12 * np.sqrt(self.nch) / self.cox
            gamma2 = 5.753e-12 * np.sqrt(self.nsub) / self.cox
            T0 = gamma1 - gamma2
            T1 = np.sqrt(self.phi - vbx) - self.sqrtPhi
            T2 = np.sqrt(self.phi * (self.phi - Vbm)) - self.phi
            self._k2 = T0 * T1 / (2. * T2 + Vbm)
            self._k1 = gamma2 - 2. * self._k2 * np.sqrt(self.phi - Vbm)
            # print self._k1, self._k2
        else:
            self._k1 = self.k1
            self._k2 = self.k2
        
        if not self.is_set('vth0'):
            self._vth0 = self.vfb + self.phi + self._k1 * self.sqrtPhi
        else:
            self._vth0 = abs(self.vth0)

        self.k1ox = self._k1 * self.tox / self.toxm
        self.k2ox = self._k2 * self.tox / self.toxm

        t1 = np.sqrt(const.epSi / const.epOx * self.tox * self.Xdep0)
        t0 = ad.safe_exp(-0.5 * self.dsub * self.leff / t1)
        self.theta0vb0 = (t0 + 2.0 * t0**2)
        # From freeda, ngspice:
        self._Tox = 1e8 * self.tox
        
        #Calculation of vbsc(Vbc) and Vbseff
        if self._k2 < 0.:
            self.vbsc = .9 * (self.phi - (.5 * self._k1 / self._k2)**2)
            if self.vbsc > -3.:
                self.vbsc = -3.
            elif self.vbsc < -30.:
                self.vbsc = -30.
        else:
            self.vbsc = -30.

        if self.u0 > 1.:
            self._u0 = self.u0 * 1e-4
        else:
            self._u0 = self.u0 

        if not thermal:
            # Calculate temperature-dependent variables
            self.set_temp_vars(self.temp)
Example #11
0
        def process_params(self, thermal=False):
            # Remove tape if present
            ad.delete_tape(self)

            if thermal:
                extraTerms = 2
            else:
                extraTerms = 0

            # First check external connections
            if self.numTerms == 3 + extraTerms:
                self.__addCBjtn = False
            elif self.numTerms == 4 + extraTerms:
                self.__addCBjtn = True
            else:
                raise cir.CircuitError('{0}: Wrong number of connections. \
Can only be {1} or {2}, {3} found.'.format(self.instanceName, 3 + extraTerms,
                                           4 + extraTerms, self.numTerms))

            # Remove internal terminals
            self.clean_internal_terms()
            # Tell autothermal to re-generate thermal ports
            self.__addThermalPorts = True

            extraVCCS = list()
            if self.re != None:
                # Add et node and translate port descriptions
                self._et = self.add_internal_term('et', 'V')
                extraVCCS += [((2, self._et), (2, self._et),
                               self.area / self.re)]
            if self.rc != None:
                # Add ct node and translate port descriptions
                self._ct = self.add_internal_term('ct', 'V')
                extraVCCS += [((0, self._ct), (0, self._ct),
                               self.area / self.rc)]

            # Process parameters from intrinsic device: emitter and
            # collector terminals are already substituted.
            IBJT.process_params(self)
            # Calculate variables in junction
            self.cbjtn.process_params(self.iss, self.ns, self.fc, self.cjs,
                                      self.vjs, self.mjs, self.xti, self.eg,
                                      self.Tnomabs)
            # Add RE, RC resistors (if any)
            self.linearVCCS += extraVCCS
            if self.__addCBjtn:
                # Add bulk-collector junction
                self.__bccn = len(self.controlPorts)
                self.__bcon = len(self.csOutPorts)
                self.controlPorts.append((3, self._ct))
                self.csOutPorts.append((3, self._ct))
                if self.cjs != 0.:
                    self.qsOutPorts.append((3, self._ct))

                # Initial guess for input ports:
                try:
                    if len(self.vPortGuess) < len(self.controlPorts):
                        self.vPortGuess = np.concatenate(
                            (self.vPortGuess, [1]), axis=0)
                except AttributeError:
                    # Ignore if vPortGuess not provided
                    pass

            # Adjust temperature
            self.set_temp_vars(self.temp)