63 lines
1.9 KiB
Python
63 lines
1.9 KiB
Python
"""Cluster Average utility for wafer sensor values."""
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
|
|
from pygui.backend.wafer.zwafer_models import Sensor
|
|
|
|
|
|
def average_clusters(values: list[float], clusters: list[list[int]]) -> list[float]:
|
|
"""Return a new list of values where members of each cluster are replaced by their mean.
|
|
|
|
NaN values are filtered out before computing the mean.
|
|
If all values in a cluster are NaN, they remain NaN.
|
|
"""
|
|
result = list(values)
|
|
for cluster in clusters:
|
|
valid_vals = []
|
|
for idx in cluster:
|
|
if idx < len(values):
|
|
val = values[idx]
|
|
if not math.isnan(val):
|
|
valid_vals.append(val)
|
|
|
|
if valid_vals:
|
|
mean_val = sum(valid_vals) / len(valid_vals)
|
|
for idx in cluster:
|
|
if idx < len(result):
|
|
result[idx] = mean_val
|
|
return result
|
|
|
|
|
|
def group_sensors_by_radius(sensors: list[Sensor], tolerance: float = 2.0) -> list[list[int]]:
|
|
"""Group sensor indices into clusters if their radial distances are within tolerance."""
|
|
# Compute radii for all sensors
|
|
radii = [(i, math.hypot(s.x, s.y)) for i, s in enumerate(sensors)]
|
|
# Filter out center sensors (r < 1.0)
|
|
non_center = [item for item in radii if item[1] >= 1.0]
|
|
if not non_center:
|
|
return []
|
|
|
|
# Sort by radius
|
|
non_center.sort(key=lambda x: x[1])
|
|
|
|
clusters: list[list[int]] = []
|
|
current_cluster: list[int] = [non_center[0][0]]
|
|
last_r = non_center[0][1]
|
|
|
|
for idx, r in non_center[1:]:
|
|
if r - last_r <= tolerance:
|
|
current_cluster.append(idx)
|
|
else:
|
|
if len(current_cluster) > 1:
|
|
clusters.append(current_cluster)
|
|
current_cluster = [idx]
|
|
last_r = r
|
|
|
|
if len(current_cluster) > 1:
|
|
clusters.append(current_cluster)
|
|
|
|
return clusters
|