app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
master
John Lauer
Publish thermal bottleneck planner, accepted candidate, analysis and native recording scripts
0049da5
28d ago
import sys,json,math,xml.etree.ElementTree as ET
from pathlib import Path
from shapely.geometry import LineString
P=Path(__file__).resolve().parent;sys.path.insert(0,str(P.parent/'thermal-expansion'));from analyze import copper,regions
from thermal_model import mesh,solve
B=P.parent/'thermal-expansion/recording/bq25792-expanded-thermal.brd';F=P/'candidate-01/filled.brd'
a=ET.parse(B).find('drawing/board');b=ET.parse(F).find('drawing/board')
unchanged=['elements','libraries','designrules','classes'];result={'preserved':{tag:ET.tostring(a.find(tag))==ET.tostring(b.find(tag)) for tag in unchanged}}
for key,xpath in [('vias','signals/signal/via'),('pads','signals/signal/contactref')]:
def get(x):return sorted((s.get('name'),tuple(sorted(i.attrib.items()))) for s in x.findall('signals/signal') for i in s.findall('via' if key=='vias' else 'contactref'))
result['preserved'][key]=get(a)==get(b)
exceptions=[]
for s in b.findall('signals/signal'):
for w in s.findall('wire'):
dx=float(w.get('x2'))-float(w.get('x1'));dy=float(w.get('y2'))-float(w.get('y1'))
angle=math.degrees(math.atan2(dy,dx))%45;err=min(angle,45-angle)
if err>.02:exceptions.append({'net':s.get('name'),'angleError':err})
result['offAngleSegments']=exceptions
result['coverage']={label:{str(l):sum(g.area for g in copper(f,l).values())/(50.4*26.4)*100 for l in [1,2,15,16]} for label,f in [('before',B),('after',F)]}
ref=copper(F,2)['PGND'];result['routeReferenceScreening']=[]
for r in json.loads((P/'candidate-01/plan.json').read_text()):
line=LineString(r['points']);before=sum(math.hypot(float(w['x2'])-float(w['x1']),float(w['y2'])-float(w['y1'])) for w in r['removed'])
result['routeReferenceScreening'].append({'net':r['net'],'layer':r['layer'],'oldLengthMm':before,'newLengthMm':line.length,'lengthOverLayer2PGNDPercent':line.intersection(ref).length/line.length*100 if r['layer']==15 else None})
result['meshSensitivity']={}
for n,r in regions(F).items():
q=solve(mesh(r['geometry'],r['sources'],.075),5,.8)[0];result['meshSensitivity'][n]=q
(P/'candidate-01/audit.json').write_text(json.dumps(result,indent=2));print(json.dumps(result,indent=2))