def hysteresis_threshold_ratios_opendrain(r1, r2, rh): """ Same as hysteresis_threshold_ratios(), but for open-drain comparators. In contrast to hysteresis_threshold_ratios(), ignores rh for the upper threshold. Parameters ---------- r1 : float or EngineerIO string The top resistor of the divider r2 : float or EngineerIO string The bottom resistor of the divider rh : float or EngineerIO string The hysteresis resistor of the divider """ # Normalize inputs r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rh = normalize_numeric(rh) # Compute r1, r2 in parallel with rh r2rh = parallel_resistors(r2, rh) # Compute thresholds thl = unloaded_ratio(r1, r2rh) thu = unloaded_ratio(r1, r2) return (thl, thu)
def load_capacitors(cload, cpin="3 pF", cstray="2 pF") -> Unit("F"): """ Compute the load capacitors which should be used for a given crystal, given that the load capacitors should be symmetric (i.e. have the same value). NOTE: You need to use a stray capacitance value that does NOT include the parasitic pin capacitance! Based on (C1 * C2) / (C1 + C2) + Cstray for C1 == C2 == (returned value) + cpin >>> auto_format(load_capacitors, "6 pF", cpin="3 pF", cstray="2pF") '5.00 pF' Parameters ---------- cload : float The load capacitance as given in the crystal datasheet cstray : float The stray capacitance cpin : float The capacitance of one of the oscillator pins of the connected device """ cload = normalize_numeric(cload) cstray = normalize_numeric(cstray) cpin = normalize_numeric(cpin) # cload = (C1 * C2) / (C1 + C2) + Cstray where C1 == C2 # => solve A = (B*B) / (B+B) + C for B # => solve A = ((B+P)*(B+P)) / ((B+P)+(B+P)) + C for B return (2 * (cload - cstray)) - cpin
def capacitive_reactance(c, f=1000.0) -> Unit("Ω"): """ Compute the capacitive reactance for a given capacitance and frequency. """ c = normalize_numeric(c) f = normalize_numeric(f) return 1.0 / (2 * np.pi * f * c)
def hysteresis_threshold_ratios_opendrain(r1, r2, rh): """ Same as hysteresis_threshold_ratios(), but for open-drain comparators. In contrast to hysteresis_threshold_ratios(), ignores rh for the upper threshold. Parameters ---------- r1 : float or EngineerIO string The top resistor of the divider r2 : float or EngineerIO string The bottom resistor of the divider rh : float or EngineerIO string The hysteresis resistor of the divider """ # Normalize inputs r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rh = normalize_numeric(rh) # Compute r1, r2 in parallel with rh r2rh = parallel_resistors(r2, rh) # Compute thresholds thl = voltage_divider_ratio(r1, r2rh) thu = voltage_divider_ratio(r1, r2) return (thl, thu)
def inductive_reactance(l, f=1000.0) -> Unit("Ω"): """ Compute the inductive reactance for a given inductance and frequency. """ l = normalize_numeric(l) f = normalize_numeric(f) return 2 * np.pi * f * l
def normalize_minmax_tuple(arg, name="field"): """ Interprets arg either a single +- value or as a 2-tuple of + and - values. All vaues If arg is a tuple: Return ValueRange(arg[0], arg[1]) (strings are normalized) Else: Return ValueRange(-arg, +arg) (strings are normalized) name is for debugging purposes and shown in the exception string """ # Parse coefficient and compute min & max factors if isinstance(arg, tuple): # Check length 2 if len(arg) != 2: raise ValueError( "If {} is given as a tuple, it must have length 2. {} is {}". format(name, name, arg)) # Parse tuple min_value = normalize_numeric(arg[0]) max_value = normalize_numeric(arg[1]) else: arg = normalize_numeric(arg) min_value = -arg max_value = arg return ValueRange(min_value, max_value)
def actual_load_capacitance(cext, cpin="3 pF", cstray="2 pF") -> Unit("F"): """ Compute the actual load capacitance of a crystal given: - The external capacitance value (use "10 pF" if your have a 10 pF capacitor on each of the crystal pins) - The parasitic pin capacitance The value returned should match the load capacitance value in the crystal datasheet. Based on (C1 * C2) / (C1 + C2) + Cstray If yu use a >>> auto_format(actual_load_capacitance, "5 pF", cpin="3 pF", cstray="2pF") '6.00 pF' Parameters ---------- cext : float The load capacitor value cstray : float The stray capacitance cpin : float The capacitance of one of the oscillator pins of the connected device """ cext = normalize_numeric(cext) cstray = normalize_numeric(cstray) cpin = normalize_numeric(cpin) # cload = (C1 * C2) / (C1 + C2) + Cstray where C1 == C2 # => solve A = (B*B) / (B+B) + C for B # => solve A = ((B+P)*(B+P)) / ((B+P)+(B+P)) + C for B ctotal = cext + cpin return cstray + ((ctotal * ctotal) / (ctotal + ctotal))
def cylinder_surface_area(radius, height) -> Unit("m²"): """ Compute the surface area (side + top + bottom) """ radius = normalize_numeric(radius) height = normalize_numeric(height) return cylinder_side_surface_area(radius, height) + 2 * circle_area(radius)
def cylinder_side_surface_area(radius, height) -> Unit("m²"): """ Compute the surface area of the side (also called ") """ radius = normalize_numeric(radius) height = normalize_numeric(height) return 2 * math.pi * radius * height
def cylinder_volume(radius, height) -> Unit("m³"): """ Compute the volume of a cylinder by its radius and height """ radius = normalize_numeric(radius) height = normalize_numeric(height) return math.pi * (radius**2) * height
def top_resistor_by_ratio(rbottom, ratio) -> Unit("Ω"): """ Compute the bottom resistor of a voltage divider given the top resistor value and the division ration """ rbottom = normalize_numeric(rbottom) ratio = normalize_numeric(ratio) return rbottom * (1.0 / ratio - 1.0)
def unloaded_ratio(r1, r2) -> Unit(""): """ Compute the denominator of the division ratio of a voltage divider, not taking into account parasitic properties or loading """ r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) return r2 / (r1 + r2)
def unloaded_ratio(r1, r2) -> Quantity(""): """ Compute the denominator of the division ratio of a voltage divider, not taking into account parasitic properties or loading """ r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) return r2 / (r1 + r2)
def bottom_resistor_by_ratio(rtop, ratio) -> Quantity("Ω"): """ Compute the bottom resistor of a voltage divider given the top resistor value and the division ration """ rtop = normalize_numeric(rtop) ratio = normalize_numeric(ratio) return -(rtop * ratio) / (ratio - 1.0)
def current_by_power(power="25 W", voltage="230 V") -> Unit("A"): """ Given a device's power (or RMS power) and the voltage (or RMS voltage) it runs on, compute how much current it will draw. """ power = normalize_numeric(power) voltage = normalize_numeric(voltage) return power / voltage
def resistor_by_voltage_and_current(voltage, current) -> Unit("Ω"): """ Compute the resistance value in Ohms that draws the given amount of current if the given voltage is across it. """ voltage = normalize_numeric(voltage) current = normalize_numeric(current) return voltage / current
def bottom_resistor_by_ratio(rtop, ratio) -> Unit("Ω"): """ Compute the bottom resistor of a voltage divider given the top resistor value and the division ration """ rtop = normalize_numeric(rtop) ratio = normalize_numeric(ratio) return -(rtop * ratio) / (ratio - 1.0)
def top_resistor_by_ratio(rbottom, ratio) -> Quantity("Ω"): """ Compute the bottom resistor of a voltage divider given the top resistor value and the division ration """ rbottom = normalize_numeric(rbottom) ratio = normalize_numeric(ratio) return rbottom * (1.0 / ratio - 1.0)
def loaded_ratio(r1, r2, rl) -> Unit(""): """ Compute the denominator of the division ratio of a voltage divider, not taking into account parasitic properties but loading. """ r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rl = normalize_numeric(rl) return r1 / (r1 + parallel_resistors(r2, rl))
def power_by_current_and_voltage(current="1.0 A", voltage="230 V") -> Unit("W"): """ Given a device's current (or RMS current) and the voltage (or RMS current) it runs on, compute its power """ current = normalize_numeric(current) voltage = normalize_numeric(voltage) return current * voltage
def centrifugal_force(radius: Unit("m"), speed: Unit("Hz"), mass: Unit("g")) -> Unit("N"): """ Compute the centrifugal force of a [mass] rotation at [speed] at radius [radius] """ radius = normalize_numeric(radius) mass = normalize_numeric( mass) / 1000.0 # mass needs to be Kilograms TODO Improve return mass * angular_speed(speed)**2 * radius
def voltage_divider_ratio(rtop, rbot, rload=np.inf) -> Unit(""): """ Compute the division ratio of a voltage divider. If rload is supplied, additional load (in parallel to R2) is taken into account. """ rtop = normalize_numeric(rtop) rbot = normalize_numeric(rbot) return rbot / (rtop + parallel_resistors(rbot, rload))
def loaded_ratio(r1, r2, rl) -> Quantity(""): """ Compute the denominator of the division ratio of a voltage divider, not taking into account parasitic properties but loading. """ r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rl = normalize_numeric(rl) return r1 / (r1 + parallel_resistors(r2, rl))
def capacitor_charge(capacitance, voltage) -> Unit("C"): """ Compute the total charge stored in a capacitor given: - The capacitance in farads - The voltage the capacitor is charged to The charge is returned in coulombs. """ capacitance = normalize_numeric(capacitance) voltage = normalize_numeric(voltage) return capacitance * voltage
def capacitor_charge(capacitance, voltage) -> Quantity("C"): """ Compute the total charge stored in a capacitor given: - The capacitance in farads - The voltage the capacitor is charged to The charge is returned in coulombs. """ capacitance = normalize_numeric(capacitance) voltage = normalize_numeric(voltage) return capacitance * voltage
def capacitor_energy(capacitance, voltage) -> Unit("J"): """ Compute the total energy stored in a capacitor given: - The capacitance in farads - The voltage the capacitor is charged to The energy is returned as joules. """ capacitance = normalize_numeric(capacitance) voltage = normalize_numeric(voltage) return 0.5 * capacitance * np.square(voltage)
def johnson_nyquist_noise_voltage(r, delta_f, T) -> Quantity("V"): """ Compute the Johnson Nyquist noise current in amperes T must be given in °C whereas r must be given in Ohms. The result is given in volts """ r = normalize_numeric(r) delta_f = normalize_numeric(delta_f) t_kelvin = normalize_temperature(T) return math.sqrt(4 * scipy.constants.k * t_kelvin * delta_f * r)
def capacitor_energy(capacitance, voltage) -> Quantity("J"): """ Compute the total energy stored in a capacitor given: - The capacitance in farads - The voltage the capacitor is charged to The energy is returned as joules. """ capacitance = normalize_numeric(capacitance) voltage = normalize_numeric(voltage) return 0.5 * capacitance * np.square(voltage)
def johnson_nyquist_noise_voltage(r, delta_f, T) -> Unit("V"): """ Compute the Johnson Nyquist noise voltage in volts T must be given in °C whereas r must be given in Ohms. The result is given in volts """ r = normalize_numeric(r) delta_f = normalize_numeric(delta_f) t_kelvin = normalize_temperature(T) return math.sqrt(4 * boltzmann_k * t_kelvin * delta_f * r)
def temperature_with_dissipation(power_dissipated="1 W", theta="50 °C/W", t_ambient="25 °C") -> Unit("°C"): """ Compute the temperature of a component, given its thermal resistance (theta), its dissipated power and """ power_dissipated = normalize_numeric(power_dissipated) theta = normalize_numeric(theta) t_ambient = normalize_temperature_celsius(t_ambient) return t_ambient + power_dissipated * theta
def __hysteresis_threshold_factors(r1, r2, rh, fn): """Internal push-pull & open-drain common code""" # Normalize inputs r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rh = normalize_numeric(rh) # Compute thresholds thl, thu = fn(r1, r2, rh) # Compute factors thnom = voltage_divider_ratio(r1, r2) return (thl / thnom, thu / thnom)
def __hysteresis_threshold_factors(r1, r2, rh, fn): """Internal push-pull & open-drain common code""" # Normalize inputs r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rh = normalize_numeric(rh) # Compute thresholds thl, thu = fn(r1, r2, rh) # Compute factors thnom = unloaded_ratio(r1, r2) return (thl / thnom, thu / thnom)
def johnson_nyquist_noise_current(r, delta_f, T) -> Unit("A"): """ Compute the Johnson Nyquist noise current in amperes T must be given in °C whereas r must be given in Ohms. The result is given in volts """ r = normalize_numeric(r) delta_f = normalize_numeric(delta_f) t_kelvin = normalize_temperature(T) # Support celsius and kelvin inputs return math.sqrt((4 * boltzmann_k * t_kelvin * delta_f)/r)
def actualNoise(density, bandwith) -> Unit("V"): """ Compute the actual noise given: - A noise density in x/√Hz where x is any unit - A bandwith in ΔHz >>> autoFormat(actualNoise, "100 µV", "100 Hz") '1.00 mV' """ density = normalize_numeric(density) bandwith = normalize_numeric(bandwith) return np.sqrt(bandwith) * density
def actualNoise(density, bandwith) -> Quantity("V"): """ Compute the actual noise given: - A noise density in x/√Hz where x is any unit - A bandwith in ΔHz >>> autoFormat(actualNoise, "100 µV", "100 Hz") '1.00 mV' """ density = normalize_numeric(density) bandwith = normalize_numeric(bandwith) return np.sqrt(bandwith) * density
def noiseDensity(actual_noise, bandwith) -> Quantity("V/√Hz"): """ Compute the noise density given: - A noise density in x/√Hz where x is any unit - A bandwith in ΔHz >>> formatValue(noiseDensity("1.0 mV", "100 Hz"), "V/√Hz") '100 μV/√Hz' """ actual_noise = normalize_numeric(actual_noise) bandwith = normalize_numeric(bandwith) return actual_noise / np.sqrt(bandwith)
def noiseDensity(actual_noise, bandwith) -> Unit("V/√Hz"): """ Compute the noise density given: - A noise density in x/√Hz where x is any unit - A bandwith in ΔHz >>> formatValue(noiseDensity("1.0 mV", "100 Hz"), "V/√Hz") '100 μV/√Hz' """ actual_noise = normalize_numeric(actual_noise) bandwith = normalize_numeric(bandwith) return actual_noise / np.sqrt(bandwith)
def rotating_liquid_pressure(density: Unit("kg/m³"), speed: Unit("Hz"), radius: Unit("m")) -> Unit("Pa"): """ Compute the pressure in a body of liquid (relative to the steady-state pressure) The calculation does not include gravity. Also see https://www.youtube.com/watch?v=kIH7wEq3H-M Also see https://www.physicsforums.com/threads/pressure-of-a-rotating-bucket-of-liquid.38112/ """ density = normalize_numeric(density) speed = normalize_numeric(speed) radius = normalize_numeric(radius) return density * angular_speed(speed)**2 * radius**2
def voltage_divider_current(rtop, rbot, vin, rload=np.inf) -> Unit("V"): """ Compute the current through the top resistor of a voltage divider. If rload is supplied, additional load (in parallel to R2) is taken into account. """ vin = normalize_numeric(vin) rtop = normalize_numeric(rtop) vout = voltage_divider_voltage(rtop, rbot, vin, rload=rload) # Compute voltage delta across resistor vdelta = vout - vin # Compute current through resisotr return current_through_resistor(rtop, vdelta)
def _normalize_frequencies(freqs): # Normalize freqs: Allow [1.0] instead of 1.0 if freqs is None: raise ValueError("Critical frequencies may not be None") # Allow multiple frequencies, but only 1 or 2 if isinstance(freqs, collections.Iterable) and not isinstance(freqs, str): if len(freqs) == 0: raise ValueError("Empty frequency list") elif len(freqs) == 1: return normalize_numeric(freqs[0]) elif len(freqs) > 2: raise ValueError("No more than 2 critical frequencies allowed") return normalize_numeric(freqs)
def barlow_tangential(outer_diameter: Unit("m"), inner_diameter: Unit("m"), pressure: Unit("Pa")) -> Unit("Pa"): """ Compute the tangential stress of a pressure vessel at [pressure] using Barlow's formula for thin-walled tubes. Note that this formula only applies for (outer_diameter/inner_diameter) < 1.2 ! (this assumption is not checked). Otherwise, the stress distribution will be too uneven. """ outer_diameter = normalize_numeric(outer_diameter) inner_diameter = normalize_numeric(inner_diameter) pressure = normalize_numeric(pressure) dm = (outer_diameter + inner_diameter) / 2 s = (outer_diameter - inner_diameter) / 2 return pressure * dm / (2 * s)
def ptx_temperature(r0, r, standard=ptxITS90, poly=None) -> Quantity("°C"): """ Compute the PTx temperature at a given temperature. Accepts an additive correction polynomial that is applied to the resistance. If the poly kwarg is None, the polynom is automatically selected. noCorrection is used for other r0 values. In this case, use a custom polynomial (numpy poly1d object) as the poly kwarg. See http://www.thermometricscorp.com/pt1000 for reference """ r = normalize_numeric(r) A, B = standard.a, standard.b # Select if poly is None: if abs(r0 - 1000.0) < 1e-3: poly = pt1000Correction elif abs(r0 - 100.0) < 1e-3: poly = pt100Correction else: poly = noCorrection t = ((-r0 * A + np.sqrt(r0 * r0 * A * A - 4 * r0 * B * (r0 - r))) / (2.0 * r0 * B)) # For subzero-temperature refine the computation by the correction polynomial if isinstance(r, numbers.Number): if r < r0: t += poly(r) else: # Treated like a numpy array t += poly(r) * np.piecewise(r, [r < r0, r >= r0], [1.0, 0.0]) return t
def load_capacitors(cload, cstray="2 pF") -> Quantity("F"): """ Compute the load capacitors which should be used for a given crystal, given that the load capacitors should be symmetric (i.e. have the same value). Parameters ---------- cload : float The load capacitance as given in the crystal datasheet cstray : float The stray capacitance """ cload = normalize_numeric(cload) cstray = normalize_numeric(cstray) # cload = (C1 * C2) / (C1 + C2) + Cstray where C1 == C2 # => solve A = (B*B) / (B+B) + C for B return 2 * (cload - cstray)
def ntc_resistance(r25, b25, t) -> Quantity("Ω"): """ Compute the NTC resistance by temperature and NTC parameters Parameters ---------- r25 : float or EngineerIO string The NTC resistance at 25°C, sometimes also called "nominal resistance" b25: float or EngineerIO string The NTC b-constant (e.g. b25/50, b25/85 or b25/100) t : temperature The temperature. Will be interpreted using normalize_temperature() """ # Normalize inputs r25 = normalize_numeric(r25) b25 = normalize_numeric(b25) t = normalize_temperature(t) # t is now in Kelvins # Compute resistance return r25 * np.exp(b25 * (1./t - 1./(25. + zero_point_celsius)))
def __init__(self, samplerate, freqs, btype="lowpass"): """ Initialize a new filter Keyword arguments: samplerate: The sampling rate freqs: The frequency (for lopass/hipass) or a list of two frequencies """ self.btype = btype self.freqs = freqs self.samplerate = normalize_numeric(samplerate) self.b = None self.a = None # These will be initialized in iir() self.order = None self.rp = None self.rs = None self.ftype = None # Normalize freqs: Allow [1.0] instead of 1.0 if freqs is None: raise ValueError("Critical frequencies may not be none") if isinstance(freqs, collections.Iterable) and not isinstance(freqs, str): if len(freqs) == 1: freqs = freqs[0] elif len(freqs) == 0: raise ValueError("Empty frequency list") elif isinstance(freqs[0], str): freqs = [normalize_numeric(f) for f in freqs] # Allow "4.5 kHz" etc if isinstance(freqs, str): __freqs_orig = freqs freqs = normalize_numeric(freqs) self.filtfreqs = self._filtfreq(freqs) # Check & store pass type if btype == "lowpass" or btype == "highpass": if not isinstance(freqs, numbers.Number): raise ValueError("Pass-type {0} requires a single critical frequency, not {1}".format(btype, freqs)) elif btype == "bandpass" or btype == "bandstop": if isinstance(freqs, numbers.Number) or len(freqs) != 2: raise ValueError("Pass-type {0} requires a two critical frequencies, not {1}".format(btype, freqs)) else: raise ValueError("Invalid pass type '{0}': Use lowpass, highpass, bandpass or bandstop!".format(btype))
def feedback_bottom_resistor(vexp, rtop, vfb) -> Quantity("Ω"): """ Utility to compute the bottom feedback resistor in a voltage feedback network (e.g. for a DC/DC converter) Parameters ---------- vexp : float The voltage at between top and bottom of the voltage divider rtop : float The known top resistor vfb : float The feedback voltage that is servoed by the regulator """ vexp = normalize_numeric(vexp) rtop = normalize_numeric(rtop) vfb = normalize_numeric(vfb) # Vo = Vfb * (R1/R2 + 1) # solve A = B*((C/D) + 1) for D return (vfb * rtop) / (vexp - vfb)
def as_samplerate(self, samplerate): """ Convert this filter to a filter with the same frequency response. Returns a new filter instance. """ if self.a is None: raise NotComputedException() samplerate = normalize_numeric(samplerate) if samplerate == self.samplerate: return self filt = SignalFilter(samplerate, self.freqs, self.btype) filt.iir(self.order, self.ftype, self.rp, self.rs) return filt
def hysteresis_resistor(r1, r2, fh=0.05): """ Computes the hysteresis resistor Rh for a given R1, R2 divider network and a given deviation factor. The deviation factor fh represents the one-sided deviation from the nominal R1/R2 ratio. The total hysteresis is +-fh, i.e 2*fh. For example, for fh=0.05, the threshold will be 95% and 105% of the nominal ratio respectively. For open-drain comparators, fh represents the full deviation as the upper threshold is equivalent to the nominal threshold. Parameters ---------- r1 : float or EngineerIO string The top resistor of the divider r2 : float or EngineerIO string The bottom resistor of the divider fh : float or EngineerIO string The deviation factor (e.g. 0.05 for 5% one-sided hysteresis deviation from the nominal r1/r2 value) """ # Normalize inputs r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) fh = normalize_numeric(fh) # NOTE: We compute rh for the lower threshold only thnom = unloaded_ratio(r1, r2) ratio_target = thnom * (1. - fh) # Compute the resistor that, in parallel to R2, yields # a divider with our target ratio r2total = bottom_resistor_by_ratio(r1, ratio_target) # Solve 1/R3 = (1/R1 + 1/R2) for R2 => R2 = (R1 * R3) / (R1 - R3) return (r2 * r2total) / (r2 - r2total)
def hysteresis_threshold_ratios(r1, r2, rh): """ Calculates hysteresis threshold factors for push-pull comparators Assumes that r1 and r2 are used to divide Vcc using a fixed ratio to obtain a threshold voltage. Additionally, Rh sources or sinks current to the threshold voltage, depending on the current state of the comparator. Additionally it it assumed that the same voltage (Vcc) that feeds the R1+R2 divider is output from the comparator and input to Rh. This function computes the (lower, upper) division ratios by assuming rh is set either parallel with R1 (upper) or with R2 (lower). Returns a tuple (lower, upper) containing floats representing the division ratios. Parameters ---------- r1 : float or EngineerIO string The top resistor of the divider r2 : float or EngineerIO string The bottom resistor of the divider rh : float or EngineerIO string The hysteresis resistor of the divider """ # Normalize inputs r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rh = normalize_numeric(rh) # Compute r1, r2 in parallel with rh r1rh = parallel_resistors(r1, rh) r2rh = parallel_resistors(r2, rh) # Compute thresholds thl = unloaded_ratio(r1, r2rh) thu = unloaded_ratio(r1rh, r2) return (thl, thu)
def feedback_actual_voltage(rtop, rbot, vfb) -> Quantity("V"): """ Compute the actual voltage regulator output in a feedback servo setup. Returns the Vout voltage. Parameters ---------- rtop : float The top resistor of the voltage divider rbot : float The bottom resistor of the voltage divider vfb : float The feedback voltage """ # Equation: Vout * ratio = vfb ratio = unloaded_ratio(rtop, rbot) return normalize_numeric(vfb) / ratio
def summing_amplifier_noninv(v1, v2, r1, r2, rfb1, rfb2) -> Quantity("V"): """ Computes the output voltage of a non-inverting summing amplifier: V1 connected via R1 to IN+ V2 connected via R2 to IN+ IN- connected via RFB1 to GND IN- connected via RFB2 to VOut """ v1 = normalize_numeric(v1) v2 = normalize_numeric(v2) r1 = normalize_numeric(r1) r2 = normalize_numeric(r2) rfb1 = normalize_numeric(rfb1) rfb2 = normalize_numeric(rfb2) return (1.0 + rfb2 / rfb1) * (v1 * (r2 / (r1 + r2)) + v2 * (r1 / (r1 + r2)))
def __hysteresis_threshold_voltages(r1, r2, rh, vcc, fn): """Internal push-pull & open-drain common code""" vcc = normalize_numeric(vcc) thl, thu = fn(r1, r2, rh) return (thl * vcc, thu * vcc)