board
OCuLink Riser for the Supermicro AIOM Slot
Public Unreviewedby John Lauer
Passive OCP NIC 3.0 SFF card that breaks a Supermicro AIOM slot's PCIe x16 into four OCuLink 4i ports (4 x4, Gen4): 6-layer, 85 ohm, length-matched, DRC-clean KiCad project with Gerbers, BOM and CPL.
← Commit history
design/gen/outline2.pydeleted−102@@ -1,102 +0,0 @@-#!/usr/bin/env python3-"""OCP NIC 3.0 SFF outline as lines and arcs: every corner filleted (slot bottoms are exact semicircles,-latch notch R0.50 outer / R0.25 inner per OCP Fig. 9, 0.2-0.3 mm on the chamfer vertices)."""-import math-import hs--W, L = 76.0, 115.0---def vertices():- F = hs.F- c30 = 3.00 * math.tan(math.radians(30))- ear, ow, od, ch = 3.7625, 2.5, 6.10, 0.75- tongue = [(F - 31.480, F - 20.4 - 1.125), (F - 20.4 + 1.125, F - 0.925),- (F + 0.925, F + 12.26 - 1.375), (F + 12.26 + 1.375, F + 31.995)]- keys = [(F - 20.4, 2.25, 7.0), (F, 1.85, 7.0), (F + 12.26, 2.75, 7.0)]- ny1, ny0 = L - 33.5, L - 30.0- V = []-- def slot(xc, w, d):- r = w / 2- V.extend([(xc + r, L - d, r), (xc - r, L - d, r)])-- V += [(0, 0, 0.5), (W, 0, 0.5), (W, ny1, 0.5), (W - 2.75, ny1, 0.25), (W - 2.75, ny0, 0.25), (W, ny0, 0.5),- (W, L - 3.00, 0.3), (W - c30, L, 0.3), (W - ear, L, 0.25)]- slot(tongue[3][1] + ow / 2, ow, od)- for i in range(3, -1, -1):- a, b = tongue[i]- V += [(b, L - ch, 0.2), (b - ch, L, 0.2), (a + ch, L, 0.2), (a, L - ch, 0.2)]- if i > 0:- slot(*keys[i - 1])- slot(tongue[0][0] - ow / 2, ow, od)- V += [(ear, L, 0.25), (c30, L, 0.3), (0, L - 3.00, 0.3), (0, ny0, 0.5), (2.75, ny0, 0.25), (2.75, ny1, 0.25), (0, ny1, 0.5)]- return V---def fillet():- V = vertices()- n = len(V)- prims = []- pts_after = [] # (start_of_next_line) per vertex- arcs = []- for i in range(n):- p0 = V[i - 1]; p1 = V[i]; p2 = V[(i + 1) % n]- d1 = (p1[0] - p0[0], p1[1] - p0[1]); l1 = math.hypot(*d1); d1 = (d1[0] / l1, d1[1] / l1)- d2 = (p2[0] - p1[0], p2[1] - p1[1]); l2 = math.hypot(*d2); d2 = (d2[0] / l2, d2[1] / l2)- cosang = max(-1, min(1, d1[0] * d2[0] + d1[1] * d2[1]))- turn = math.acos(cosang)- r = p1[2]- t = r * math.tan(turn / 2)- assert t <= l1 / 2 + 1e-3 and t <= l2 / 2 + 1e-3, (i, p1, t, l1, l2)- a = (p1[0] - d1[0] * t, p1[1] - d1[1] * t)- b = (p1[0] + d2[0] * t, p1[1] + d2[1] * t)- # centre: from a, perpendicular toward the inside of the turn- cross = d1[0] * d2[1] - d1[1] * d2[0]- nrm = (-d1[1], d1[0]) if cross > 0 else (d1[1], -d1[0])- c = (a[0] + nrm[0] * r, a[1] + nrm[1] * r)- bis = ((a[0] + b[0]) / 2 - c[0], (a[1] + b[1]) / 2 - c[1]); bl = math.hypot(*bis)- m = (c[0] + bis[0] / bl * r, c[1] + bis[1] / bl * r)- arcs.append((a, m, b, c, r))- for i in range(n):- a_prev = arcs[i - 1][2]- a_cur = arcs[i][0]- s, m, e, c, r = arcs[i]- if math.hypot(a_cur[0] - a_prev[0], a_cur[1] - a_prev[1]) > 1e-3:- prims.append(("line", a_prev[0], a_prev[1], a_cur[0], a_cur[1]))- else:- s = a_prev # tangent arcs meet: start exactly where the previous arc ended- prims.append(("arc", s[0], s[1], m[0], m[1], e[0], e[1]))- return prims, arcs---def polygon(seg_per_arc=8):- prims, arcs = fillet()- pts = []- for pr in prims:- if pr[0] == "line":- pts.append((pr[1], pr[2]))- else:- sx, sy, mx, my, ex, ey = pr[1:]- # sample the arc through its three points- import numpy as np- ax, ay, bx, by, cx_, cy_ = sx, sy, mx, my, ex, ey- d = 2 * (ax * (by - cy_) + bx * (cy_ - ay) + cx_ * (ay - by))- ux = ((ax * ax + ay * ay) * (by - cy_) + (bx * bx + by * by) * (cy_ - ay) + (cx_ * cx_ + cy_ * cy_) * (ay - by)) / d- uy = ((ax * ax + ay * ay) * (cx_ - bx) + (bx * bx + by * by) * (ax - cx_) + (cx_ * cx_ + cy_ * cy_) * (bx - ax)) / d- r = math.hypot(ax - ux, ay - uy)- a0 = math.atan2(ay - uy, ax - ux); a1 = math.atan2(by - uy, bx - ux); a2 = math.atan2(cy_ - uy, cx_ - ux)- # go from a0 through a1 to a2- def norm(t):- return (t + 2 * math.pi) % (2 * math.pi)- ccw = norm(a1 - a0) < norm(a2 - a0)- span = norm(a2 - a0) if ccw else -norm(a0 - a2)- for k in range(seg_per_arc):- t = a0 + span * k / seg_per_arc- pts.append((ux + r * math.cos(t), uy + r * math.sin(t)))- return pts---if __name__ == "__main__":- prims, _ = fillet()- print(len(prims), "primitives;", sum(1 for p in prims if p[0] == "arc"), "arcs;", len(polygon()), "polygon points")