[Report] Added support for Eurocircuits drill adjust to fix small OARs.

Closes #227
This commit is contained in:
Salvador E. Tropea 2022-09-08 11:37:58 -03:00
parent 51885ccb71
commit 42aa142a56
9 changed files with 77 additions and 19 deletions

View File

@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Support for Eurocircuits drill adjust to fix small OARs.
Option `eurocircuits_reduce_holes`. (#227)
## [1.3.0] - 2022-09-08

View File

@ -32,6 +32,10 @@ from . import log
logger = log.get_logger()
INF = float('inf')
# This OAR is the minimum Eurocircuits does without extra charge
EC_SMALL_OAR = 0.125*pcbnew.IU_PER_MM
# The minimum drill tool
EC_MIN_DRILL = 0.1*pcbnew.IU_PER_MM
def do_round(v, dig):
@ -194,6 +198,10 @@ class ReportOptions(BaseOptions):
Note that the extension should match the `convert_to` value """
self.eurocircuits_class_target = '10F'
""" Which Eurocircuits class are we aiming at """
self.eurocircuits_reduce_holes = 0.45
""" When computing the Eurocircuits category: Final holes sizes smaller or equal to this given
diameter can be reduced to accommodate the correct annular ring values.
Use 0 to disable it """
super().__init__()
self._expand_id = 'report'
self._expand_ext = 'txt'
@ -463,6 +471,20 @@ class ReportOptions(BaseOptions):
self.bb_w = x2-x1
self.bb_h = y2-y1
def compute_oar(self, pad, hole):
""" Compute the OAR and the corrected OAR for Eurocircuits """
oar_ec = oar = (pad-hole)/2
if oar < EC_SMALL_OAR and oar > 0 and hole < self.eurocircuits_reduce_holes*pcbnew.IU_PER_MM:
# This hole is classified as "via hole" and has a problematic OAR
hole_ec = max(adjust_drill(pad-2*EC_SMALL_OAR, is_pth=False), EC_MIN_DRILL)
oar_ec = (pad-hole_ec)/2
if GS.debug_level > 2:
logger.debug('Adjusting drill from {} to {} to get an OAR of {}'.
format(to_mm(hole), to_mm(hole_ec), to_mm(oar_ec)))
else:
hole_ec = hole
return oar, oar_ec, hole_ec
def collect_data(self, board):
ds = board.GetDesignSettings()
self.extra_pth_drill = GS.global_extra_pth_drill*pcbnew.IU_PER_MM
@ -505,10 +527,12 @@ class ReportOptions(BaseOptions):
###########################################################
self.track_d = ds.m_TrackMinWidth
tracks = board.GetTracks()
self.oar_vias = self.track = INF
self.oar_vias = self.oar_vias_ec = self.track = INF
self._vias = {}
self._vias_ec = {}
self._tracks_m = {}
self._drills_real = {}
self._drills_ec = {}
track_type = 'TRACK' if GS.ki5 else 'PCB_TRACK'
via_type = 'VIA' if GS.ki5 else 'PCB_VIA'
for t in tracks:
@ -522,8 +546,13 @@ class ReportOptions(BaseOptions):
via_id = (via.GetDrill(), via.GetWidth())
self._vias[via_id] = self._vias.get(via_id, 0) + 1
d = adjust_drill(via_id[0])
self.oar_vias = min(self.oar_vias, (via_id[1] - d) / 2)
oar, oar_ec, d_ec = self.compute_oar(via_id[1], d)
via_id_ec = (d_ec, via_id[1])
self._vias_ec[via_id_ec] = self._vias.get(via_id_ec, 0) + 1
self.oar_vias = min(self.oar_vias, oar)
self.oar_vias_ec = min(self.oar_vias_ec, oar_ec)
self._drills_real[d] = self._drills_real.get(d, 0) + 1
self._drills_ec[d_ec] = self._drills_ec.get(d_ec, 0) + 1
self.track_min = min(self.track_d, self.track)
###########################################################
# Drill (min)
@ -531,7 +560,7 @@ class ReportOptions(BaseOptions):
modules = board.GetModules() if GS.ki5 else board.GetFootprints()
self._drills = {}
self._drills_oval = {}
self.oar_pads = self.pad_drill = self.pad_drill_real = INF
self.oar_pads = self.oar_pads_ec = self.pad_drill = self.pad_drill_real = self.pad_drill_real_ec = INF
self.slot = INF
self.top_smd = self.top_tht = self.bot_smd = self.bot_tht = 0
top_layer = board.GetLayerID('F.Cu')
@ -581,11 +610,16 @@ class ReportOptions(BaseOptions):
# print('{} @ {}'.format(dr, pad.GetPosition()))
self._drills_real[d_r] = self._drills_real.get(d_r, 0) + 1
pad_sz = pad.GetSize()
oar_x = (pad_sz.x - dr_x_real) / 2
oar_y = (pad_sz.y - dr_y_real) / 2
oar_x, oar_ec_x, dr_x_ec = self.compute_oar(pad_sz.x, dr_x_real)
oar_y, oar_ec_y, dr_y_ec = self.compute_oar(pad_sz.y, dr_y_real)
dr_ec = min(dr_x_ec, dr_y_ec)
self._drills_ec[dr_ec] = self._drills_ec.get(dr_ec, 0) + 1
self.pad_drill_real_ec = min(dr_ec, self.pad_drill_real_ec)
oar_t = min(oar_x, oar_y)
oar_ec_t = min(oar_ec_x, oar_ec_y)
if oar_t > 0:
self.oar_pads = min(self.oar_pads, oar_t)
self.oar_pads_ec = min(self.oar_pads_ec, oar_ec_t)
if oar_t < min_oar:
logger.warning(W_WRONGOAR+"Really small OAR detected ({} mm) for pad {}".
format(to_mm(oar_t, 4), get_pad_info(pad)))
@ -594,6 +628,7 @@ class ReportOptions(BaseOptions):
elif oar_t == 0 and is_pth:
logger.warning(W_WRONGOAR+"Plated pad without copper "+get_pad_info(pad))
self._vias_m = sorted(self._vias.keys())
self._vias_ec_m = sorted(self._vias_ec.keys())
# Via Pad size
self.via_pad_d = ds.m_ViasMinSize
self.via_pad = self._vias_m[0][1] if self._vias_m else INF
@ -603,14 +638,18 @@ class ReportOptions(BaseOptions):
self.via_drill_d = ds.m_ViasMinDrill if GS.ki5 else ds.m_MinThroughDrill
self.via_drill = self._vias_m[0][0] if self._vias_m else INF
self.via_drill_min = min(self.via_drill_d, self.via_drill)
self.via_drill_real_ec = self.via_drill_ec = self._vias_ec_m[0][0] if self._vias_ec_m else INF
self.via_drill_ec_min = min(self.via_drill_d, self.via_drill_ec)
# Via Drill size before platting
self.via_drill_real_d = adjust_drill(self.via_drill_d)
self.via_drill_real = adjust_drill(self.via_drill)
self.via_drill_real_min = adjust_drill(self.via_drill_min)
self.via_drill_real_ec_min = adjust_drill(self.via_drill_ec_min)
# Pad Drill
# No minimum defined (so no _d)
self.pad_drill_min = self.pad_drill if GS.ki5 else ds.m_MinThroughDrill
self.pad_drill_real_min = self.pad_drill_real if GS.ki5 else adjust_drill(ds.m_MinThroughDrill, False)
self.pad_drill_real_ec_min = self.pad_drill_real_ec if GS.ki5 else adjust_drill(ds.m_MinThroughDrill, False)
# Drill overall
self.drill_d = min(self.via_drill_d, self.pad_drill)
self.drill = min(self.via_drill, self.pad_drill)
@ -619,6 +658,9 @@ class ReportOptions(BaseOptions):
self.drill_real_d = min(self.via_drill_real_d, self.pad_drill_real)
self.drill_real = min(self.via_drill_real, self.pad_drill_real)
self.drill_real_min = min(self.via_drill_real_min, self.pad_drill_real_min)
self.drill_real_ec_d = min(self.via_drill_real_d, self.pad_drill_real_ec)
self.drill_real_ec = min(self.via_drill_real_ec, self.pad_drill_real_ec)
self.drill_real_ec_min = min(self.via_drill_real_ec_min, self.pad_drill_real_ec_min)
self.top_comp_type = to_smd_tht(self.top_smd, self.top_tht)
self.bot_comp_type = to_smd_tht(self.bot_smd, self.bot_tht)
###########################################################
@ -631,13 +673,15 @@ class ReportOptions(BaseOptions):
via_sizes = board.GetViasDimensionsList()
self._vias_defined = set()
self._via_sizes_sorted = []
self.oar_vias_d = INF
self.oar_vias_d = self.oar_vias_ec_d = INF
for v in sorted(via_sizes, key=lambda x: (x.m_Diameter, x.m_Drill)):
d = v.m_Diameter
h = v.m_Drill
if not d and not h:
continue # KiCad 6
self.oar_vias_d = min(self.oar_vias_d, (d - adjust_drill(h)) / 2)
oar, oar_ec, _ = self.compute_oar(d, adjust_drill(h))
self.oar_vias_d = min(self.oar_vias_d, oar)
self.oar_vias_ec_d = min(self.oar_vias_ec_d, oar_ec)
self._vias_defined.add((h, d))
self._via_sizes_sorted.append((h, d))
###########################################################
@ -648,18 +692,24 @@ class ReportOptions(BaseOptions):
self.oar = min(self.oar_vias, self.oar_pads)
self.oar_min = min(self.oar_d, self.oar)
self.oar_vias_min = min(self.oar_vias_d, self.oar_vias)
# Eurocircuits OAR
self.oar_pads_ec_min = self.oar_pads_ec
self.oar_ec_d = min(self.oar_vias_ec_d, self.oar_pads_ec)
self.oar_ec = min(self.oar_vias_ec, self.oar_pads_ec)
self.oar_ec_min = min(self.oar_ec_d, self.oar_ec)
self.oar_vias_ec_min = min(self.oar_vias_ec_d, self.oar_vias_ec)
###########################################################
# Eurocircuits class
# https://www.eurocircuits.com/pcb-design-guidelines-classification/
###########################################################
# Pattern class
self.pattern_class_min = get_pattern_class(self.track_min, self.clearance, self.oar_min, 'minimum')
self.pattern_class = get_pattern_class(self.track, self.clearance, self.oar, 'measured', self._ec_pat)
self.pattern_class_d = get_pattern_class(self.track_d, self.clearance, self.oar_d, 'defined')
self.pattern_class_min = get_pattern_class(self.track_min, self.clearance, self.oar_ec_min, 'minimum')
self.pattern_class = get_pattern_class(self.track, self.clearance, self.oar_ec, 'measured', self._ec_pat)
self.pattern_class_d = get_pattern_class(self.track_d, self.clearance, self.oar_ec_d, 'defined')
# Drill class
self.drill_class_min = get_drill_class(self.drill_real_min, 'minimum')
self.drill_class = get_drill_class(self.drill_real, 'measured', self._ec_drl)
self.drill_class_d = get_drill_class(self.drill_real_d, 'defined')
self.drill_class_min = get_drill_class(self.drill_real_ec_min, 'minimum')
self.drill_class = get_drill_class(self.drill_real_ec, 'measured', self._ec_drl)
self.drill_class_d = get_drill_class(self.drill_real_ec_d, 'defined')
###########################################################
# General stats
###########################################################

View File

@ -69,6 +69,7 @@ Outer Annular Ring: ${oar_mm} mm (${oar_mils} mils)
- By design rules: ${oar_d_mm} mm (${oar_d_mils} mils)
Eurocircuits class: ${pattern_class}${drill_class}
- Using min drill ${drill_real_ec_mm} mm for an OAR of ${oar_ec_mm} mm
# General stats

View File

@ -42,7 +42,8 @@ Outer Annular Ring: 0.08 mm (3 mils)
- By design rules: 0.08 mm (3 mils)
Eurocircuits class: 10C
Eurocircuits class: 6D
- Using min drill 0.25 mm for an OAR of 0.13 mm
# General stats

View File

@ -42,7 +42,8 @@ Outer Annular Ring: 0.08 mm (3 mils)
- By design rules: 0.08 mm (3 mils)
Eurocircuits class: 10C
Eurocircuits class: 6D
- Using min drill 0.25 mm for an OAR of 0.13 mm
# General stats

View File

@ -3,7 +3,7 @@ Size:
- 59.69x48.26 mm
Class: 10C
Class: 6D
Track width: ≥ 0.15 mm

View File

@ -67,7 +67,8 @@ Outer Annular Ring: 0.08 mm (3 mils)
- By design rules: 0.08 mm (3 mils)
Eurocircuits class: 10C
Eurocircuits class: 6D
- Using min drill 0.25 mm for an OAR of 0.13 mm
# General stats

View File

@ -67,7 +67,8 @@ Outer Annular Ring: 0.08 mm (3 mils)
- By design rules: 0.08 mm (3 mils)
Eurocircuits class: 10C
Eurocircuits class: 6D
- Using min drill 0.25 mm for an OAR of 0.13 mm
# General stats

View File

@ -3,7 +3,7 @@ Size:
- 59.69x48.26 mm
Class: 10C
Class: 6D
Track width: ≥ 0.15 mm