project
Adom Custom Electronic Load
Public Made by Adomby adom
Independent compact digitally controlled load design for 3rdPartyFab; research and AIFlow evidence in progress
main
John Lauer
R0 engineering checkpoint: checked schematic, sourcing, servo evidence and safety-policy code; PCB and qualification incomplete
10054d3
1h ago
#!/usr/bin/env python3
"""TI OPA189 + assumed Level-1 MOSFET sensitivity study; NOT IXTP64N10L2 validation."""
import json,subprocess,os
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
P=Path(__file__).parent; template=(P/'vendor-servo-startup.cir').read_text();comp=float(os.environ.get('COMP_NF','4.7'));template=template.replace('C2 out fb 4.7n',f'C2 out fb {comp:g}n');rows=[];fig,ax=plt.subplots(figsize=(11,5))
for kp in [.4,4,40]:
for cap in [1,3]:
key=f'kp{kp:g}-cap{cap}';s=template.replace('KP=4',f'KP={kp}').replace('3.4n',f'{3.4*cap}n').replace('235p',f'{235*cap}p').replace('vendor-servo-startup.dat',key+'.dat')
(P/(key+'.cir')).write_text(s)
run=subprocess.run(['ngspice','-b',key+'.cir'],cwd=P,capture_output=True,text=True);(P/(key+'.log')).write_text(run.stdout+run.stderr)
a=np.loadtxt(P/(key+'.dat'));t=a[:,0];current=a[:,1]/.02;gate=a[:,5]
measurements={}
for label,start,end,target in [('one_amp',.035,.038,1),('three_amp',.055,.058,3),('off',.075,.078,0)]:
y=current[(t>start)&(t<end)];measurements[label]={'mean_A':float(y.mean()),'ripple_pp_A':float(np.ptp(y)),'error_A':float(y.mean()-target)}
good=all(abs(measurements[k]['error_A'])<.005 and measurements[k]['ripple_pp_A']<.005 for k in measurements)
rows.append({'kp_assumed':kp,'capacitance_scale_assumed':cap,'measurements':measurements,'peak_A':float(current.max()),'gate_max_V':float(gate.max()),'settled_windows_pass':good})
ax.plot(t*1000,current,label=f'KP={kp:g}, C×{cap}',lw=1)
ax.set(xlabel='Time (ms)',ylabel='Sink current (A)',title='Engineering sensitivity study — vendor amplifier, approximate MOSFET')
ax.grid(alpha=.25);ax.legend(ncol=3);fig.tight_layout();fig.savefig(P/'servo-sensitivity.png',dpi=160)
(P/'servo-sensitivity.json').write_text(json.dumps({'compensation_nF':comp,'scope':'partial current servo only','vendor_amplifier':'TI OPAx189 Rev E, unmodified','transistor':'illustrative Level-1 NMOS, NOT vendor IXTP64N10L2 model','limitations':['No thermals or linear-mode SOA in this model','No cable inductance, DUT control-loop interaction, boost ripple or PCB parasitics','No tolerance sweep or measurement chain validation','Ideal switch approximates gate clamp; hardware latch and startup/reset/power-domain faults require separate tests'],'pass':all(x['settled_windows_pass'] for x in rows),'rows':rows},indent=2))
print(json.dumps({'settled_scenarios':sum(x['settled_windows_pass'] for x in rows),'total':len(rows)}))