Example #1
0
    def __init__(self, iNode, pwrNode, gndNode, model, speed=Typical):
        """
		Arguments:
		iNode -- Input Node
		pwrNode -- Vcc Node
		gndNode -- Ground Node
		model -- IbisModel
		speed -- (optional) Maximum, Minimum, Typical, default = Typical
		"""

        self.__dict__['model'] = model
        self.__dict__['speed'] = speed

        if hasattr(model, 'c_comp'):
            self.C_comp = device.C(iNode, gndNode, model.c_comp[speed])
        if hasattr(model, 'gnd_clamp'):
            self.VI_gnd = device.VI(iNode, gndNode,
                                    waveform.PWL(model.gnd_clamp[speed]))
        if hasattr(model, 'power_clamp'):
            self.VI_pwr = device.VI(pwrNode, iNode,
                                    waveform.PWL(model.power_clamp[speed]))
Example #2
0
    def __setattr__(self, name, value):

        if ((name == 'model') or (name == 'speed')):
            if hasattr(self.model, 'c_comp'):
                if hasattr(self, 'C_comp'):
                    self.C_comp.C = self.model.c_comp[self.speed]
                else:
                    raise RuntimeError, "Can't add C_comp"
            if hasattr(self.model, 'gnd_clamp'):
                if hasattr(self, 'VI_gnd'):
                    self.VI_gnd.VI = waveform.PWL(
                        self.model.gnd_clamp[self.speed])
                else:
                    raise RuntimeError, "Can't add VI_gnd"
            if hasattr(self.model, 'power_clamp'):
                if hasattr(self, 'VI_pwr'):
                    self.VI_pwr.VI = waveform.PWL(
                        self.model.power_clamp[self.speed])
                else:
                    raise RuntimeError, "Can't add VI_pwr"
        else:
            subckt.Subckt.__setattr__(self, name, value)
Example #3
0
    def __init__(self,
                 oNode,
                 pwrNode,
                 gndNode,
                 model,
                 speed=Typical,
                 direction=Rising):
        """
		Arguments:
		oNode -- Output Node
		pwrNode -- Vcc Node
		gndNode -- Ground Node
		model -- IbisModel
		speed -- (optional) Maximum, Minimum, or Typical, default = Typical
		direction -- (optional) Rising or Falling, default = Rising
		"""

        self.__dict__['model'] = model
        self.__dict__['speed'] = speed
        self.__dict__['direction'] = direction

        if hasattr(model, 'c_comp'):
            self.C_comp = device.C(oNode, gndNode, model.c_comp[speed])
        if hasattr(model, 'gnd_clamp'):
            self.VI_gnd = device.VI(oNode, gndNode,
                                    waveform.PWL(model.gnd_clamp[speed]))
        if hasattr(model, 'power_clamp'):
            self.VI_pwr = device.VI(pwrNode, oNode,
                                    waveform.PWL(model.power_clamp[speed]))
        if hasattr(model, 'pullup'):
            self.VI_pu = device.VI(
                pwrNode, oNode, waveform.PWL(model.pullup[speed]),
                waveform.PWL(model.pullup_k[direction][speed]))
        if hasattr(model, 'pulldown'):
            self.VI_pd = device.VI(
                oNode, gndNode, waveform.PWL(model.pulldown[speed]),
                waveform.PWL(model.pulldown_k[direction][speed]))
Example #4
0
    def __setattr__(self, name, value):

        if ((name == 'model') or (name == 'speed') or (name == 'direction')):
            if hasattr(self.model, 'C_comp'):
                if hasattr(self, 'C_comp'):
                    self.C_comp.C = self.model.c_comp[self.speed]
                else:
                    raise RuntimeError, "Can't add C_comp"
            if hasattr(self.model, 'gnd_clamp'):
                if hasattr(self, 'VI_gnd'):
                    self.VI_gnd.VI = waveform.PWL(
                        self.model.gnd_clamp[self.speed])
                else:
                    raise RuntimeError, "Can't add VI_gnd"
            if hasattr(self.model, 'power_clamp'):
                if hasattr(self, 'VI_pwr'):
                    self.VI_pwr.VI = waveform.PWL(
                        self.model.power_clamp[self.speed])
                else:
                    raise RuntimeError, "Can't add VI_pwr"
            if hasattr(self.model, 'pullup'):
                if hasattr(self, 'VI_pu'):
                    self.VI_pu.VI = waveform.PWL(self.model.pullup[self.speed])
                    self.VI_pu.TA = waveform.PWL(
                        self.model.pullup_k[self.direction][self.speed])
                else:
                    raise RuntimeError, "Can't add VI_pu"
            if hasattr(self.model, 'pulldown'):
                if hasattr(self, 'VI_pd'):
                    self.VI_pd.VI = waveform.PWL(
                        self.model.pulldown[self.speed])
                    self.VI_pd.TA = waveform.PWL(
                        self.model.pulldown_k[self.direction][self.speed])
                else:
                    raise RuntimeError, "Can't add VI_pd"
        else:
            subckt.Subckt.__setattr__(self, name, value)
