def _calculate(name, f, period, bit_width, prescaler): t_cnt_cycle = 1 / float(f) * prescaler t_full_overflow = t_cnt_cycle * (2 ** bit_width) cycles_ideal = round(float(period) / t_cnt_cycle) # However, we're limited by the counter. cycles = cycles_ideal if cycles < 1: cycles = 1 elif cycles > (2 ** bit_width): cycles = 2 ** bit_width preload = (2 ** bit_width) - cycles actual_period = t_cnt_cycle * cycles error = (actual_period - float(period)) / float(period) return { "name": name, "prescaler": prescaler, "t_cnt_cycle": UnitValue(t_cnt_cycle).to_dict(), "t_full_overflow": UnitValue(t_full_overflow).to_dict(), "f_full_overflow": UnitValue(1 / t_full_overflow).to_dict(), "cycles_ideal": cycles_ideal, "cycles": cycles, "actual_period": UnitValue(actual_period).to_dict(), "actual_frequency": UnitValue(1 / actual_period).to_dict(), "error": error, "preload": preload, }
def request(self, endpoint, parameters): if parameters["f_std"] != "": f = UnitValue(parameters["f_std"]) else: f = UnitValue(parameters["f_user"]) ckdiv8 = "ckdiv8" in parameters if ckdiv8: f = UnitValue(f.exact_value / 8) period = UnitValue(parameters["period"]) bit_width = int(parameters["bit_width"]) if parameters["prescaler"] != "": user_prescaler = int(parameters["prescaler"]) else: user_prescaler = None options = [ ] for prescaler_value in [ 1, 8, 64, 256, 1024 ]: option = self._calculate("Prescaler CK / %d" % (prescaler_value), f = f, period = period, bit_width = bit_width, prescaler = prescaler_value) options.append(option) options.sort(key = lambda opt: abs(opt["error"])) if user_prescaler is not None: option = self._calculate("User choice", f = f, period = period, bit_width = bit_width, prescaler = user_prescaler) options.insert(0, option) return { "options": options, }
def test_init_unitvalue(self): x = UnitValue("1.2345") self.assertEqual(x, x) y = UnitValue("1.2345") self.assertEqual(x, y) y = UnitValue(x) self.assertEqual(x, y)
def test_str_units(self): self.assertAlmostEqual(float(UnitValue("12345f")), 12345e-15) self.assertAlmostEqual(float(UnitValue("12345p")), 12345e-12) self.assertAlmostEqual(float(UnitValue("12345n")), 12345e-9) self.assertAlmostEqual(float(UnitValue("12345u")), 12345e-6) self.assertAlmostEqual(float(UnitValue("12345m")), 12345e-3) self.assertAlmostEqual(float(UnitValue("12345")), 12345) self.assertAlmostEqual(float(UnitValue("12345k")), 12345e3) self.assertAlmostEqual(float(UnitValue("12345M")), 12345e6) self.assertAlmostEqual(float(UnitValue("12345G")), 12345e9) self.assertAlmostEqual(float(UnitValue("12345T")), 12345e12)
def from_dict(cls, dict_data): if not "name" in dict_data: raise DataMissingException( "No 'name' attribute in ValueSet definition: %s" % (str(dict_data))) if not "type" in dict_data: raise DataMissingException( "No 'type' attribute in ValueSet definition: %s" % (str(dict_data))) vs_type = dict_data["type"] if vs_type == "explicit": if not "items" in dict_data: raise DataMissingException( "No 'items' attribute in explicit ValueSet definition: %s" % (str(dict_data))) return cls(name=dict_data["name"], values=[UnitValue(v) for v in dict_data["items"]]) elif vs_type == "eseries": if not "series" in dict_data: raise DataMissingException( "No 'series' attribute in eseries ValueSet definition: %s" % (str(dict_data))) if not "min" in dict_data: raise DataMissingException( "No 'min' attribute in eseries ValueSet definition: %s" % (str(dict_data))) if not "max" in dict_data: raise DataMissingException( "No 'max' attribute in eseries ValueSet definition: %s" % (str(dict_data))) eseries = ESeries.standard(dict_data["series"]) (minval, maxval) = UnitValue(dict_data["min"]), UnitValue(dict_data["max"]) values = [ UnitValue(v) for v in eseries.from_to(minval.exact_value, maxval.exact_value, maxvalue_inclusive=True) ] return cls(name=dict_data["name"], values=values) elif vs_type == "union": if not "groups" in dict_data: raise DataMissingException( "No 'groups' attribute in union ValueSet definition: %s" % (str(dict_data))) return cls(name=dict_data["name"], values=None, additional_data=dict_data["groups"]) else: raise InvalidDataException( "Invalid 'type' attribute of ValueSet '%s': %s" % (vs_type, str(dict_data)))
def _calculate_choice(name, r, v_in, v_load, i): r_load = v_load / i actual_v_load = v_in * r_load / (r_load + float(r)) rel_error = (actual_v_load - v_load) / v_load abs_error = UnitValue(actual_v_load - v_load) return { "name": name, "r": UnitValue(r).to_dict(), "v_load": UnitValue(actual_v_load).to_dict(), "rel_error": rel_error, "abs_error": abs_error.to_dict(), }
def request(self, endpoint, parameters): value = UnitValue(parameters["input_value"]) significant_digits = int(parameters["significant_digits"]) return { "value": value.to_dict(significant_digits=significant_digits), "significant_digits": significant_digits, }
def request(self, endpoint, parameters): v_in = UnitValue(parameters["v_in"]) v_out = UnitValue(parameters["v_out"]) r_sum = UnitValue(parameters["r_sum"]) r_set = self.config.get_valuesets("r")[parameters["r_set"]] r_tolerance = float(parameters["r_tolerance"]) / 100 options = [] ideal_r1 = float(r_sum) * (float(v_out)) / float(v_in) min_r1 = ideal_r1 * (1 - r_tolerance) max_r1 = ideal_r1 * (1 + r_tolerance) for r1 in r_set.iter_range(min_r1, max_r1): ideal_r2 = float(r1) * (float(v_in) - float(v_out)) / float(v_out) for r2 in r_set.iter_closest(ideal_r2): opt_v_out = float(v_in) * float(r1) / (float(r1) + float(r2)) opt_r_sum = float(r1) + float(r2) opt_i = float(v_in) / opt_r_sum opt_p = (opt_i**2) * opt_r_sum option = { "r1": r1.to_dict(), "r2": r2.to_dict(), "r_total": UnitValue(opt_r_sum).to_dict(), "v_out": UnitValue(opt_v_out).to_dict(), "v_error": (opt_v_out - float(v_out)) / float(v_out), "r_error": (opt_r_sum - float(r_sum)) / float(r_sum), "i": UnitValue(opt_i).to_dict(), "p": UnitValue(opt_p).to_dict(), } options.append(option) options.sort( key=lambda opt: (abs(opt["v_error"]), abs(opt["r_error"]))) return { "options": options, }
def to_dict(self, repr_callback=None): return { "name": self.name, "values": [ UnitValue(element, repr_callback=repr_callback).to_dict() for element in self._values ], }
def find_closest(self, value): value = UnitValue(value) index = bisect.bisect(self._values, value) - 1 if index >= 0: smaller = self._values[index] else: smaller = None if index + 1 < len(self._values): larger = self._values[index + 1] else: larger = None return (smaller, larger)
def request(self, endpoint, parameters): if parameters["f_std"] != "": f = UnitValue(parameters["f_std"]) else: f = UnitValue(parameters["f_user"]) ckdiv8 = "ckdiv8" in parameters u2x = "u2x" in parameters if ckdiv8: f = UnitValue(f.exact_value / 8) ckdivisor = 8 if u2x else 16 result_items = [] for baudrate in self.config.get_valuesets( "baudrate")["Standard"].values.ordered_tuple: ubrr = max(0, round(float(f) / (ckdivisor * float(baudrate))) - 1) act_baudrate = float(f) / (ckdivisor * (ubrr + 1)) error = (act_baudrate - float(baudrate)) / float(baudrate) ideal_freq = float(baudrate) * (ckdivisor * (ubrr + 1)) if ckdiv8: ideal_freq *= 8 result_items.append({ "baudrate": baudrate.to_dict(include_repr=True), "act_baudrate": act_baudrate, "ubrr": ubrr, "error": error, "ideal_freq": UnitValue( ideal_freq, repr_callback=lambda value: value.format( significant_digits=6)).to_dict(include_repr=True), }) return { "items": result_items, }
def request(self, endpoint, parameters): marking = parameters["marking"].strip() try: int_marking = int(marking) except ValueError: int_marking = None try: flt_marking = float(marking) except ValueError: flt_marking = None if (int_marking is not None) and (int_marking >= 100): (base, exponent) = divmod(int_marking, 10) value = base * (10**exponent) (r, c, l) = (1, 1e-12, 1e-6) elif flt_marking is not None: value = flt_marking (r, c, l) = (1, 1e-12, None) else: replacers = { "r": (1, None, 1e-6), "u": (None, 1e-6, 1e-6), "n": (None, 1e-9, 1e-9), "p": (None, 1e-12, None), } lmarking = marking.lower() for (character, (r, c, l)) in replacers.items(): if character in lmarking: value = float(lmarking.replace(character, ".")) break else: raise InputDataException("Unable to interpret \"%s\"." % (marking)) return { "r": UnitValue(value * r).to_dict() if r else None, "c": UnitValue(value * c).to_dict() if c else None, "l": UnitValue(value * l).to_dict() if l else None, }
def request(self, endpoint, parameters): f_in = UnitValue(parameters["f_in"]) f_out = UnitValue(parameters["f_out"]) multipliers = self._parse_ckfield(parameters["mul"]) dividers = SortedList(self._parse_ckfield(parameters["div"])) results = [] ratio = float(f_out) / float(f_in) for multiplier in multipliers: ideal_divider = multiplier / ratio for divider in dividers.less_more_list(ideal_divider): f_result = float(f_in) * multiplier / divider error = (f_result - float(f_out)) / float(f_out) result = { "multiplier": multiplier, "divider": divider, "f_out": UnitValue(f_result).to_dict(), "error": error, } results.append(result) results.sort(key=lambda result: abs(result["error"])) return results
def request(self, endpoint, parameters): r = UnitValue(parameters["r"]) r_set = self.config.get_valuesets("r")[parameters["r_set"]] options = [] for r1 in r_set: if r1 == r: continue ideal_r2 = 1 / ((1 / float(r)) - (1 / float(r1))) for r2 in r_set.iter_closest(ideal_r2): if r2 < r1: continue r_total = 1 / ((1 / float(r1)) + (1 / float(r2))) error = (r_total - float(r)) / float(r) if abs(error) > 0.75: continue option = { "r1": UnitValue(r1).to_dict(), "r2": UnitValue(r2).to_dict(), "r": UnitValue( r_total, repr_callback=lambda v: v.format( significant_digits=4)).to_dict(include_repr=True), "error": error, "ratio": float(r2) / float(r1), } options.append(option) options.sort(key=lambda o: (abs(o["error"]), o["ratio"])) return { "options": options[:15], }
def request(self, endpoint, parameters): if parameters["v"].strip() == "": i = UnitValue(parameters["i"]) r = UnitValue(parameters["r"]) v = UnitValue(float(i) * float(r)) elif parameters["i"].strip() == "": r = UnitValue(parameters["r"]) v = UnitValue(parameters["v"]) i = UnitValue(float(v) / float(r)) elif parameters["r"].strip() == "": v = UnitValue(parameters["v"]) i = UnitValue(parameters["i"]) r = UnitValue(float(v) / float(i)) else: raise InputDataException( "Exactly one of V, I, R must be left empty.") p = UnitValue((float(i)**2) * float(r)) return { "v": v.to_dict(), "i": i.to_dict(), "r": r.to_dict(), "p": p.to_dict(), }
def request(self, endpoint, parameters): v_in = UnitValue(parameters["v_in"]) v_load = UnitValue(parameters["v_load"]) i = UnitValue(parameters["i"]) if v_in < v_load: raise InputDataException("Input voltage is lower than load voltage.") v_r = float(v_in) - float(v_load) r = v_r / float(i) p_r = float(i) * v_r p_load = float(i) * float(v_load) eta = float(v_load) / float(v_in) choices = [ ] if parameters["r_user"] != "": r_user = UnitValue(parameters["r_user"]) choices.append(self._calculate_choice("User choice", r = r_user, v_in = float(v_in), v_load = float(v_load), i = float(i))) if parameters["r_set"] != "": r_set = self.config.get_valuesets("r")[parameters["r_set"]] (smaller, larger) = r_set.find_closest(r) if smaller is not None: choices.append(self._calculate_choice("Smaller in set", r = smaller, v_in = float(v_in), v_load = float(v_load), i = float(i))) if larger is not None: choices.append(self._calculate_choice("Larger in set", r = larger, v_in = float(v_in), v_load = float(v_load), i = float(i))) return { "v_in": v_in.to_dict(), "v_load": v_load.to_dict(), "i": i.to_dict(), "v_r": UnitValue(v_r).to_dict(), "r": UnitValue(r).to_dict(), "p_r": UnitValue(p_r).to_dict(), "p_load": UnitValue(p_load).to_dict(), "p_total": UnitValue(p_r + p_load).to_dict(), "eta": eta, "choices": choices, }
def request(self, endpoint, parameters): r1 = UnitValue(parameters["r1"]) r2 = UnitValue(parameters["r2"]) c1 = UnitValue(parameters["c1"]) t_on = 0.693 * (float(r1) + float(r2)) * float(c1) t_off = 0.693 * float(r2) * float(c1) t = t_on + t_off f = 1 / t duty = t_on / t return { "r1": r1.to_dict(), "r2": r2.to_dict(), "c1": c1.to_dict(), "t": UnitValue(t).to_dict(), "t_on": UnitValue(t_on).to_dict(), "t_off": UnitValue(t_off).to_dict(), "f": UnitValue(f).to_dict(), "duty": duty, }
def request(self, endpoint, parameters): diameter = UnitValue(parameters["diameter"]) length = UnitValue(parameters["length"]) turns = int(parameters["turns"]) pitch = float(length) / turns diameter_inch = UnitValue(diameter.exact_value * 10000 / 254) reference = Thread(diameter=float(diameter), pitch=pitch) candidates = list(self.config.thread_db.closest(reference)) candidates = [{ "group": candidate.group, "name": candidate.name, "usage": candidate.usage, "diameter": UnitValue(candidate.diameter).to_dict(), "diameter_frac": FractionalRepresentation(candidate.diameter * 10000 / 254, max_abs_fractional_error=0.01).to_dict(), "pitch": UnitValue(candidate.pitch).to_dict(), "pitch_tpi": candidate.pitch_tpi, "diameter_err": (candidate.diameter - float(diameter)) / float(diameter), "pitch_err": (candidate.pitch - pitch) / pitch, } for candidate in candidates] return { "diameter": diameter.to_dict(), "diameter_inch": diameter_inch.to_dict(), "diameter_frac": FractionalRepresentation(diameter_inch.exact_value, max_abs_fractional_error=0.01).to_dict(), "pitch": UnitValue(pitch).to_dict(), "pitch_tpi": 0.0254 / pitch, "candidates": candidates, }
def request(self, endpoint, parameters): v_out = UnitValue(parameters["v_out"]) r_set = self.config.get_valuesets("r")[parameters["r_set"]] l = UnitValue(parameters["l"]) if (parameters["l"] != "") else None v_in = UnitValue( parameters["v_in"]) if (parameters["v_in"] != "") else None i_out = UnitValue( parameters["i_out"]) if (parameters["i_out"] != "") else None f = 325e3 options = [] for r2 in r_set.iter_range(500, 50000): ideal_r1 = (float(v_out) / 0.925 * float(r2)) - float(r2) for r1 in r_set.iter_closest(ideal_r1): actual_v_out = 0.925 * (float(r1) + float(r2)) / float(r2) error = (actual_v_out - float(v_out)) / float(v_out) option = { "r1": r1.to_dict(), "r2": r2.to_dict(), "v_out": UnitValue(actual_v_out).to_dict(), "error": error, } if (v_in is not None) and (l is not None): # Inductor and V_IN also given, calculate Delta I_L option["delta_i_load"] = UnitValue( ((float(v_in) * float(v_out)) - (float(v_out)**2)) / (f * float(l) * float(v_in))).to_dict() if (v_in is not None) and (l is not None) and (i_out is not None): option["max_inductor_i"] = UnitValue( float(i_out) + (float(v_out) / (2 * f * float(l)) * (1 - (float(v_out) / float(v_in))))).to_dict() options.append(option) options.sort(key=lambda opt: abs(opt["error"])) return { "show_other": (v_in is not None) and (l is not None), "options": options[:15], }
def test_format_units(self): self.assertEqual(UnitValue(1.23e-17).format(significant_digits = 3), "0.0123 f") self.assertEqual(UnitValue(1.23e-16).format(significant_digits = 3), "0.123 f") self.assertEqual(UnitValue(1.23e-15).format(significant_digits = 3), "1.23 f") self.assertEqual(UnitValue(1.23e-14).format(significant_digits = 3), "12.3 f") self.assertEqual(UnitValue(1.23e-13).format(significant_digits = 3), "123 f") self.assertEqual(UnitValue(1.23e-12).format(significant_digits = 3), "1.23 p") self.assertEqual(UnitValue(1.23e-11).format(significant_digits = 3), "12.3 p") self.assertEqual(UnitValue(1.23e-10).format(significant_digits = 3), "123 p") self.assertEqual(UnitValue(1.23e-9).format(significant_digits = 3), "1.23 n") self.assertEqual(UnitValue(1.23e-8).format(significant_digits = 3), "12.3 n") self.assertEqual(UnitValue(1.23e-7).format(significant_digits = 3), "123 n") self.assertEqual(UnitValue(1.23e-6).format(significant_digits = 3), "1.23 µ") self.assertEqual(UnitValue(1.23e-5).format(significant_digits = 3), "12.3 µ") self.assertEqual(UnitValue(1.23e-4).format(significant_digits = 3), "123 µ") self.assertEqual(UnitValue(1.23e-3).format(significant_digits = 3), "1.23 m") self.assertEqual(UnitValue(1.23e-2).format(significant_digits = 3), "12.3 m") self.assertEqual(UnitValue(1.23e-1).format(significant_digits = 3), "123 m") self.assertEqual(UnitValue(1.23e0).format(significant_digits = 3), "1.23 ") self.assertEqual(UnitValue(1.23e1).format(significant_digits = 3), "12.3 ") self.assertEqual(UnitValue(1.23e2).format(significant_digits = 3), "123 ") self.assertEqual(UnitValue(1.23e3).format(significant_digits = 3), "1.23 k") self.assertEqual(UnitValue(1.23e4).format(significant_digits = 3), "12.3 k") self.assertEqual(UnitValue(1.23e5).format(significant_digits = 3), "123 k") self.assertEqual(UnitValue(1.23e6).format(significant_digits = 3), "1.23 M") self.assertEqual(UnitValue(1.23e7).format(significant_digits = 3), "12.3 M") self.assertEqual(UnitValue(1.23e8).format(significant_digits = 3), "123 M") self.assertEqual(UnitValue(1.23e9).format(significant_digits = 3), "1.23 G") self.assertEqual(UnitValue(1.23e10).format(significant_digits = 3), "12.3 G") self.assertEqual(UnitValue(1.23e11).format(significant_digits = 3), "123 G") self.assertEqual(UnitValue(1.23e12).format(significant_digits = 3), "1.23 T") self.assertEqual(UnitValue(1.23e13).format(significant_digits = 3), "12.3 T") self.assertEqual(UnitValue(1.23e14).format(significant_digits = 3), "123 T") self.assertEqual(UnitValue(1.23e15).format(significant_digits = 3), "1.23 E") self.assertEqual(UnitValue(1.23e16).format(significant_digits = 3), "12.3 E") self.assertEqual(UnitValue(1.23e17).format(significant_digits = 3), "123 E") self.assertEqual(UnitValue(1.23e18).format(significant_digits = 3), "1230 E") self.assertEqual(UnitValue(1.23e19).format(significant_digits = 3), "12300 E")
def test_reformat_1u(self): value = UnitValue("1u") self.assertEqual(value.format(significant_digits = 3), "1.00 µ")
def request(self, endpoint, parameters): t1 = UnitValue(parameters["t1"]) v1 = UnitValue(parameters["v1"]) t2 = UnitValue(parameters["t2"]) v2 = UnitValue(parameters["v2"]) if t1 > t2: (t1, v1, t2, v2) = (t2, v2, t1, v1) if v2 < v1: # Capacitor is discharging # v(t) = v0 * exp(-t / tau) # v1 = v0 * exp(-t1 / tau) -> v0 = v1 / exp(-t1 / tau) # v2 = v0 * exp(-t2 / tau) -> v0 = v2 / exp(-t2 / tau) # v1 / exp(-t1 / tau) = v2 / exp(-t2 / tau) # v1 / v2 = exp(-t1 / tau) / exp(-t2 / tau) = exp((-t1 - (-t2)) / tau) = exp((t2 - t1) / tau) # (t2 - t1) / tau = ln(v1 / v2) # tau = (t2 - t1) / ln(v1 / v2) tau = (float(t2) - float(t1)) / math.log(float(v1) / float(v2)) v0 = float(v1) / math.exp(-float(t1) / tau) else: # Capacitor is charging, here we need to rely on numeric solution. # v(t) = v0 * (1 - exp(-t / tau)) # v1 = v0 * exp(-t1 / tau) # v2 = v0 * exp(-t2 / tau) # v1 / v2 = exp(-t1 / tau) / exp(-t2 / tau) # Substitute: d = v1 / v2 # d = exp(-t1 / tau) / exp(-t2 / tau) # d - exp(-t1 / tau) / exp(-t2 / tau) = 0 # Solve this by Newton's method. d = float(v1) / float(v2) function = _ChargingCapFunction(d=float(v1) / float(v2), t1=float(t1), t2=float(t2)) try: tau = NewtonSolver(function).solve(x0=1) v0 = float(v1) / (1 - math.exp(-float(t1) / tau)) except ZeroDivisionError: raise InputDataException( "Result is numerically instable, cannot solve.") if tau < 0: raise InputDataException( "Result is numerically instable, tau was negative.") # Now, plausibilize values. if v2 < v1: calc_v1 = v0 * math.exp(-float(t1) / tau) calc_v2 = v0 * math.exp(-float(t2) / tau) else: calc_v1 = v0 * (1 - math.exp(-float(t1) / tau)) calc_v2 = v0 * (1 - math.exp(-float(t2) / tau)) error_v1 = abs(calc_v1 - float(v1)) error_v2 = abs(calc_v2 - float(v2)) max_error = max(error_v1, error_v2) if (max_error > 1e-3): raise InputDataException( "Result is numerically instable and diverged. Refusing to give a completely wrong answer. Absolute error was %.2e" % (max_error)) # Cutoff frequency f = 1 / (2 * math.pi * tau) return { "tau": tau, "v0": UnitValue(v0).to_dict(), "f": UnitValue(f).to_dict(), }
def test_str_init(self): self.assertAlmostEqual(float(UnitValue("1.23456")), 1.23456) self.assertAlmostEqual(float(UnitValue(".23456")), .23456) self.assertAlmostEqual(float(UnitValue("0000.23456")), .23456)
def iter_range(self, min_value, max_value): min_index = bisect.bisect(self._values, UnitValue(min_value)) - 1 max_index = bisect.bisect(self._values, UnitValue(max_value)) for index in range(min_index, max_index + 1): if 0 <= index < len(self._values): yield self._values[index]
def request(self, endpoint, parameters): if parameters.get("i", "") != "": i = UnitValue(parameters["i"]) else: i = None if parameters.get("thickness", "") != "": thickness = UnitValue(parameters["thickness"]) thickness_unit = parameters["thickness_unit"] uc = UnitConversion.lengths() uc.add(1, "oz", 35, "um") thickness_mil = uc.convert(float(thickness), thickness_unit, "mil") else: thickness_mil = None if parameters.get("tempdelta", "") != "": tempdelta = UnitValue(parameters["tempdelta"]) tempdelta_unit = parameters["tempdelta_unit"] uc = UnitConversion.temperatures() t = uc.convert_delta(float(tempdelta), tempdelta_unit, "K") else: t = None if parameters.get("trace_width", "") != "": trace_width = UnitValue(parameters["trace_width"]) trace_width_unit = parameters["trace_width_unit"] uc = UnitConversion.lengths() trace_width_mil = uc.convert(float(trace_width), trace_width_unit, "mil") else: trace_width_mil = None inner_layer = (int(parameters.get("inner_layer", "0")) == 1) if parameters.get("trace_length", "") != "": trace_length = UnitValue(parameters["trace_length"]) else: trace_length = None k = 0.024 if inner_layer else 0.048 # IPC-2221A, pg. 50 # k = 0.048 for outer, 0.024 for inner layers # I = k * T^0.44 * A^0.725 # A = Cross section in mil² # T = Temperature delta in °C # A = (I / k / T^0.44)^(1 / 0.725) # T = (I / k / A^0.725)^ (1 / 0.44) def unit_temperature(tempdelta_kelvin): return { "kelvin": tempdelta_kelvin, } def unit_length_mil(length_mil): return { "mil": length_mil, } def unit_area_sqrmil(area_sqrmil): return { "sqrmil": area_sqrmil, "mm2": area_sqrmil / ((1000 / 25.4)**2), } def unit_copper_thickness(length_mil): uc = UnitConversion.lengths() uc.add(1, "oz", 35, "um") return { "mil": length_mil, "oz": uc.convert(length_mil, "mil", "oz"), "mm": uc.convert(length_mil, "mil", "mm"), } results = [] if (i is not None) and (t is not None) and (thickness_mil is not None): # Calculate trace width calc_A_sqrmil = (float(i) / k / (t**0.44))**(1 / 0.725) calc_trace_width_mil = calc_A_sqrmil / thickness_mil result = { "given": { "i": i.to_dict(), "t": unit_temperature(t), "thickness": unit_copper_thickness(thickness_mil), }, "calculated": { "A": unit_area_sqrmil(calc_A_sqrmil), "width": unit_length_mil(calc_trace_width_mil), }, } results.append(result) if (trace_width_mil is not None) and (t is not None) and (thickness_mil is not None): # Calculate current calc_A_sqrmil = trace_width_mil * thickness_mil calc_i = UnitValue(k * (t**0.44) * (calc_A_sqrmil**0.725)) result = { "given": { "width": unit_length_mil(calc_trace_width_mil), "t": unit_temperature(t), "thickness": unit_copper_thickness(thickness_mil), }, "calculated": { "A": unit_area_sqrmil(calc_A_sqrmil), "i": calc_i.to_dict(), }, } results.append(result) if (trace_width_mil is not None) and (t is not None) and (i is not None): # Calculate copper thickness calc_A_sqrmil = (float(i) / k / (t**0.44))**(1 / 0.725) calc_copper_height_mil = calc_A_sqrmil / trace_width_mil result = { "given": { "i": i.to_dict(), "t": unit_temperature(t), "width": unit_length_mil(trace_width_mil), }, "calculated": { "A": unit_area_sqrmil(calc_A_sqrmil), "thickness": unit_copper_thickness(calc_copper_height_mil), }, } results.append(result) if (trace_width_mil is not None) and (i is not None) and (thickness_mil is not None): # Calculate temperature rise calc_A_sqrmil = trace_width_mil * thickness_mil calc_t = (float(i) / k / (calc_A_sqrmil**0.725))**(1 / 0.44) result = { "given": { "i": i.to_dict(), "width": unit_length_mil(trace_width_mil), "thickness": unit_copper_thickness(thickness_mil), }, "calculated": { "A": unit_area_sqrmil(calc_A_sqrmil), "t": unit_temperature(calc_t), }, } results.append(result) for result in results: cu_resistivity = 1.68e-8 # Ohm-meters area_sqrm = result["calculated"]["A"]["mm2"] / 1e6 resistance_per_meter = cu_resistivity / area_sqrm result["calculated"]["R_per_cm"] = UnitValue(resistance_per_meter / 100).to_dict() if trace_length is not None: result["given"]["l"] = trace_length.to_dict() result["calculated"]["R"] = UnitValue( resistance_per_meter * float(trace_length)).to_dict() if ("i" in result["given"]): i = result["given"]["i"]["flt"] else: i = result["calculated"]["i"]["flt"] P = (i**2) * result["calculated"]["R"]["flt"] result["calculated"]["P"] = UnitValue(P).to_dict() return results
def test_format(self): self.assertEqual(UnitValue("0").format(significant_digits = 1), "0 ") self.assertEqual(UnitValue("0").format(significant_digits = 2), "0.0 ") self.assertEqual(UnitValue("0").format(significant_digits = 3), "0.00 ") self.assertEqual(UnitValue("0").format(significant_digits = 4), "0.000 ") self.assertEqual(UnitValue("1").format(significant_digits = 1), "1 ") self.assertEqual(UnitValue("1").format(significant_digits = 2), "1.0 ") self.assertEqual(UnitValue("1").format(significant_digits = 3), "1.00 ") self.assertEqual(UnitValue("1").format(significant_digits = 4), "1.000 ") self.assertEqual(UnitValue("-1").format(significant_digits = 1), "-1 ") self.assertEqual(UnitValue("-1").format(significant_digits = 2), "-1.0 ") self.assertEqual(UnitValue("-1").format(significant_digits = 3), "-1.00 ") self.assertEqual(UnitValue("-1").format(significant_digits = 4), "-1.000 ") self.assertEqual(UnitValue("1").format(significant_digits = 3), "1.00 ") self.assertEqual(UnitValue("12").format(significant_digits = 3), "12.0 ") self.assertEqual(UnitValue("123").format(significant_digits = 3), "123 ") self.assertEqual(UnitValue("1").format(significant_digits = 4), "1.000 ") self.assertEqual(UnitValue("12").format(significant_digits = 4), "12.00 ") self.assertEqual(UnitValue("123").format(significant_digits = 4), "123.0 ") self.assertEqual(UnitValue("1234").format(significant_digits = 4), "1.234 k") self.assertEqual(UnitValue("12345").format(significant_digits = 4), "12.35 k") self.assertEqual(UnitValue("123456").format(significant_digits = 4), "123.5 k") self.assertEqual(UnitValue("123456").format(significant_digits = 5), "123.46 k")