AnasSarkiz/usb-c-pd-brushed-motor

USB-C PD-powered motor controller with protected input, selectable 5/9/12 V buck supply, MCU qualification, PWM H-bridge drive, overvoltage sensing, regenerative energy-dump resistors, and safety interlocks.

Version
0.0.1-a48-cloud-pipeline9-unrouted-c41d79a-305b1e7a
License
unset
Stars
0

scripts/buck-input-review.ts

import { readFile, writeFile } from "node:fs/promises"
import { z } from "zod"

const charts = z
  .array(
    z.object({
      graphType: z.string(),
      selectPartsList: z.array(
        z.object({
          partsName: z.string(),
          chartList: z.array(
            z.object({
              rippleFreq: z.string().optional(),
              data: z.array(
                z.object({ x: z.coerce.number(), y: z.coerce.number() }),
              ),
            }),
          ),
        }),
      ),
    }),
  )
  .parse(
    JSON.parse(
      await readFile("evidence/C138687-characteristics-A9.json", "utf8"),
    ),
  )
const dcBias = charts.find((chart) => chart.graphType === "DCBias")
  ?.selectPartsList[0]
if (dcBias?.partsName !== "CL32B106KBJNNN")
  throw new Error("Exact manufacturer curve missing")
const maximumInputVoltageV = 21
// Use the next measured curve point above the maximum input voltage.
const upperBiasPoint = dcBias.chartList[0].data.find(
  (point) => point.x >= maximumInputVoltageV,
)
if (!upperBiasPoint)
  throw new Error("DC-bias curve does not cover the input envelope")
const nominalInputCapacitanceF = 2 * 10e-6
const nominalBiasedCapacitanceF =
  nominalInputCapacitanceF * (1 + upperBiasPoint.y / 100)
const screenedEffectiveCapacitanceF =
  nominalBiasedCapacitanceF * 0.9 * 0.85 * 0.8
const peakOutputCurrentA = 2.423
const maximumInputRippleCurrentA = peakOutputCurrentA * 0.5
const worstSharedRipplePerCapacitorA = maximumInputRippleCurrentA * 0.55
const rippleCurves = charts.find((chart) => chart.graphType === "RippleCurr")
  ?.selectPartsList[0].chartList
if (!rippleCurves)
  throw new Error("Manufacturer ripple characterization missing")
const report = {
  revision: "A9",
  part: "C138687 / CL32B106KBJNNNE",
  references: ["C13", "C14"],
  maximumInputVoltageV,
  upperBiasPoint,
  nominalInputCapacitanceF,
  nominalBiasedCapacitanceF,
  screenedEffectiveCapacitanceF,
  requiredEffectiveCapacitanceF: 3e-6,
  effectiveCapacitanceMargin: screenedEffectiveCapacitanceF / 3e-6,
  maximumInputRippleCurrentA,
  worstSharedRipplePerCapacitorA,
  rippleCharacterizationLowPoints: rippleCurves.map((curve) => ({
    frequencyKhz: curve.rippleFreq,
    firstPoint: curve.data[0],
  })),
  oldInputNominalCapacitanceF: 2e-6,
  capacitanceScreenPass: screenedEffectiveCapacitanceF >= 3e-6,
  interpretation:
    "Manufacturer curves are typical, not guaranteed minima. 10% initial tolerance, 15% temperature loss, and an additional 20% aging/design reserve are combined for engineering screening. Ripple sharing assumes 55/45 maximum imbalance; measure with the completed layout. This is not a measured capacitor or converter thermal rating.",
}
await writeFile(
  "evidence/buck-input-review-A9.json",
  JSON.stringify(report, null, 2) + "\n",
)
console.log(JSON.stringify(report, null, 2))
if (!report.capacitanceScreenPass) process.exitCode = 1