Example #5
0
def calcDriverKDoubleWave(model, direction, speed, tstepDivisor=10):
    """
	Calculates a Time/Multiplier (TA) Table using 2 Waveforms
	
	Arguments:
	model -- IBIS Model Class
	direction -- either Rising or Falling (constants defined above)
	speed -- either Typical, Maximum, or Minimum (constants defined above)
	tstepDivisor -- Number of simulation points between defined waveform
		points, a larger number may yeild a more accurate result but will
		take longer to process.
	
	Returns:
	(ku, kd) -- two 2D Arrays, the first column in each is time and the
	second is either the up (ku) or down (kd) VI Multiplier
	
	To create an IBIS Defined Driver Model that changes state the Driver's 
	two VI Tables (Pull-Up and Pull-Down) are modified during the simulation
	by multiplying them	at each time step with values from the TA Tables.
	
	This method of calculating a Driver TA Table is the most accuarate.
	It uses two provided Waveforms driven into two different loads. This
	function uses the eispice simulation engine to simulate two instanciations
	of the follow circuit:

            VCC                             VCC
             +                               +
             |                               |  Power Clamp IV
            .-. Pull-Up IV                  .-. (Xcu0/1)
            | | (Xpu0/1)                    | |
            | |                             | |       Vfixture
   .-----.  '-'       _ Current Probe       '-'          +
   |  G  |   |       / \ (Vmeas)             |     ___   |
   |_-_-_|----------(_/_)--------o-----------o----|___|--o
   |     |   |       \_/         |           |  Rfixture
   '-----'  .-.                  |          .-.
  Waveform  | | Pull-Down IV    --- C_comp  | | Ground Clamp IV
  (Xwv0/1)  | | (Xpd0/1)        --- (Cc0/1) | | (Xcd0/1)
            '-'                  |          '-'
             |                   |           |
            ===                 ===         ===
            GND                 GND         GND

	The value of the two multipliers (ku and ku) are calculated at
	each time step using a two B-Elements, based on the folowing relationships:
	
	Imeas0 = ku*Ipu0 - kd*Ipd0 (1)
	Imeas1 = ku*Ipu1 - kd*Ipd1 (2)
	
	Solving (1) for ku:
	
	     Imeas0 - kd*Ipd0
	ku = ----------------- (3)
			   Ipu0
			   
	Substitute into (2) and solving results in:
	
	     Imeas0*Ipu1 - Imeas1*Ipu0
	kd = ------------------------- (4)
		   Ipd1*Ipu0 - Ipd0*Ipu1
	
	To limit calculation error the paired releationship is used to
	calculate ku, not (3):
	
	     Imeas0*Ipd1 - Imeas1*Ipd0
	ku = ------------------------- (5)
		   Ipd1*Ipu0 - Ipd0*Ipu1
	
	"""

    if direction == Rising:
        wave = model.rising_waveform
    elif direction == Falling:
        wave = model.falling_waveform
    else:
        raise RuntimeError, 'Direction must be Rising or Falling.'

    # Based on the schematic defined above
    cct = circuit.Circuit("Double Waveform")

    # ----------------------- Waveform 0 -----------------------------------
    cct.Vcc = device.V('vcc', 0, model.voltage_range[speed])
    cct.Xwv0 = device.V('wv0', 0, 0, waveform.PWL(wave[0].data[speed]))
    cct.Xpu0 = device.VI('vcc', 'wv0', waveform.PWL(model.pullup[speed]))
    cct.Xpd0 = device.VI('wv0', 0, waveform.PWL(model.pulldown[speed]))
    cct.Vmeas0 = device.V('wv0', 'ts0', 0)
    cct.Cc0 = device.C('ts0', 0, model.c_comp[speed])
    cct.Rfix0 = device.R('ts0', 'fix0', wave[0].r_fixture)
    if speed == Typical:
        cct.Vfix0 = device.V('fix0', 0, wave[0].v_fixture)
    elif speed == Maximum:
        try:
            cct.Vfix0 = device.V('fix0', 0, wave[0].v_fixture_min)
        except AttributeError:
            cct.Vfix0 = device.V('fix0', 0, wave[0].v_fixture)
    elif speed == Minimum:
        try:
            cct.Vfix0 = device.V('fix0', 0, wave[0].v_fixture_max)
        except AttributeError:
            cct.Vfix0 = device.V('fix0', 0, wave[0].v_fixture)
    # May not have GND and/or Power Clamps
    if hasattr(model, 'power_clamp'):
        cct.Xcu0 = device.VI('vcc', 'ts0',
                             waveform.PWL(model.power_clamp[speed]))
    if hasattr(model, 'gnd_clamp'):
        cct.Xcd0 = device.VI('ts0', 0, waveform.PWL(model.gnd_clamp[speed]))

    # ----------------------- Waveform 1 -----------------------------------
    cct.Xwv1 = device.V('wv1', 0, 0, waveform.PWL(wave[1].data[speed]))
    cct.Xpu1 = device.VI('vcc', 'wv1', waveform.PWL(model.pullup[speed]))
    cct.Xpd1 = device.VI('wv1', 0, waveform.PWL(model.pulldown[speed]))
    cct.Vmeas1 = device.V('wv1', 'ts1', 0)
    cct.Cc1 = device.C('ts1', 0, model.c_comp[speed])
    cct.Rfix1 = device.R('ts1', 'fix1', wave[1].r_fixture)
    if speed == Typical:
        cct.Vfix1 = device.V('fix1', 0, wave[1].v_fixture)
    elif speed == Maximum:
        try:
            cct.Vfix1 = device.V('fix1', 0, wave[1].v_fixture_min)
        except AttributeError:
            cct.Vfix1 = device.V('fix1', 0, wave[1].v_fixture)
    elif speed == Minimum:
        try:
            cct.Vfix1 = device.V('fix1', 0, wave[1].v_fixture_max)
        except AttributeError:
            cct.Vfix1 = device.V('fix1', 0, wave[1].v_fixture)
    # May not have GND and/or Power Clamps
    if hasattr(model, 'power_clamp'):
        cct.Xcu1 = device.VI('vcc', 'ts1',
                             waveform.PWL(model.power_clamp[speed]))
    if hasattr(model, 'gnd_clamp'):
        cct.Xcd1 = device.VI('ts1', 0, waveform.PWL(model.gnd_clamp[speed]))

    # ------------------ Multiplier Calculator -----------------------------
    # Equation (4)
    cct.Bkdn = device.B(
        'kd', 0, 'v', "(i(Xpu0)*i(Vmeas1) - i(Xpu1)*i(Vmeas0))"
        "/ (i(Xpd0)*i(Xpu1) - i(Xpd1)*i(Xpu0))")
    # Equation (5)
    cct.Bkun = device.B(
        'ku', 0, 'v', "(i(Xpd0)*i(Vmeas1) - i(Xpd1)*i(Vmeas0))"
        "/ (i(Xpd0)*i(Xpu1) - i(Xpd1)*i(Xpu0))")

    # The simulation length is based on the last time point from the longest
    # defined waverform.
    tstop0 = wave[0].data[speed][wave[0].data[speed].shape[0] - 1][0]
    tstop1 = wave[1].data[speed][wave[1].data[speed].shape[0] - 1][0]
    tstop = max(tstop0, tstop1)

    # The simulation step length is based on the shortest step between points
    # 0 and 1.
    tstep0 = wave[0].data[speed][1][0] - wave[0].data[speed][0][0]
    tstep1 = wave[1].data[speed][1][0] - wave[1].data[speed][0][0]
    tstep = min(tstep0, tstep1)

    # Run the simulations
    cct.tran(tstep / tstepDivisor, tstop)

    # Only need the results for ku and kd
    # TODO: Could filter out the time points that aren't on
    # the orginal waveform list to save some memory.
    ku = cct.voltage_array('ku')[1::]  # remove the first point
    kd = cct.voltage_array('kd')[1::]  # remove the first point

    return (ku, kd)
