def set_device_temperature(self, T): """Change the temperature of the device. VTO, KP and PHI get updated. """ self.TEMP = T self.VTO = self.VTO - self.TCV * (T - self.TNOM) self.KP = self.KP * (T / self.TNOM)**self.BEX self.PHI = self.PHI * T/self.TNOM + 3*constants.Vth(self.TNOM)*math.log(T/self.TNOM) \ - constants.si.Eg(self.TNOM)*T/self.TNOM + constants.si.Eg(T)
def __init__(self, name, IS=None, N=None, ISR=None, NR=None, RS=None, CJ0=None, M=None, VJ=None, FC=None, CP=None, TT=None, BV=None, IBV=None, KF=None, AF=None, FFE=None, TEMP=None, XTI=None, EG=None, TBV=None, TRS=None, TTT1=None, TTT2=None, TM1=None, TM2=None): self.name = name self.IS = float(IS) if IS is not None else IS_DEFAULT self.N = float(N) if N is not None else N_DEFAULT self.ISR = float(ISR) if ISR is not None else ISR_DEFAULT self.NR = float(NR) if NR is not None else NR_DEFAULT self.RS = float(RS) if RS is not None else RS_DEFAULT self.CJ0 = float(CJ0) if CJ0 is not None else CJ0_DEFAULT self.M = float(M) if M is not None else M_DEFAULT self.VJ = float(VJ) if VJ is not None else VJ_DEFAULT self.FC = float(FC) if FC is not None else FC_DEFAULT self.CP = float(CP) if CP is not None else CP_DEFAULT self.TT = float(TT) if TT is not None else TT_DEFAULT self.BV = float(BV) if BV is not None else BV_DEFAULT self.IBV = float(IBV) if IBV is not None else IBV_DEFAULT self.KF = float(KF) if KF is not None else KF_DEFAULT self.AF = float(AF) if AF is not None else AF_DEFAULT self.FFE = float(FFE) if FFE is not None else FFE_DEFAULT self.TEMP = utilities.Celsius2Kelvin( float(TEMP)) if TEMP is not None else TEMP_DEFAULT self.XTI = float(XTI) if XTI is not None else XTI_DEFAULT self.EG = float(EG) if EG is not None else EG_DEFAULT self.TBV = float(TBV) if TBV is not None else TBV_DEFAULT self.TRS = float(TRS) if TRS is not None else TRS_DEFAULT self.TTT1 = float(TTT1) if TTT1 is not None else TTT1_DEFAULT self.TTT2 = float(TTT2) if TTT2 is not None else TTT2_DEFAULT self.TM1 = float(TM1) if TM1 is not None else TM1_DEFAULT self.TM2 = float(TM2) if TM2 is not None else TM2_DEFAULT self.T = T_DEFAULT self.last_vd = None self.VT = constants.Vth(self.T)
def setup_scaling(self, nq, device): """Calculates and stores in self.scaling the following factors: Ut, the thermal voltage, Is, the specific current, Gs, the specific transconductance, Qs, the specific charge. """ self.scaling.Ut = constants.Vth() self.scaling.Is = 2 * nq * self.scaling.Ut**2 * self.KP * device.W / device.L self.scaling.Gs = 2 * nq * self.scaling.Ut * self.KP * device.W / device.L self.scaling.Qs = 2 * nq * self.scaling.Ut * self.COX return
def get_td(dx, locked_nodes, n=-1): """Calculates the damping coefficient for the Newthon method. The damping coefficient is choosen as the lowest between: - the damping required for the first NR iterations - the biggest factor that keeps the change in voltage above the locked nodes less than the max variation allowed (nl_voltages_lock_factor*Vth) Requires: dx - the undamped increment locked_nodes - a vector of tuples of nodes that are a port of a NL component n - the newthon iteration counter k - the maximum number of Vth allowed on a NL component Note: If n is set to -1 (or any negative value), td is independent from the iteration number. Returns: a float, the damping coefficient (td) """ if not options.nr_damp_first_iters or n < 0: td = 1 else: if n < 10: td = 1e-2 elif n < 20: td = 0.1 else: td = 1 td_new = 1 if options.nl_voltages_lock: for (n1, n2) in locked_nodes: if n1 != 0: if n2 != 0: if abs( dx[n1 - 1, 0] - dx[n2 - 1, 0] ) > options.nl_voltages_lock_factor * constants.Vth(): td_new = (options.nl_voltages_lock_factor * constants.Vth()) / abs(dx[n1 - 1, 0] - dx[n2 - 1, 0]) else: if abs( dx[n1 - 1, 0] ) > options.nl_voltages_lock_factor * constants.Vth(): td_new = (options.nl_voltages_lock_factor * constants.Vth()) / abs(dx[n1 - 1, 0]) else: if abs(dx[n2 - 1, 0] ) > options.nl_voltages_lock_factor * constants.Vth(): td_new = (options.nl_voltages_lock_factor * constants.Vth()) / abs(dx[n2 - 1, 0]) if td_new < td: td = td_new return td
def update_status_dictionary(self, ports_v): if self.opdict is None: self.opdict = {} if not (self.opdict['state'] == ports_v[0] and self.opdict.has_key('gmd')) or \ not (self.opdict['state'] == ports_v[0] and self.opdict.has_key('gmg')) or \ not (self.opdict['state'] == ports_v[0] and self.opdict.has_key('gms')) or \ not (self.opdict['state'] == ports_v[0] and self.opdict.has_key('Ids')): self.opdict['state'] == ports_v[0] self.opdict['gmd'] = self.g(0, ports_v[0], 0) self.opdict['gmg'] = self.g(0, ports_v[0], 1) self.opdict['gms'] = self.g(0, ports_v[0], 2) self.opdict['Ids'] = self.i(0, ports_v[0]) gmd = self.opdict['gmd'] gmg = self.opdict['gmg'] gms = self.opdict['gms'] ids = self.opdict['Ids'] if ids == 0: TEF = float('nan') else: TEF = abs(gms * constants.Vth() / ids) self.opdict['TEF'] = TEF
def __init__(self, name=None, TYPE='n', TNOM=None, COX=None, \ GAMMA=None, NSUB=None, PHI=None, VTO=None, KP=None, \ LAMBDA=None, AKP=None, AVT=None,\ TOX=None, VFB=None, U0=None, TCV=None, BEX=None): self.scaling = scaling_holder() self.name = "model_mosq0" if name is None else name Vth = constants.Vth() self.TNOM = float(TNOM) if TNOM is not None else constants.Tref #print "TYPE IS:" + TYPE self.NPMOS = 1 if TYPE == 'n' else -1 # optional parameters (no defaults) self.TOX = float(TOX) if TOX is not None else None self.NSUB = float(NSUB) if NSUB is not None else None self.VFB = self.NPMOS * float(VFB) if VFB is not None else None self.U0 = float(U0) if U0 is not None else None # crucial parameters if COX is not None: self.COX = float(COX) elif TOX is not None: self.COX = constants.si.eox / TOX else: self.COX = COX_DEFAULT if GAMMA is not None: self.GAMMA = float(GAMMA) elif NSUB is not None: self.GAMMA = math.sqrt(2 * constants.e * constants.si.esi * NSUB * 10**6 / self.COX) else: self.GAMMA = GAMMA_DEFAULT if PHI is not None: self.PHI = float(PHI) elif NSUB is not None: self.PHI = 2 * constants.Vth(self.TNOM) * math.log( NSUB * 10**6 / constants.si.ni(self.TNOM)) else: self.PHI = PHI_DEFAULT if VTO is not None: self.VTO = self.NPMOS * float(VTO) if self.VTO < 0: print "(W): model %s has internal negative VTO (%f V)." % ( self.name, self.VTO) elif VFB is not None: self.VTO = VFB + PHI + GAMMA * PHI #inv here?? else: self.VTO = self.NPMOS * VTO_DEFAULT if KP is not None: self.KP = float(KP) elif U0 is not None: self.KP = (U0 * 10**-4) * self.COX else: self.KP = KP_DEFAULT self.LAMBDA = LAMBDA if LAMBDA is not None else LAMBDA_DEFAULT # Intrinsic model temperature parameters self.TCV = self.NPMOS * float( TCV) if TCV is not None else self.NPMOS * TCV_DEFAULT self.BEX = float(BEX) if BEX is not None else BEX_DEFAULT # Monte carlo self.AVT = AVT if AVT is not None else AVT_DEFAULT self.AKP = AKP if AKP is not None else AKP_DEFAULT self.set_device_temperature(constants.T) sc, sc_reason = self._self_check() if not sc: raise Exception, sc_reason + " out of range"
def get_ip_abs_err(self, device): """Absolute error to be enforced in the calculation of the normalized currents. """ return options.iea / (2.0 * constants.Vth(self.TEMP)**2.0 * self.KP * device.M * device.W / device.L)
def __init__(self, name=None, TYPE='n', TNOM=None, COX=None, GAMMA=None, NSUB=None, PHI=None, VTO=None, KP=None, XJ=None, LAMBDA=None, TOX=None, VFB=None, U0=None, TCV=None, BEX=None): self.scaling = scaling_holder() self.name = "model_ekv0" if name is None else name self.TNOM = float(TNOM) if TNOM is not None else constants.Tref self.NPMOS = 1 if TYPE == 'n' else -1 # optional parameters (no defaults) self.TOX = float(TOX) if TOX is not None else None self.NSUB = float(NSUB) if NSUB is not None else None self.VFB = self.NPMOS * float(VFB) if VFB is not None else None self.U0 = float(U0) if U0 is not None else None # crucial parameters if COX is not None: self.COX = float(COX) elif TOX is not None: self.COX = constants.si.eox / TOX else: self.COX = COX_DEFAULT if GAMMA is not None: self.GAMMA = float(GAMMA) elif NSUB is not None: self.GAMMA = math.sqrt(2.0 * constants.e * constants.si.esi * NSUB * 10**6 / self.COX) else: self.GAMMA = GAMMA_DEFAULT if PHI is not None: self.PHI = float(PHI) elif NSUB is not None: self.PHI = 2. * constants.Vth(self.TNOM) * math.log( NSUB * 10.0**6.0 / constants.si.ni(self.TNOM)) else: self.PHI = PHI_DEFAULT if VTO is not None: self.VTO = self.NPMOS * float(VTO) if self.VTO < 0: print "(W): model %s has internal negative VTO (%f V)." % ( self.name, self.VTO) elif VFB is not None: self.VTO = VFB + PHI + GAMMA * PHI # inv here?? else: self.VTO = self.NPMOS * VTO_DEFAULT if KP is not None: self.KP = float(KP) elif U0 is not None: self.KP = (U0 * 10.0**-4) * self.COX else: self.KP = KP_DEFAULT self.LAMBDA = LAMBDA if LAMBDA is not None else LAMBDA_DEFAULT self.XJ = XJ if XJ is not None else XJ_DEFAULT self.UCRIT = UCRIT_DEFAULT # Intrinsic model temperature parameters self.TCV = self.NPMOS * \ float(TCV) if TCV is not None else self.NPMOS * TCV_DEFAULT self.BEX = float(BEX) if BEX is not None else BEX_DEFAULT self.set_device_temperature(constants.T) # Setup switches self.SATLIM = math.exp(4.0) self.WMSI_factor = 10 self.NR_damp_factor = options.nl_voltages_lock_factor sc, sc_reason = self._self_check() if not sc: raise Exception, sc_reason + " out of range"
WMSI = 0 else: WMSI = 1 opdict.update({'WMSI': WMSI}) if debug: print "current:", Ids return Ids, qf, qr def get_leq_virp(self, device, (vd, vg, vs), Vp, Leff, ifn): # if ifn > 0 and Vp - constants.Vth()*vd > 0: assert vd >= vs Vc = self.UCRIT * device.N * Leff Vdss = Vc * \ (math.sqrt(.25 + constants.Vth() / Vc * math.sqrt(ifn)) - .5) # eq. 46 # Drain-to-source saturation voltage for reverse normalized current, # eq. 47 Vdssp = Vc * (math.sqrt(.25 + constants.Vth() / Vc * (math.sqrt(ifn) - .75 * math.log(ifn))) - .5) + \ constants.Vth() * (math.log(.5 * Vc / constants.Vth()) - .6) # channel length modulation vser_1 = math.sqrt(ifn) - Vdss / constants.Vth() # if vser_1 < 0: # vser_1 = 0 Vds = (vd - vs) * .5 * constants.Vth() delta_v = 4.0 * constants.Vth() * math.sqrt( self.LAMBDA * vser_1 + 1.0 / 64) # eq. 48 Vip = math.sqrt(Vdss**2 + delta_v**2) - math.sqrt( (Vds - Vdss)**2 + delta_v**2) # eq 50