"""Thin film MELF resistor, Vishay Beyschlag MMU 0102 (MicroMELF), MMA 0204 (MiniMELF) or MMB 0207 (MELF). Lying on the XY plane (the board) with its axis along X and centred on the origin in X and Y: the coated ceramic body between two metal end caps, each end cap its own solid. The resistance and tolerance make the colour rings on the body (IEC 60062), read from the -X end. Dimensions from Vishay's data sheet, listed in the README.""" import math from steve import Model size = "MMA0204" # MMU0102 (MicroMELF), MMA0204 (MiniMELF) or MMB0207 (MELF) resistance = 10000.0 # Ω Resistance (in the range the sheet gives for the size and tolerance) tolerance = "F" # B 0.1 %, C 0.25 %, D 0.5 %, F 1 %, G 2 %, J 5 % (one the sheet offers for this resistance) # Vishay Beyschlag "MMU 0102, MMA 0204, MMB 0207 - Thin Film MELF Resistors", document number 28963, revision 02-Jun-2026, page 13, # table "DIMENSIONS AND MASS", in mm: L, D (end caps), D1 (body) = D + 0 / - x, L1 min. (between the end caps), K (end caps' length), and # the mass in mg. Each entry: (L (min, max), D (min, max), x, L1 min., K (min, max), mass). SIZES = { "MMU0102": ((2.1, 2.2), (1.0, 1.1), 0.1, 1.2, (0.35, 0.5), 8), "MMA0204": ((3.4, 3.6), (1.3, 1.4), 0.15, 1.8, (0.65, 0.85), 22), "MMB0207": ((5.65, 5.8), (2.0, 2.2), 0.2, 3.2, (1.05, 1.25), 80), } # The same sheet, pages 2 and 3, "TEMPERATURE COEFFICIENT AND RESISTANCE RANGE": the resistance ranges in Ω by tolerance, every temperature # coefficient's rows taken together (jumpers left out). RANGES = { "MMU0102": {"J": ((0.22, 0.91),), "G": ((1, 9.1),), "F": ((10, 2.21e6),), "D": ((10, 221e3),), "C": ((47, 332e3),), "B": ((100, 221e3),)}, "MMA0204": {"J": ((0.22, 0.91),), "F": ((0.22, 0.91), (1, 10e6)), "D": ((10, 2.21e6),), "C": ((10, 5.11e6),), "B": ((10, 5.11e6),)}, "MMB0207": {"J": ((0.1, 0.2), (0.22, 0.91)), "G": ((0.1, 0.2), (0.22, 0.91)), "F": ((0.22, 0.91), (1, 15e6)), "D": ((10, 1e6),), "C": ((15, 10e6),), "B": ((20, 10e6),)}, } # Colour code, IEC 60062 (the sheet, page 5: "Four (E24 series) or five (E96 and E192 series) color code rings designate the resistance value # and tolerance in accordance with IEC 60062"; page 13: "The last color band for tolerance is approximately 50 % wider than the other # bands"): ± 5 % and ± 2 % carry two digit rings, the closer tolerances three; then the multiplier ring (pink x 0.001, silver x 0.01, # gold x 0.1) and the tolerance ring. DIGIT_COLOURS = ("#1a1a1a", "#7a4a26", "#c8302c", "#e8792b", "#f2d22e", "#3f8f3f", "#2f5fb3", "#7d4fa8", "#8a8a8a", "#f4f4f4") MULTIPLIER_COLOURS = {-3: "#f0a3b8", -2: "#c0c0c4", -1: "#cfa646", 0: "#1a1a1a", 1: "#7a4a26", 2: "#c8302c", 3: "#e8792b", 4: "#f2d22e", 5: "#3f8f3f", 6: "#2f5fb3"} TOLERANCE_COLOURS = {"B": "#7d4fa8", "C": "#2f5fb3", "D": "#3f8f3f", "F": "#7a4a26", "G": "#c8302c", "J": "#cfa646"} # Proportions, for looks (the sheet shows the rings but doesn't dimension them): each ring is RING of the body's length between the end caps # wide (the tolerance ring 1.5 times that), with equal gaps between the rings and at their ends. RING = 0.1 if size not in SIZES: raise ValueError(f"no size {size!r}: {', '.join(SIZES)}") if tolerance not in RANGES[size]: raise ValueError(f"Vishay {size} comes in tolerance {', '.join(RANGES[size])}") if not any(low * (1 - 1e-9) <= resistance <= high * (1 + 1e-9) for low, high in RANGES[size][tolerance]): spans = " or ".join(f"{low:g} to {high:g} Ω" for low, high in RANGES[size][tolerance]) raise ValueError(f"Vishay {size} at tolerance {tolerance}: {spans}") DIGITS = 2 if tolerance in "JG" else 3 exponent = math.floor(math.log10(resistance) + 1e-9) - (DIGITS - 1) digits = round(resistance / 10 ** exponent) if digits >= 10 ** DIGITS: digits, exponent = digits // 10, exponent + 1 if not math.isclose(digits * 10.0 ** exponent, resistance, rel_tol=1e-6) or exponent not in MULTIPLIER_COLOURS: raise ValueError(f"{resistance} Ω can't be written in {DIGITS} digit rings and a multiplier ring") def mid(pair): return (pair[0] + pair[1]) / 2 LEN, CAP_D, UNDER, _l1, CAP_L, _mass = SIZES[size] length, cap_d, cap_l = mid(LEN), mid(CAP_D), mid(CAP_L) body_d = cap_d - UNDER / 2 # D1 is D + 0 / - x: the middle inside = length / 2 - cap_l axis_z = cap_d / 2 # the part rests on its end caps def ring_colours(): text = str(digits).rjust(DIGITS, "0") return [DIGIT_COLOURS[int(t)] for t in text] + [MULTIPLIER_COLOURS[exponent], TOLERANCE_COLOURS[tolerance]] def body_outline(): """The body's half section (x, z) from -inside to +inside, with a point at each ring's edges, and the rings' segment indices.""" span = 2 * inside widths = [RING * span] * (DIGITS + 1) + [1.5 * RING * span] gap = (span - sum(widths)) / (len(widths) + 1) pts = [(-inside, axis_z), (-inside, axis_z + body_d / 2)] segments = [] x = -inside + gap for w in widths: pts.append((x, axis_z + body_d / 2)) segments.append(len(pts) - 1) pts.append((x + w, axis_z + body_d / 2)) x += w + gap pts += [(inside, axis_z + body_d / 2), (inside, axis_z)] return pts, segments model = Model() # Each cylinder starts at `at` and runs along +X. for tag, x0 in (("cap_1", -length / 2), ("cap_2", inside)): model.cylinder(tag, cap_d / 2, cap_l, at=(x0, 0, axis_z), direction=(1, 0, 0), op="new", body=f"{tag}_body", name="End caps") outline, rings = body_outline() with model.sketch("body_sketch", on="XZ", name="Body") as sk: sk.polyline("body_outline", outline, closed=True) model.revolve("body", "body_sketch", axis=((0, 0, axis_z), (1, 0, 0)), op="new", body="body_body", name="Body") # Materials, for looks and a rough mass (the sheet, page 5: "a high grade ceramic body (Al2O3)", "Nickel plated steel termination caps", # "a final pure matte tin on nickel plating"): the body alumina under its protective coating (the coating's colour is for looks only: the # sheet doesn't name one); the end caps steel, tin plated. model.material("alumina", bodies=["body_body"], color="#9cc3e0") model.material("steel-generic", bodies=["cap_1_body", "cap_2_body"], color="#c9ccd1") for i, colour in zip(rings, ring_colours()): model.appearance(color=colour, faces=[f"body.side(body_outline.side{i})"]) result = model.result()