Example #6
0
def calcDriverKRamp(model, direction, speed, tstepDivisor=10):
    """
	Calculates a Time/Multiplier (TA) Table using 1 Waveform
	
	Arguments:
	model -- IBIS Model Class
	direction -- either Rising or Falling (constants defined above)
	speed -- either Typ, Max, or Min (constants defined above)
	tstepDivisor -- Number of simulation points between defined waveform
		points, a larger number may yeild a more accurate result but will
		take longer to process.
	
	Returns:
	(ku, kd) -- two 2D Arrays, the first column in each is time and the
	second is either the up (ku) or down (kd) VI Multiplier
	
	Refer to calcDriverKDoubleWave for a general description of the TA Table
	creation process. This function uses the ramp data and interpolates
	a gaussina rising edge from it to use as a wavefrom example. It is
	less accurate as a result but unfortunatally there aren't always 2 
	waveformes provided in an IBIS Model.
	
	Since there is only a single defined waveform equations (4) and (5) have
	to be modified:
	
	Imeas = ku*Ipu - kd*Ipd + Ifix(1)
	ku - kd = 1 (2)
	
	Solving (1) for ku:
	    
	ku = 1 + kd (3)
	   
	Substitute into (2) and solving results in:
	
	     Imeas - Ipu - Ifix
	kd = ------------------ (4)
		      Ipu - Ipd
	
	To limit calculation error the paired releationship is used to
	calculate ku, not (3):
	
	     Imeas - Ipd - Ifx
	ku = ------------------ (5)
		      Ipu - Ipd
	
	"""

    warnings.warn(
        'IBIS Driver Model based on Ramp Specs only, will have poor accuracy')

    #~ vol = model.voltage_range[speed] - model.ramp.dv_r[speed]/0.6
    vol = 0.0
    #~ voh = model.ramp.dv_r[speed]/0.6
    voh = model.voltage_range[speed]

    if direction == Rising:
        ramp = model.ramp.dt_r[speed]
        wave = waveform.Gauss(vol, voh, 0, ramp)
    elif direction == Falling:
        ramp = model.ramp.dt_f[speed]
        wave = waveform.Gauss(voh, vol, 0, ramp)
    else:
        raise RuntimeError, 'Direction must be Rising or Falling.'

    # Based on the schematic defined above
    cct = circuit.Circuit("Ramp")

    # ----------------------- Waveform -------------------------------------
    cct.Vcc = device.V('vcc', 0, model.voltage_range[speed])
    cct.Xwv = device.V('wv', 0, 0, wave)
    cct.Xpu = device.VI('vcc', 'wv', waveform.PWL(model.pullup[speed]))
    cct.Xpd = device.VI('wv', 0, waveform.PWL(model.pulldown[speed]))
    cct.Vmeas = device.V('wv', 'ts', 0)
    cct.Cc = device.C('ts', 0, model.c_comp[speed])
    cct.Rfix = device.R('ts', 'fix', model.ramp.r_load)
    if direction == Rising:
        cct.Vfix = device.V('fix', 0, 0.0)
    elif direction == Falling:
        cct.Vfix = device.V('fix', 0, model.voltage_range[speed])
    # May not have GND and/or Power Clamps
    if hasattr(model, 'power_clamp'):
        cct.Xcu = device.VI('vcc', 'ts',
                            waveform.PWL(model.power_clamp[speed]))
    if hasattr(model, 'gnd_clamp'):
        cct.Xcd = device.VI('ts', 0, waveform.PWL(model.gnd_clamp[speed]))

    # ------------------ Multiplier Calculator -----------------------------
    # Equation (4)
    cct.Bkdn = device.B('kd', 0, 'v', "(i(Vmeas) - i(Xpu) - i(Vfix))"
                        "/ (i(Xpd) - i(Xpu))")
    # Equation (5)
    cct.Bkun = device.B('ku', 0, 'v', "(i(Vmeas) - i(Xpd) - i(Vfix))"
                        "/ (i(Xpd) - i(Xpu))")

    # The simulation length is based on the last time point of the waveform
    tstop = ramp * 4

    # The simulation step length is based on the step between points 0 and 1.
    tstep = ramp * 0.5

    # Run the simulations
    cct.tran(tstep / tstepDivisor, tstop)

    # Only need the results for ku and kd
    # TODO: Could filter out the time points that aren't on
    # the orginal waveform list to save some memory.
    ku = cct.voltage_array('ku')[1::]  # remove the first point
    kd = cct.voltage_array('kd')[1::]  # remove the first point

    #~ if direction == Rising and speed == Typical:
    #~ import plot
    #~ plot.plot(cct)

    return (ku, kd)