CP测试Touchdown次数预估计算器

该文章已生成可运行项目,

已知量有:晶圆的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:

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小馆长布鲁克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值