已知量有:晶圆的Die Size和Gross Die数量和针卡工位数,需计算出需要的Touchdown的总次数。
简单而言就是,将指定尺寸的小矩形拼接成近似圆的形状,然后用大矩阵进行扫描,要求将所有圆都扫描覆盖到。大矩形只能上下左右移动,且移动单位至少是其长或宽,每个小矩形只能被扫描一次。
结果展示:

实现代码:
import tkinter as tk
from tkinter import ttk
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文
plt.rcParams['axes.unicode_minus'] = False # 负号正常显示
def simulate_scan(rect_w, rect_h, num_rects, scan_w, scan_h):
total_area = rect_w * rect_h * num_rects
radius = np.sqrt(total_area / np.pi)
cols = int(2 * radius // rect_w) + 2
rows = int(2 * radius // rect_h) + 2
center_x = cols * rect_w / 2
center_y = rows * rect_h / 2
rect_positions = []
for r in range(rows):
for c in range(cols):
cx = c * rect_w + rect_w / 2
cy = r * rect_h + rect_h / 2
if (cx - center_x) ** 2 + (cy - center_y) ** 2 <= radius ** 2:
rect_positions.append((c, r))
if len(rect_positions) > num_rects:
rect_positions = rect_positions[:num_rects]
grid = np.zeros((rows, cols), dtype=int)
for (c, r) in rect_positions:
grid[r, c] = 1
scans = []
covered = np.zeros_like(grid)
rows_with_rects = np.where(np.any(grid == 1, axis=1))[0]
r = int(rows_with_rects[0]) if len(rows_with_rects) > 0 else 0
while r < rows:
r_end = min(rows, int(r + (scan_h + rect_h - 1) // rect_h))
rows_to_check = grid[r:r_end, :]
uncovered_mask = (rows_to_check == 1) & (covered[r:r_end, :] == 0)
if np.any(uncovered_mask):
cols_with_rects = np.where(np.any(uncovered_mask, axis=0))[0]
c_min = int(cols_with_rects[0])
c_max = int(cols_with_rects[-1])
c = c_min
while c <= c_max:
c_end = int(c + (scan_w + rect_w - 1) // rect_w)
scans.append((c * rect_w, r * rect_h))
covered[r:r_end, c:c_end] = np.maximum(
covered[r:r_end, c:c_end],
grid[r:r_end, c:c_end]
)
c = c_end
r += int((scan_h + rect_h - 1) // rect_h)
return scans, rect_positions, cols, rows
def plot_scan(ax, rect_positions, scans, rect_w, rect_h, scan_w, scan_h, cols, rows, title, color):
ax.clear()
for (c, r) in rect_positions:
ax.add_patch(plt.Rectangle((c * rect_w, r * rect_h), rect_w, rect_h,
facecolor='lightgray', edgecolor='black'))
for idx, (x, y) in enumerate(scans):
ax.add_patch(plt.Rectangle((x, y), scan_w, scan_h,
fill=False, edgecolor='red', linewidth=1.2))
ax.text(x + scan_w / 2, y + scan_h / 2, str(idx + 1),
ha='center', va='center', fontsize=6, color='red')
ax.set_aspect('equal')
ax.set_xlim(0, cols * rect_w)
ax.set_ylim(0, rows * rect_h)
ax.invert_yaxis()
ax.set_title(title, fontsize=10, color=color)
def calculate_and_plot():
try:
rect_w = float(entry_rect_w.get())
rect_h = float(entry_rect_h.get())
num_rects = int(entry_num_rects.get())
scan_w1 = float(entry_scan_w.get()) * rect_w
scan_h1 = float(entry_scan_h.get()) * rect_h
scan_w2 = float(entry_scan_h.get()) * rect_w
scan_h2 = float(entry_scan_w.get()) * rect_h
scans1, rects1, cols1, rows1 = simulate_scan(rect_w, rect_h, num_rects, scan_w1, scan_h1)
scans2, rects2, cols2, rows2 = simulate_scan(rect_w, rect_h, num_rects, scan_w2, scan_h2)
min_scans = min(len(scans1), len(scans2))
color1 = 'red' if len(scans1) == min_scans else 'black'
color2 = 'red' if len(scans2) == min_scans else 'black'
plot_scan(ax1, rects1, scans1, rect_w, rect_h, scan_w1, scan_h1, cols1, rows1,
f"正常排布: {len(scans1)} 次扫描", color1)
plot_scan(ax2, rects2, scans2, rect_w, rect_h, scan_w2, scan_h2, cols2, rows2,
f"旋转: {len(scans2)} 次扫描", color2)
canvas.draw()
except ValueError:
ax1.clear()
ax2.clear()
ax1.set_title("输入有误,请检查参数", fontsize=12, color='red')
ax2.set_title("", fontsize=12)
canvas.draw()
核心代码解释simulate_scan:

6710

被折叠的 条评论
为什么被折叠?



