288 lines
10 KiB
C#
288 lines
10 KiB
C#
|
|
using Aitex.Core.RT.DataCenter;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
|
|||
|
|
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps
|
|||
|
|
{
|
|||
|
|
public enum DataType
|
|||
|
|
{
|
|||
|
|
Wafer,
|
|||
|
|
Tray,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 测温点位置
|
|||
|
|
/// </summary>
|
|||
|
|
public enum EnumZoneNum
|
|||
|
|
{
|
|||
|
|
Center,
|
|||
|
|
CenterEdge,
|
|||
|
|
Edge
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class AKunTriggerChannelWaferTempData
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 创建通道对应的单个晶圆温度对象
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="waferNum">晶圆编号</param>
|
|||
|
|
/// <param name="ch">测温设备通道编号</param>
|
|||
|
|
/// <param name="name">当前晶圆对象的名称,Wafer or Tray,测温对象也能反馈Tray温度</param>
|
|||
|
|
public AKunTriggerChannelWaferTempData(int waferNum, int ch = 1, string name = "Wafer")
|
|||
|
|
{
|
|||
|
|
Detector = ch;
|
|||
|
|
WaferNum = waferNum;
|
|||
|
|
WaferName = $"CH{Detector}.{name}{waferNum}"; //eg: CH1.Wafer1 CH1.Wafer2 CH2.Wafer1 CH2.Wafer2
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 通道编号,默认为1
|
|||
|
|
/// </summary>
|
|||
|
|
public int Detector { get; set; }
|
|||
|
|
|
|||
|
|
public string WaferName { get; set; }
|
|||
|
|
|
|||
|
|
public int WaferNum { get; set; }
|
|||
|
|
|
|||
|
|
public DataType Type { get; set; }
|
|||
|
|
|
|||
|
|
public double Temp { get; set; }
|
|||
|
|
|
|||
|
|
public int ZoneNum { get; set; }
|
|||
|
|
|
|||
|
|
public EnumZoneNum ZoneNumSelect { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 0表示无效晶圆代表Dummy晶圆或者空位,此位置的温度不能参与STC控温
|
|||
|
|
/// </summary>
|
|||
|
|
public int PocketNum { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// The reflection of 404nm
|
|||
|
|
/// </summary>
|
|||
|
|
public double Reflect1 { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// The reflection of 633nm.
|
|||
|
|
/// </summary>
|
|||
|
|
public double Reflect2 { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// The reflection of 950nm.
|
|||
|
|
/// </summary>
|
|||
|
|
public double Reflect3 { get; set; }
|
|||
|
|
|
|||
|
|
public double Curvature { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// false不参与控温,晶圆温度是否参与区域计算,不放片或者放Dummy时,不参与区域计算
|
|||
|
|
/// </summary>
|
|||
|
|
public bool CalZone { get; set; }
|
|||
|
|
|
|||
|
|
public void UpData(AKunTriggerChannelWaferTempData newData)
|
|||
|
|
{
|
|||
|
|
// 确保传入的 newData 对象不为空
|
|||
|
|
if (newData == null)
|
|||
|
|
{
|
|||
|
|
throw new ArgumentNullException(nameof(newData));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Detector = newData.Detector;
|
|||
|
|
WaferNum = newData.WaferNum;
|
|||
|
|
Temp = newData.Temp;
|
|||
|
|
ZoneNum = newData.ZoneNum;
|
|||
|
|
ZoneNumSelect = newData.ZoneNumSelect;
|
|||
|
|
Reflect1 = newData.Reflect1;
|
|||
|
|
Curvature = newData.Curvature;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class AKunTriggerTempDataManager(int waferNum, double minTemp)
|
|||
|
|
{
|
|||
|
|
private readonly int _waferNum = waferNum;
|
|||
|
|
private double _minTemp = minTemp;
|
|||
|
|
|
|||
|
|
private List<AKunTriggerChannelWaferTempData> _waferTempDataList = new();
|
|||
|
|
private static readonly object _lock = new object();
|
|||
|
|
|
|||
|
|
#region 重新整理温度解析
|
|||
|
|
|
|||
|
|
public bool ProcessReceivedData(string tcpReceive)
|
|||
|
|
{
|
|||
|
|
lock (_lock)
|
|||
|
|
{
|
|||
|
|
List<AKunTriggerChannelWaferTempData> tempDataList = new List<AKunTriggerChannelWaferTempData>();
|
|||
|
|
AKunTriggerChannelWaferTempData aKunChWaferTempData;
|
|||
|
|
string[] keyValuePairs = tcpReceive.Split('\0');
|
|||
|
|
|
|||
|
|
for (int i = 0; i < keyValuePairs.Length - 1; i++)
|
|||
|
|
{
|
|||
|
|
aKunChWaferTempData = new AKunTriggerChannelWaferTempData(-999);
|
|||
|
|
string[] keyValues = keyValuePairs[i].Split(',');
|
|||
|
|
foreach (string pair in keyValues)
|
|||
|
|
{
|
|||
|
|
string[] keyValue = pair.Split('=');
|
|||
|
|
switch (keyValue[0])
|
|||
|
|
{
|
|||
|
|
case "Detector":
|
|||
|
|
aKunChWaferTempData.Detector = int.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "PocketNum":
|
|||
|
|
aKunChWaferTempData.PocketNum = int.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "WaferNum":
|
|||
|
|
aKunChWaferTempData.WaferNum = int.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "CalZone":
|
|||
|
|
aKunChWaferTempData.CalZone = int.Parse(keyValue[1]) == 1;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "TTemp":
|
|||
|
|
aKunChWaferTempData.Temp = double.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "ZoneNum":
|
|||
|
|
aKunChWaferTempData.ZoneNum = int.Parse(keyValue[1]);
|
|||
|
|
aKunChWaferTempData.ZoneNumSelect =
|
|||
|
|
(EnumZoneNum)Enum.Parse(typeof(EnumZoneNum), keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "Reflec1":
|
|||
|
|
aKunChWaferTempData.Reflect1 = double.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "Reflec2":
|
|||
|
|
aKunChWaferTempData.Reflect2 = double.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "Reflec3":
|
|||
|
|
aKunChWaferTempData.Reflect3 = double.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case "Curvature":
|
|||
|
|
aKunChWaferTempData.Curvature = double.Parse(keyValue[1]);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (aKunChWaferTempData.WaferNum == -999)
|
|||
|
|
return true;
|
|||
|
|
|
|||
|
|
tempDataList.Add(aKunChWaferTempData);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_waferTempDataList = tempDataList;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public bool[] GetCalZone()
|
|||
|
|
{
|
|||
|
|
bool[] calZone = new bool[_waferNum];
|
|||
|
|
if (_waferTempDataList.Count < _waferNum)
|
|||
|
|
return calZone;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < _waferNum; i++) //只有前面几个数据,是需要统计是否参与计算
|
|||
|
|
{
|
|||
|
|
calZone[i] = _waferTempDataList[i].CalZone;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return calZone;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//public double[] GetWaferTemp()
|
|||
|
|
//{
|
|||
|
|
// double[] waferTemps = Enumerable.Repeat(_minTemp, _waferNum).ToArray();
|
|||
|
|
// if (_waferTempDataList.Count < _waferNum)
|
|||
|
|
// return waferTemps;
|
|||
|
|
|
|||
|
|
// int count = (_waferTempDataList.Count - 1) / _waferNum ;//分区数计算,最后一个数据是托盘的,所以减一,
|
|||
|
|
// if ((_waferTempDataList.Count - 1) % _waferNum != 0)//分区数量不是整数,温度不解析防呆,
|
|||
|
|
// return waferTemps;
|
|||
|
|
|
|||
|
|
// for (int i = 0; i < _waferNum; i++) //Wafer温度只取每个晶圆的第一个设置的中心温度
|
|||
|
|
// {
|
|||
|
|
// var index = i * count;
|
|||
|
|
// waferTemps[i] = _waferTempDataList[index].Temp;//直接使用第一个中心温度作为中心温度
|
|||
|
|
|
|||
|
|
// //要求不判断中心点,只用第一个分区温度
|
|||
|
|
// //for (int j = index; j < index + count ; j++)
|
|||
|
|
// //{
|
|||
|
|
// // if(_waferTempDataList[j].ZoneNum==0)
|
|||
|
|
// // {
|
|||
|
|
// // waferTemps[i] = _waferTempDataList[j].Temp;//有中心温度设置,获取第一个中心温度作为晶圆温度
|
|||
|
|
// // break;
|
|||
|
|
// // }
|
|||
|
|
// //}
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// return waferTemps;
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
public double[] GetWaferTemp()
|
|||
|
|
{
|
|||
|
|
double[] waferTemps = Enumerable.Repeat(_minTemp, _waferNum).ToArray();
|
|||
|
|
if (_waferTempDataList.Count < _waferNum)
|
|||
|
|
return waferTemps;
|
|||
|
|
|
|||
|
|
//这届
|
|||
|
|
for (int i = 0; i < _waferNum; i++) //只有前面几个温度数据,才是需要统计的
|
|||
|
|
{
|
|||
|
|
waferTemps[i] = _waferTempDataList[i].Temp;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//_waferTempDataList[i].CalZone
|
|||
|
|
//for (int i = 0; i < _waferNum; i++)
|
|||
|
|
//{
|
|||
|
|
// //根据编号,获取同一分区所有温度数据
|
|||
|
|
// var tempCaches = _waferTempDataList.Where(item => item.PocketNum == i + 1);
|
|||
|
|
// if (tempCaches != null && tempCaches.Count() > 0)
|
|||
|
|
// {
|
|||
|
|
// //同一分区所有温度数据,查找第一个CalZone为true的温度数据
|
|||
|
|
// var matchedItem = tempCaches.Where(item => item.CalZone).FirstOrDefault();
|
|||
|
|
|
|||
|
|
// if (matchedItem != null)
|
|||
|
|
// waferTemps[i] = matchedItem.Temp;
|
|||
|
|
// else
|
|||
|
|
// waferTemps[i] = tempCaches.First().Temp;//未设置CalZone为true,使用当前分区第一个数据作为默认温度值
|
|||
|
|
// }
|
|||
|
|
// else
|
|||
|
|
// waferTemps[i] = -1;//没有分区温度是乱的无法解析,使用-1作为提示
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
return waferTemps;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public double GetTrayTemp()
|
|||
|
|
{
|
|||
|
|
if (_waferTempDataList.Count == 0)
|
|||
|
|
return _minTemp;
|
|||
|
|
|
|||
|
|
return _waferTempDataList[_waferTempDataList.Count - 1].Temp; //最后一个数据才是Tray温度
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion 重新整理温度解析
|
|||
|
|
|
|||
|
|
public List<double[]> GetReflectValue()
|
|||
|
|
{
|
|||
|
|
List<double[]> reflectList = Enumerable.Range(0, _waferNum)
|
|||
|
|
.Select(_ => new double[3]) // 每个数组默认元素为 0
|
|||
|
|
.ToList();
|
|||
|
|
if (_waferTempDataList.Count < _waferNum)
|
|||
|
|
return reflectList;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < _waferNum; i++) //只有前面几个反射率数据,才是需要统计的
|
|||
|
|
{
|
|||
|
|
var data = _waferTempDataList[i];
|
|||
|
|
reflectList.Add([data.Reflect1, data.Reflect2, data.Reflect3]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return reflectList;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|