using Cognex.VisionPro; using Cognex.VisionPro.ToolBlock; using MaterialDesignThemes.Wpf; using MathNet.Numerics; using Prism.Commands; using Prism.Events; using Prism.Ioc; using Prism.Mvvm; using Prism.Regions; using Prism.Services.Dialogs; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Team.FFFeederService.Interfaces; using TeamAAS_VP.Core; using TeamAAS_VP.Core.PLCs; using TeamAAS_VP.Enums; using TeamAAS_VP.Interfaces; using TeamAAS_VP.Models; using TeamAAS_VP.Resources.Languages; using TeamAAS_VP.Services; using static TeamAAS_VP.Core.StabilityAnalyzer; namespace TeamAAS_VP.ViewModels.Product { public class VisionDynamicAccuracyAnalyzerViewModel : BindableBase, IDialogAware { IRegionManager _regionManager; IEventAggregator _eventAggregator; IContainerProvider _container; IDialogService _dialogService; IFeederService _feederService; IRobotService _robotService; ICameraService _cameraService; ISystemDatabaseService _systemDatabaseService; ICalibrationService _calibrationService; IConfigService _configService; IPlcService _plcService; //测试过程中控制取消的CTS CancellationTokenSource _cts; #region 属性 private float _Distance; public float Distance { get { return _Distance; } set { SetProperty(ref _Distance, value); } } private bool _IsVertical = true; /// /// 是否启用垂直精度检测 /// public bool IsVertical { get { return _IsVertical; } set { SetProperty(ref _IsVertical, value); } } private ProductModel _SelectProduct; public ProductModel SelectProduct { get { return _SelectProduct; } set { SetProperty(ref _SelectProduct, value); } } private ICogImage _Image; public ICogImage Image { get { return _Image; } set { SetProperty(ref _Image, value); } } private Cognex.VisionPro.CogGraphicCollection _Graphic; public Cognex.VisionPro.CogGraphicCollection Graphic { get { return _Graphic; } set { SetProperty(ref _Graphic, value); } } private ProcedureModel _SelectProcedure; /// /// 选中的流程 /// public ProcedureModel SelectProcedure { get { return _SelectProcedure; } set { SetProperty(ref _SelectProcedure, value); } } private ICamera _Camera; public ICamera Camera { get { return _Camera; } set { SetProperty(ref _Camera, value); } } private IRobot _Robot; public IRobot Robot { get { return _Robot; } set { SetProperty(ref _Robot, value); } } private string _Message = "等待开始..."; public string Message { get { return _Message; } set { SetProperty(ref _Message, value); } } private bool _IsRunning; public bool IsRunning { get { return _IsRunning; } set { SetProperty(ref _IsRunning, value); } } private CogToolBlock _VisionTool; public CogToolBlock VisionTool { get { return _VisionTool; } set { SetProperty(ref _VisionTool, value); } } private int _RepeatCount = 10; /// /// 重复次数 /// public int RepeatCount { get { return _RepeatCount; } set { SetProperty(ref _RepeatCount, value); } } private int _CurrentProgress; /// /// 当前进度 /// public int CurrentProgress { get { return _CurrentProgress; } set { SetProperty(ref _CurrentProgress, value); } } private int _SuccessCount; /// /// 成功次数 /// public int SuccessCount { get { return _SuccessCount; } set { SetProperty(ref _SuccessCount, value); } } private int _FailCount; /// /// 失败次数 /// public int FailCount { get { return _FailCount; } set { SetProperty(ref _FailCount, value); } } private double _SuccessRate; /// /// 成功率 /// public double SuccessRate { get { return _SuccessRate; } set { SetProperty(ref _SuccessRate, value); } } private ObservableCollection _TestResults; /// /// 测试结果列表 /// public ObservableCollection TestResults { get { return _TestResults; } set { SetProperty(ref _TestResults, value); } } private SnackbarMessageQueue _MessageQueue; public SnackbarMessageQueue MessageQueue { get { return _MessageQueue; } set { SetProperty(ref _MessageQueue, value); } } private RPoint _PointA; public RPoint PointA { get { return _PointA; } set { SetProperty(ref _PointA, value); } } private RPoint _PointB; public RPoint PointB { get { return _PointB; } set { SetProperty(ref _PointB, value); } } private ObservableCollection _ProcedureModels; /// /// 流程集合 /// public ObservableCollection ProcedureModels { get { return _ProcedureModels; } set { SetProperty(ref _ProcedureModels, value); } } private int _MoveSpeed = 100; /// /// 移动速度 /// public int MoveSpeed { get { return _MoveSpeed; } set { SetProperty(ref _MoveSpeed, value); } } private double _CycleTime; /// /// 单次的时长 /// public double CycleTime { get { return _CycleTime; } set { SetProperty(ref _CycleTime, value); } } private PrecisionAnalysisResult _precisionResult = new PrecisionAnalysisResult(); /// /// 精度分析结果 /// public PrecisionAnalysisResult PrecisionResult { get { return _precisionResult; } set { SetProperty(ref _precisionResult, value); } } private bool _Is3DMode = false; /// /// 是否为3D模式(true=3D,false=2D) /// public bool Is3DMode { get { return _Is3DMode; } set { SetProperty(ref _Is3DMode, value); } } #endregion #region 命令 private DelegateCommand _ConfirmCommand; public DelegateCommand ConfirmCommand => _ConfirmCommand ?? (_ConfirmCommand = new DelegateCommand(ExecuteConfirmCommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _CancelCommand; public DelegateCommand CancelCommand => _CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _StartTestCommand; public DelegateCommand StartTestCommand => _StartTestCommand ?? (_StartTestCommand = new DelegateCommand(ExecuteStartTestCommand, CanExecuteStartTestCommand).ObservesProperty(() => IsRunning).ObservesProperty(() => SelectProcedure).ObservesProperty(() => PointA).ObservesProperty(() => PointB)); private DelegateCommand _StopTestCommand; public DelegateCommand StopTestCommand => _StopTestCommand ?? (_StopTestCommand = new DelegateCommand(() => { _cts?.Cancel(); }, () => IsRunning).ObservesProperty(() => IsRunning)); //暂停测试命令 private DelegateCommand _PauseTestCommand; public DelegateCommand PauseTestCommand => _PauseTestCommand ?? (_PauseTestCommand = new DelegateCommand(() => { _cts?.Cancel(); }, () => IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _ExportCSVCommand; public DelegateCommand ExportCSVCommand => _ExportCSVCommand ?? (_ExportCSVCommand = new DelegateCommand(ExecuteExportCSVCommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _ExportReportCommand; public DelegateCommand ExportReportCommand => _ExportReportCommand ?? (_ExportReportCommand = new DelegateCommand(ExecuteExportReportCommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _ClearDataCommand; public DelegateCommand ClearDataCommand => _ClearDataCommand ?? (_ClearDataCommand = new DelegateCommand(ExecuteClearDataCommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _TeachPointACommand; public DelegateCommand TeachPointACommand => _TeachPointACommand ?? (_TeachPointACommand = new DelegateCommand(ExecuteTeachPointACommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _TeachPointBCommand; public DelegateCommand TeachPointBCommand => _TeachPointBCommand ?? (_TeachPointBCommand = new DelegateCommand(ExecuteTeachPointBCommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _ProcedureSelectionChangedCommand; public DelegateCommand ProcedureSelectionChangedCommand => _ProcedureSelectionChangedCommand ?? (_ProcedureSelectionChangedCommand = new DelegateCommand(ExecuteProcedureSelectionChangedCommand, () => !IsRunning).ObservesProperty(() => IsRunning)); private DelegateCommand _SingleTestCommand; public DelegateCommand SingleTestCommand => _SingleTestCommand ?? (_SingleTestCommand = new DelegateCommand(ExecuteSingleTestCommand, () => !IsRunning && SelectProcedure != null && PointA != null && PointB != null).ObservesProperty(() => IsRunning).ObservesProperty(() => SelectProcedure).ObservesProperty(() => PointA).ObservesProperty(() => PointB)); private DelegateCommand _ShowTrendChartCommand; public DelegateCommand ShowTrendChartCommand => _ShowTrendChartCommand ?? (_ShowTrendChartCommand = new DelegateCommand(ExecuteShowTrendChartCommand)); #endregion #region 事件 #endregion public VisionDynamicAccuracyAnalyzerViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IDialogService dialogService, IFeederService feederService, IRobotService robotService, ICameraService cameraService, ISystemDatabaseService systemDatabaseService, ICalibrationService calibrationService, IConfigService configService, IPlcService plcService) { _regionManager = regionManager; _eventAggregator = ea; _container = container; _dialogService = dialogService; _feederService = feederService; _robotService = robotService; _cameraService = cameraService; _systemDatabaseService = systemDatabaseService; MessageQueue = new SnackbarMessageQueue(TimeSpan.FromSeconds(1)); _calibrationService = calibrationService; _plcService = plcService; _configService = configService; } #region 方法 /// /// 确定 /// void ExecuteConfirmCommand() { _cts?.Cancel(); IDialogParameters parameters = new DialogParameters(); //parameters.Add("Tool", Tool); //parameters.Add("RobotCameraRotationMatrix", RobotCameraRotationMatrix); //parameters.Add("Angle", Angle); RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters)); } /// /// 取消 /// void ExecuteCancelCommand() { _cts?.Cancel(); IDialogParameters parameters = new DialogParameters(); //parameters.Add("Tool", Tool); RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel, parameters)); } /// /// 单次测试 /// async void ExecuteSingleTestCommand() { var addressConfig = _configService.GetPlcAddresses(); var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; if (plc == null || !plc.IsConnected) return; if (Robot == null || !Robot.IsConnected) { SendTaskMessage("机器人未连接,无法示教!"); return; } if (Camera == null || !Camera.IsConnected) { SendTaskMessage("相机未连接,无法示教!"); return; } //弹窗提示是否进行单次测试 var result = System.Windows.MessageBox.Show("确定进行单次测试吗?", "提示", System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Question); if (result != System.Windows.MessageBoxResult.Yes) { return; } IsRunning = true; try { DateTime startTime = DateTime.Now; //为机器人设置移动速度 await Robot.CalibParameAsync(new PickInfo(), MoveSpeed, 0, false, 0, 0); //移动机器人至A点 bool isSuccess1 = await Robot.CalibMotionAsync(PointA, null); //if (!isSuccess1) //{ // SendTaskMessage("机器人移动到A点失败!"); // return; //} await Task.Delay(200); if (Is3DMode == true) { await plc.WriteNodeAsync(addressConfig.Out_mustart_3D_1.Address, true); } else { await plc.WriteNodeAsync(addressConfig.Out_mustart_3D_2.Address, true); } //移动机器人至B点 isSuccess1 = await Robot.CalibMotionAsync(PointB, null); //if (!isSuccess1) //{ // SendTaskMessage("机器人移动到B点失败!"); // return; //} await Task.Delay(300); var management = _container.Resolve(); var ctsAll = new CancellationTokenSource(); var camera = _configService.GetCamera(SelectProcedure.CameraId); //相机拍照并处理 (bool isSuccess, double pixelX, double pixelY, double angleU, double transformX, double transformY) = await ExecutePhotoEx(CurrentProgress); CycleTime = DateTime.Now.Subtract(startTime).TotalSeconds; } catch (Exception ex) { LogHelper.WriteLogError("机器人移动到A点失败!", ex); SendTaskMessage("机器人移动到A点失败!"); } finally { IsRunning = false; } } /// /// 连续测试 /// async void ExecuteStartTestCommand() { IsRunning = true; _cts = new CancellationTokenSource(); CurrentProgress = 0; SuccessCount = 0; SuccessRate = 0; FailCount = 0; Message = "测试进行中..."; TestResults = new ObservableCollection(); int i = 1; var addressConfig = _configService.GetPlcAddresses(); var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; if (plc == null || !plc.IsConnected) return; try { //弹窗提示是否进行连续测试 var result = System.Windows.MessageBox.Show("确定进行连续测试吗?", "提示", System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Question); if (result != System.Windows.MessageBoxResult.Yes) { return; } //为机器人设置移动速度 await Robot.CalibParameAsync(new PickInfo(), MoveSpeed, 0, false, 0, 0); while (CurrentProgress < RepeatCount) { if (_cts.Token.IsCancellationRequested) { Message = "测试已取消!"; break; } DateTime startTime = DateTime.Now; //移动机器人至A点 bool isSuccess1 = await Robot.CalibMotionAsync(PointA, null); //if (!isSuccess1) //{ // SendTaskMessage("机器人移动到A点失败!"); // return; //} await Task.Delay(200); if (Is3DMode == true) { await plc.WriteNodeAsync(addressConfig.Out_mustart_3D_1.Address, true); } else { await plc.WriteNodeAsync(addressConfig.Out_mustart_3D_2.Address, true); } if (_cts.Token.IsCancellationRequested) { Message = "测试已取消!"; break; } if (IsVertical == true) { RPoint verticalPosition = PointB.Clone(); verticalPosition.Z = verticalPosition.Z + (i) * Distance; i = i + 1; isSuccess1 = await Robot.CalibMotionAsync(verticalPosition, null); await Task.Delay(1000); if (_cts.Token.IsCancellationRequested) { Message = "测试已取消!"; break; } } else { //移动机器人至B点 isSuccess1 = await Robot.CalibMotionAsync(PointB, null); //if (!isSuccess1) //{ // SendTaskMessage("机器人移动到B点失败!"); // return; //} await Task.Delay(1000); if (_cts.Token.IsCancellationRequested) { Message = "测试已取消!"; break; } } //相机拍照并处理 (bool isSuccess, double pixelX, double pixelY, double angleU, double transformX, double transformY) = await ExecutePhotoEx(CurrentProgress); CycleTime = DateTime.Now.Subtract(startTime).TotalSeconds; if (isSuccess) { SuccessCount++; } else { FailCount++; } TestResults.Add(new DynamicTestResult(CurrentProgress, isSuccess, PointB, CycleTime, pixelX, pixelY, angleU, transformX, transformY)); OnTestResultAdded(); CurrentProgress++; SuccessRate = (double)SuccessCount / CurrentProgress * 100; SendTaskMessage($"测试进行中... {CurrentProgress}/{RepeatCount}"); } if (CurrentProgress >= RepeatCount) { Message = "测试完成!"; } } catch (Exception ex) { LogHelper.WriteLogError("视觉静态重复测试时出错!", ex); } finally { IsRunning = false; } } bool CanExecuteStartTestCommand() { return !IsRunning && SelectProcedure != null && PointA != null && PointB != null; } /// /// 清除数据 /// void ExecuteClearDataCommand() { if (TestResults != null) { TestResults.Clear(); } } /// /// 导出测试报告 /// 使用 iTextSharp 生成 PDF,包含:标题、测试摘要、数据表格、每列稳定性分析结果 /// 详细伪代码: /// 1. 校验 TestResults 是否存在且有数据,若无则提示并返回。 /// 2. 弹出保存对话框,获取 PDF 保存路径,若取消则返回。 /// 3. 使用 iTextSharp 创建 Document 和 PdfWriter,打开文档流。 /// 4. 尝试从系统字体目录加载中文字体(多候选),若加载失败使用回退字体。 /// 5. 写入标题(居中大号字体)和测试摘要信息(表格格式:导出时间、目标次数、当前进度、成功/失败次数、成功率)。 /// 6. 创建一个 PdfPTable,列为固定的测试结果字段(Index, Timestamp, IsPhotoSuccess, PointB.X/Y/Z, CycleTime, PixelX, PixelY, AngleU, TransformX, TransformY)。 /// - 写入表头(加粗) /// - 遍历 TestResults,每行按列顺序写入值(数值按 InvariantCulture 格式化,空值写空字符串) /// 7. 新页,写入“分析结果”标题。 /// 8. 对于需要分析的维度(TransformX, TransformY, AngleU): /// - 从 TestResults 过滤出 IsPhotoSuccess 为 true 的样本并收集对应维度值(double) /// - 若样本数为0,写明无法计算;否则调用 StabilityAnalyzer.AnalyzeStability(values) 获取 StabilityMetrics /// - 将 StabilityMetrics 的公开属性写成两列表(属性名 / 值)写入 PDF /// 9. 关闭并释放文档、writer、流,提示导出成功;捕获异常记录日志并提示失败。 /// 10. 使用 SendTaskMessage 在 UI 上通知结果。 /// void ExecuteExportReportCommand() { try { if (TestResults == null || TestResults.Count == 0) { SendTaskMessage("无测试数据,无法导出报告。"); return; } var dlg = new Microsoft.Win32.SaveFileDialog { DefaultExt = "pdf", Filter = "PDF 文件 (*.pdf)|*.pdf|所有文件 (*.*)|*.*", FileName = "TestReport.pdf", Title = "保存测试报告为 PDF" }; bool? dlgResult = dlg.ShowDialog(); if (dlgResult != true) return; string path = dlg.FileName; // 创建文档(A4, 边距) var doc = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4, 36, 36, 54, 54); using (var fs = System.IO.File.Create(path)) { var writer = iTextSharp.text.pdf.PdfWriter.GetInstance(doc, fs); doc.Open(); // 字体加载,优先中文系统字体 iTextSharp.text.Font titleFont; iTextSharp.text.Font headerFont; iTextSharp.text.Font normalFont; iTextSharp.text.pdf.BaseFont baseFont = null; try { var fontsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Fonts); var candidates = new[] { "msyh.ttf", "msyhbd.ttf", "simsun.ttc,0", "simsun.ttc,1", "Microsoft YaHei.ttf", "msyh.ttc,0", "msyh.ttc,1", "simhei.ttf" }; foreach (var f in candidates) { var path1 = Path.Combine(fontsFolder, f); try { baseFont = iTextSharp.text.pdf.BaseFont.CreateFont( path1, iTextSharp.text.pdf.BaseFont.IDENTITY_H, iTextSharp.text.pdf.BaseFont.EMBEDDED ); if (baseFont != null) break; } catch { continue; } } } catch { baseFont = null; } if (baseFont != null) { titleFont = new iTextSharp.text.Font(baseFont, 16, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK); headerFont = new iTextSharp.text.Font(baseFont, 10, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK); normalFont = new iTextSharp.text.Font(baseFont, 10, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLACK); } else { titleFont = iTextSharp.text.FontFactory.GetFont(iTextSharp.text.FontFactory.HELVETICA, 16, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK); headerFont = iTextSharp.text.FontFactory.GetFont(iTextSharp.text.FontFactory.HELVETICA, 10, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK); normalFont = iTextSharp.text.FontFactory.GetFont(iTextSharp.text.FontFactory.HELVETICA, 10, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLACK); } // 标题 var title = new iTextSharp.text.Paragraph("视觉动态精度测试报告", titleFont) { Alignment = iTextSharp.text.Element.ALIGN_CENTER, SpacingAfter = 12f }; doc.Add(title); // 测试摘要 var metaTable = new iTextSharp.text.pdf.PdfPTable(2) { WidthPercentage = 100f }; metaTable.SetWidths(new float[] { 1f, 2f }); void AddMeta(string name, string value) { var cellName = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(name, headerFont)) { Border = 0, PaddingBottom = 6f }; var cellVal = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(value, normalFont)) { Border = 0, PaddingBottom = 6f }; metaTable.AddCell(cellName); metaTable.AddCell(cellVal); } AddMeta("导出时间", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); AddMeta("测试次数(目标)", RepeatCount.ToString(System.Globalization.CultureInfo.InvariantCulture)); AddMeta("当前进度", $"{CurrentProgress} / {RepeatCount}"); AddMeta("成功次数", SuccessCount.ToString(System.Globalization.CultureInfo.InvariantCulture)); AddMeta("失败次数", FailCount.ToString(System.Globalization.CultureInfo.InvariantCulture)); AddMeta("成功率(%)", SuccessRate.ToString("F2", System.Globalization.CultureInfo.InvariantCulture)); doc.Add(metaTable); doc.Add(new iTextSharp.text.Paragraph(" ")); // 空行 // 数据表格列定义 var headers = new[] { "Index", "Timestamp", "IsPhotoSuccess", "PointB.X", "PointB.Y", "PointB.Z", "CycleTime(s)", "PixelX", "PixelY", "AngleU", "TransformX", "TransformY" }; var table = new iTextSharp.text.pdf.PdfPTable(headers.Length) { WidthPercentage = 100f }; foreach (var h in headers) { var cell = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(h, headerFont)) { HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER, BackgroundColor = new iTextSharp.text.BaseColor(230, 230, 230), Padding = 4f }; table.AddCell(cell); } // 写入每一行数据 foreach (var r in TestResults) { string sIndex = r.Index.ToString(System.Globalization.CultureInfo.InvariantCulture); string sTime = r.Timestamp.ToString("o", System.Globalization.CultureInfo.InvariantCulture); string sSucc = r.IsPhotoSuccess ? "True" : "False"; string sPx = ""; string sPy = ""; string sPz = ""; if (r.PointB != null) { sPx = Convert.ToString(r.PointB.X, System.Globalization.CultureInfo.InvariantCulture); sPy = Convert.ToString(r.PointB.Y, System.Globalization.CultureInfo.InvariantCulture); sPz = Convert.ToString(r.PointB.Z, System.Globalization.CultureInfo.InvariantCulture); } string sCycle = Convert.ToString(r.CycleTime, System.Globalization.CultureInfo.InvariantCulture); string sPixelX = Convert.ToString(r.PixelX, System.Globalization.CultureInfo.InvariantCulture); string sPixelY = Convert.ToString(r.PixelY, System.Globalization.CultureInfo.InvariantCulture); string sAngle = Convert.ToString(r.AngleU, System.Globalization.CultureInfo.InvariantCulture); string sTx = Convert.ToString(r.TransformX, System.Globalization.CultureInfo.InvariantCulture); string sTy = Convert.ToString(r.TransformY, System.Globalization.CultureInfo.InvariantCulture); var rowVals = new[] { sIndex, sTime, sSucc, sPx, sPy, sPz, sCycle, sPixelX, sPixelY, sAngle, sTx, sTy }; foreach (var v in rowVals) { var cell = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(v ?? "", normalFont)) { Padding = 4f }; table.AddCell(cell); } } doc.Add(table); // 新页,写入分析结果 doc.NewPage(); var analysisTitle = new iTextSharp.text.Paragraph("分析结果", titleFont) { SpacingAfter = 8f }; doc.Add(analysisTitle); var dims = new[] { new { Name = "TransformX", Values = TestResults.Where(t => t.IsPhotoSuccess).Select(t => t.TransformX).ToArray() }, new { Name = "TransformY", Values = TestResults.Where(t => t.IsPhotoSuccess).Select(t => t.TransformY).ToArray() }, new { Name = "AngleU", Values = TestResults.Where(t => t.IsPhotoSuccess).Select(t => t.AngleU).ToArray() } }; foreach (var dim in dims) { try { var header = new iTextSharp.text.Paragraph(dim.Name, headerFont) { SpacingBefore = 6f, SpacingAfter = 4f }; doc.Add(header); if (dim.Values == null || dim.Values.Length == 0) { doc.Add(new iTextSharp.text.Paragraph("样本数为 0,无法计算。", normalFont)); continue; } StabilityMetrics metrics = StabilityAnalyzer.AnalyzeStability(dim.Values); var metricsTable = new iTextSharp.text.pdf.PdfPTable(2) { WidthPercentage = 60f, SpacingAfter = 6f }; metricsTable.SetWidths(new float[] { 1f, 1f }); var props = metrics.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var p in props) { object pv = p.GetValue(metrics); string pvStr; if (pv == null) pvStr = ""; else if (pv is double) pvStr = ((double)pv).ToString("G", System.Globalization.CultureInfo.InvariantCulture); else pvStr = pv.ToString(); var pc = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(p.Name, normalFont)) { Padding = 4f }; var vc = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(pvStr, normalFont)) { Padding = 4f }; metricsTable.AddCell(pc); metricsTable.AddCell(vc); } doc.Add(metricsTable); } catch (Exception exCol) { LogHelper.WriteLogError($"导出报告时处理维度[{dim.Name}]出错", exCol); doc.Add(new iTextSharp.text.Paragraph($"处理维度 {dim.Name} 时出错: {exCol.Message}", normalFont)); } } doc.Close(); writer.Close(); } SendTaskMessage($"已导出测试报告到:{path}"); } catch (Exception ex) { LogHelper.WriteLogError("导出测试报告时出错", ex); SendTaskMessage($"导出测试报告失败:{ex.Message}"); } } /// /// 导出测试数据为CSV文件 /// void ExecuteExportCSVCommand() { try { if (TestResults == null || TestResults.Count == 0) { SendTaskMessage("无测试数据,无法导出。"); return; } var dlg = new Microsoft.Win32.SaveFileDialog { DefaultExt = "csv", Filter = "CSV 文件 (*.csv)|*.csv|所有文件 (*.*)|*.*", FileName = "TestResults.csv", Title = "保存测试结果为 CSV" }; bool? dlgResult = dlg.ShowDialog(); if (dlgResult != true) return; string path = dlg.FileName; var sb = new System.Text.StringBuilder(); // CSV 字段转义 Func EscapeCsv = (s) => { if (s == null) return ""; bool mustQuote = s.Contains(",") || s.Contains("\"") || s.Contains("\r") || s.Contains("\n"); string esc = s.Replace("\"", "\"\""); return mustQuote ? $"\"{esc}\"" : esc; }; // 写入表头 var headers = new[] { "Index", "Timestamp", "IsPhotoSuccess", "PointB.X", "PointB.Y", "PointB.Z", "CycleTime", "PixelX", "PixelY", "AngleU", "TransformX", "TransformY" }; sb.AppendLine(string.Join(",", headers.Select(h => EscapeCsv(h)))); // 写入数据行 foreach (var r in TestResults) { var cols = new List(); cols.Add(EscapeCsv(r.Index.ToString())); cols.Add(EscapeCsv(r.Timestamp.ToString("o"))); // ISO 8601 格式 cols.Add(EscapeCsv(r.IsPhotoSuccess ? "True" : "False")); if (r.PointB != null) { // 假设 RPoint 有 X,Y,Z 属性(若命名不同需调整) cols.Add(EscapeCsv(Convert.ToString(r.PointB.X, System.Globalization.CultureInfo.InvariantCulture))); cols.Add(EscapeCsv(Convert.ToString(r.PointB.Y, System.Globalization.CultureInfo.InvariantCulture))); cols.Add(EscapeCsv(Convert.ToString(r.PointB.Z, System.Globalization.CultureInfo.InvariantCulture))); } else { cols.Add(""); cols.Add(""); cols.Add(""); } cols.Add(EscapeCsv(Convert.ToString(r.CycleTime, System.Globalization.CultureInfo.InvariantCulture))); cols.Add(EscapeCsv(Convert.ToString(r.PixelX, System.Globalization.CultureInfo.InvariantCulture))); cols.Add(EscapeCsv(Convert.ToString(r.PixelY, System.Globalization.CultureInfo.InvariantCulture))); cols.Add(EscapeCsv(Convert.ToString(r.AngleU, System.Globalization.CultureInfo.InvariantCulture))); cols.Add(EscapeCsv(Convert.ToString(r.TransformX, System.Globalization.CultureInfo.InvariantCulture))); cols.Add(EscapeCsv(Convert.ToString(r.TransformY, System.Globalization.CultureInfo.InvariantCulture))); sb.AppendLine(string.Join(",", cols)); } // 在末尾追加分析结果 sb.AppendLine(); sb.AppendLine("分析结果"); sb.AppendLine("维度,指标,值"); // 要分析的维度:TransformX, TransformY, AngleU var dims = new[] { new { Name = "TransformX", Values = TestResults.Where(t => t.IsPhotoSuccess).Select(t => t.TransformX).ToArray() }, new { Name = "TransformY", Values = TestResults.Where(t => t.IsPhotoSuccess).Select(t => t.TransformY).ToArray() }, new { Name = "AngleU", Values = TestResults.Where(t => t.IsPhotoSuccess).Select(t => t.AngleU).ToArray() } }; foreach (var dim in dims) { try { if (dim.Values == null || dim.Values.Length == 0) { sb.AppendLine($"{EscapeCsv(dim.Name)},{EscapeCsv("样本数")},{EscapeCsv("0")}"); continue; } // 调用稳定性分析 StabilityMetrics metrics = StabilityAnalyzer.AnalyzeStability(dim.Values); // 反射写入公开属性 var props = metrics.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var p in props) { object pv = p.GetValue(metrics); string pvStr; if (pv == null) pvStr = ""; else if (pv is double) pvStr = Convert.ToString((double)pv, System.Globalization.CultureInfo.InvariantCulture); else pvStr = pv.ToString(); sb.AppendLine($"{EscapeCsv(dim.Name)},{EscapeCsv(p.Name)},{EscapeCsv(pvStr)}"); } } catch (Exception exCol) { LogHelper.WriteLogError($"导出分析结果时处理维度[{dim.Name}]出错", exCol); sb.AppendLine($"{EscapeCsv(dim.Name)},{EscapeCsv("Error")},{EscapeCsv(exCol.Message)}"); } } // 写入文件(UTF8,无 BOM) System.IO.File.WriteAllText(path, sb.ToString(), System.Text.Encoding.UTF8); SendTaskMessage($"已导出测试结果到:{path}"); } catch (Exception ex) { LogHelper.WriteLogError("导出CSV时出错", ex); SendTaskMessage($"导出CSV失败:{ex.Message}"); } } /// /// 选中视觉流程改变时 /// void ExecuteProcedureSelectionChangedCommand() { if (SelectProcedure == null) { return; } //获取相机 Camera = _cameraService.GetCamera(SelectProcedure.CameraId); VisionTool = SelectProcedure.ToolBlock; } /// /// 示教点B /// void ExecuteTeachPointBCommand() { if (Robot == null || !Robot.IsConnected) { SendTaskMessage("机器人未连接,无法示教!"); return; } try { var position = Robot.GetRobotPos(); if (position != null) { PointB = position.Clone(); SendTaskMessage($"已示教点B:X={PointB.X:F2} Y={PointB.Y:F2} Z={PointB.Z:F2}"); } else { SendTaskMessage("获取机器人当前位置失败,无法示教点B!"); } } catch (Exception ex) { LogHelper.WriteLogError("示教点B时出错!", ex); SendTaskMessage($"示教点B时出错:{ex.Message}"); } } /// /// 示教点A /// void ExecuteTeachPointACommand() { if (Robot == null || !Robot.IsConnected) { SendTaskMessage("机器人未连接,无法示教!"); return; } try { var position = Robot.GetRobotPos(); if (position != null) { PointA = position.Clone(); SendTaskMessage($"已示教点A:X={PointA.X:F2} Y={PointA.Y:F2} Z={PointA.Z:F2}"); } else { SendTaskMessage("获取机器人当前位置失败,无法示教点A!"); } } catch (Exception ex) { LogHelper.WriteLogError("示教点A时出错!", ex); SendTaskMessage($"示教点A时出错:{ex.Message}"); } } /// /// 显示趋势图 /// void ExecuteShowTrendChartCommand() { } /// /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs、图像和图形集合。 /// /// /// public Task<(bool isSuccess, double pixelX, double pixelY, double angleU, double transformX, double transformY)> ExecutePhotoEx(int index) { return Task.Run(() => { CogToolBlockTerminalCollection outputCollection; List result = new List(); result.Add(index); try { // 1. 采集图像 bool succed = Camera.SetExposureTime(SelectProcedure.ExposureTime); if (!succed) { SendTaskMessage(Lang.相机曝光设置失败); } succed = Camera.SetGain(SelectProcedure.Gain); if (!succed) { SendTaskMessage(Lang.相机增益设置失败); } DateTime nowtime = DateTime.Now; LogHelper.WriteLogInfo(Lang.开始采集图像); var image = Camera.Grab(); if (image == null) { SendTaskMessage(Lang.图像采集失败); outputCollection = null; return (false, 0d, 0d, 0d, 0d, 0d); } //Image = image; VisionTool.Inputs["InputImage"].Value = image; //LogHelper.WriteLogInfo(string.Format(Lang.采集图像完成用时0ms, (DateTime.Now - nowtime).Milliseconds)); // 2. 为ToolBlock传入其他输入终端 //if (InputTerminal != null) //{ // LogHelper.WriteLogInfo(Lang.为ToolBlock传入输入终端); // foreach (var item in InputTerminal) // { // if (VisionTool.Inputs.Contains(item.Key)) // { // LogHelper.WriteLogInfo($"传入[{item.Key}]={item.Value}"); // VisionTool.Inputs[item.Key].Value = item.Value; // } // else // { // LogHelper.WriteLogInfo($"创建并传入[{item.Key}]={item.Value}"); // VisionTool.Inputs.Add(new CogToolBlockTerminal(item.Key, item.Value)); // } // } //} Image = VisionTool.Inputs["InputImage"].Value as ICogImage; // 3. 运行视觉工具 LogHelper.WriteLogInfo(Lang.开始运行视觉工具); VisionTool.Run(); //运行ToolBlock if (VisionTool.RunStatus.Result == CogToolResultConstants.Accept) { SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", SelectProcedure.Name).Replace("{1}", $"{VisionTool.RunStatus.ProcessingTime:F1}")); outputCollection = VisionTool.Outputs; //获取输出终端集合 Graphic = outputCollection["Graphic"].Value as CogGraphicCollection; if (!outputCollection.Contains("Found")) { SendTaskMessage(Lang.未找到视觉输出结果); return (false, 0d, 0d, 0d, 0d, 0d); } // 2. 获取视觉输出结果 bool Found = (bool)(outputCollection["Found"].Value); if (!Found) { SendTaskMessage(Lang.拍照NG); return (false, 0d, 0d, 0d, 0d, 0d); } //SendTaskMessage(Lang.拍照OK, MessageLevel.Debug); // 3. 获取视觉输出结果 //string points = (string)(outputCollection["Point"].Value); //string[] strpoints = points.Split(';'); ////先将pos按照逗号进行分隔,拿到数组 //var posParts = strpoints[0].Split(','); //double _pixel_x = double.Parse(posParts[0]); //double _pixel_y = double.Parse(posParts[1]); //double _pixel_u = double.Parse(posParts[2]); ////获取相机校准 //var calib = _calibrationService.GetCalibration(SelectProcedure.CalibrationId); //if (calib == null) //{ // return (true, _pixel_x, _pixel_y, _pixel_u, 0, 0); ; //} ////获取机器人当前坐标系 //RPoint rPoint = Robot.GetRobotPos(); //double[] point = new double[3]; //point[0] = rPoint.X; //point[1] = rPoint.Y; //point[2] = rPoint.U; //if (calib.CameraMount == CameraMount.FixedUp || calib.CameraMount == CameraMount.FixedDown) //{ // point = null; //} ////转换点位-像素转换成机器人绝对坐标 //var calibResult = _calibrationService.ConvertPixelToPosition((_pixel_x, _pixel_y, _pixel_u), point, calib, RobotBrand.XYZ_Platform); //if (!calibResult.IsSucceed) //{ // return (false, _pixel_x, _pixel_y, _pixel_u, 0d, 0d); //} //eturn (true, _pixel_x, _pixel_y, _pixel_u, calibResult.X, calibResult.Y); ; if (!outputCollection.Contains("dis1")) { string[] Point1 = ((string)(outputCollection["Point"].Value)).Split(','); var calibration = _calibrationService.GetCalibration(SelectProcedure.CalibrationId); var pos= Robot.GetRobotPos(); double[] robotpos = new double[] { pos.X, pos.Y, pos.Z }; (bool IsSucceed, double X, double Y, double U) = _calibrationService.ConvertPixelToPosition((double.Parse(Point1[0]), double.Parse(Point1[1]), double.Parse(Point1[2])), robotpos, calibration); if (!IsSucceed) { SendTaskMessage("坐标转换失败!"); } return (true, double.Parse(Point1[0]), double.Parse(Point1[1]), double.Parse(Point1[2]), X, Y); } double dis1 = (double)(outputCollection["dis1"].Value); return (true, dis1, 0, 0, 0, 0); } else { SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", SelectProcedure.Name).Replace("{1}", $"{VisionTool.RunStatus.ProcessingTime:F1}")); SendTaskMessage(VisionTool.RunStatus.Message); outputCollection = null; Graphic = outputCollection["Graphic"].Value as CogGraphicCollection; return (false, 0d, 0d, 0d, 0d, 0d); //return (true, 0, 0, 0, 0, 0); ; } } catch (Exception ex) { SendTaskMessage(ex.Message); LogHelper.WriteLogError(Lang.执行相机取图并执行视觉工具组时出错, ex); outputCollection = null; return (false, 0d, 0d, 0d, 0d, 0d); } }); } public void SendTaskMessage(string msg) { App.Current.Dispatcher.Invoke(() => { MessageQueue.Clear(); MessageQueue.Enqueue(msg); }); } // 规格限制(根据实际情况设置) private double _xLSL = -0.02; // X下规格限 private double _xUSL = 0.02; // X上规格限 private double _yLSL = -0.02; // Y下规格限 private double _yUSL = 0.02; // Y上规格限 private double _angleLSL = -1.0; // 角度下规格限 private double _angleUSL = 1.0; // 角度上规格限 /// /// 计算所有精度指标 /// public void CalculatePrecisionMetrics() { if (TestResults == null || TestResults.Count < 2) return; // 过滤成功的测试结果 var successResults = TestResults.Where(r => r.IsPhotoSuccess).ToList(); if (successResults.Count < 2) return; // 提取数据 var transformXs = successResults.Select(r => r.TransformX).ToList(); var transformYs = successResults.Select(r => r.TransformY).ToList(); var angleUs = successResults.Select(r => r.AngleU).ToList(); // 计算X方向指标 var xMetrics = CalculateMetrics(transformXs, _xLSL, _xUSL); PrecisionResult.XMean = xMetrics.Mean; PrecisionResult.XPrecision = xMetrics.StdDeviation; PrecisionResult.XThreeSigmaRange = xMetrics.ThreeSigmaRange; PrecisionResult.XRange = xMetrics.Range; PrecisionResult.XKurtosis = xMetrics.Kurtosis; PrecisionResult.XCpk = xMetrics.Cpk; // 计算Y方向指标 var yMetrics = CalculateMetrics(transformYs, _yLSL, _yUSL); PrecisionResult.YMean = yMetrics.Mean; PrecisionResult.YPrecision = yMetrics.StdDeviation; PrecisionResult.YThreeSigmaRange = yMetrics.ThreeSigmaRange; PrecisionResult.YRange = yMetrics.Range; PrecisionResult.YKurtosis = yMetrics.Kurtosis; PrecisionResult.YCpk = yMetrics.Cpk; // 计算角度指标 var angleMetrics = CalculateMetrics(angleUs, _angleLSL, _angleUSL); PrecisionResult.AngleMean = angleMetrics.Mean; PrecisionResult.AnglePrecision = angleMetrics.StdDeviation; PrecisionResult.AngleThreeSigmaRange = angleMetrics.ThreeSigmaRange; PrecisionResult.AngleRange = angleMetrics.Range; PrecisionResult.AngleCpk = angleMetrics.Cpk; // 计算综合精度 PrecisionResult.OverallPrecision = Math.Sqrt( Math.Pow(PrecisionResult.XPrecision, 2) + Math.Pow(PrecisionResult.YPrecision, 2)); PrecisionResult.OverallThreeSigmaRange = PrecisionResult.OverallPrecision * 3; // 使用最差的CPK作为整体评级 var minCpk = Math.Min(Math.Min(PrecisionResult.XCpk, PrecisionResult.YCpk), PrecisionResult.AngleCpk); PrecisionResult.ProcessRating = PrecisionResult.GetCpkRating(minCpk); } /// /// 计算单个维度的所有指标 /// private DimensionMetrics CalculateMetrics(List values, double lsl, double usl) { if (values == null || values.Count < 2) return new DimensionMetrics(); var metrics = new DimensionMetrics { Mean = values.Average(), StdDeviation = CalculateStandardDeviation(values), Range = values.Max() - values.Min(), Kurtosis = CalculateKurtosis(values) }; metrics.ThreeSigmaRange = metrics.StdDeviation * 3; metrics.Cpk = CalculateCpk(values, lsl, usl); return metrics; } /// /// 计算标准差 /// private double CalculateStandardDeviation(List values) { if (values.Count < 2) return 0; var mean = values.Average(); var sumSq = values.Sum(v => Math.Pow(v - mean, 2)); return Math.Sqrt(sumSq / (values.Count - 1)); } /// /// 计算峰度 /// private double CalculateKurtosis(List values) { if (values.Count < 4) return 0; var mean = values.Average(); var n = values.Count; var sum4 = values.Sum(v => Math.Pow(v - mean, 4)); var sum2 = values.Sum(v => Math.Pow(v - mean, 2)); if (sum2 == 0) return 0; return (n * sum4) / Math.Pow(sum2, 2) - 3; } /// /// 计算CPK /// private double CalculateCpk(List values, double lsl, double usl) { if (values.Count < 2 || usl <= lsl) return 0; var stdDev = CalculateStandardDeviation(values); if (stdDev == 0) return double.MaxValue; var mean = values.Average(); var cpu = (usl - mean) / (3 * stdDev); var cpl = (mean - lsl) / (3 * stdDev); return Math.Min(cpu, cpl); } /// /// 单个维度的指标 /// private class DimensionMetrics { public double Mean { get; set; } public double StdDeviation { get; set; } public double ThreeSigmaRange { get; set; } public double Range { get; set; } public double Kurtosis { get; set; } public double Cpk { get; set; } } /// /// 在添加测试结果后自动更新精度分析 /// private void OnTestResultAdded() { CalculatePrecisionMetrics(); RaisePropertyChanged(nameof(PrecisionResult)); } /// /// 设置规格限制 /// public void SetSpecificationLimits(double xLSL, double xUSL, double yLSL, double yUSL, double angleLSL, double angleUSL) { _xLSL = xLSL; _xUSL = xUSL; _yLSL = yLSL; _yUSL = yUSL; _angleLSL = angleLSL; _angleUSL = angleUSL; // 重新计算精度指标 CalculatePrecisionMetrics(); } /// /// 基于3σ自动设置规格限制 /// public void AutoSetSpecificationLimits() { if (TestResults == null || TestResults.Count < 2) return; var successResults = TestResults.Where(r => r.IsPhotoSuccess).ToList(); if (successResults.Count < 2) return; var transformXs = successResults.Select(r => r.TransformX).ToList(); var transformYs = successResults.Select(r => r.TransformY).ToList(); var angleUs = successResults.Select(r => r.AngleU).ToList(); var xStd = CalculateStandardDeviation(transformXs); var yStd = CalculateStandardDeviation(transformYs); var angleStd = CalculateStandardDeviation(angleUs); var xMean = transformXs.Average(); var yMean = transformYs.Average(); var angleMean = angleUs.Average(); // 使用平均值±3σ作为自动规格限 SetSpecificationLimits( xLSL: xMean - 3 * xStd, xUSL: xMean + 3 * xStd, yLSL: yMean - 3 * yStd, yUSL: yMean + 3 * yStd, angleLSL: angleMean - 3 * angleStd, angleUSL: angleMean + 3 * angleStd ); } #endregion #region 继承 public string Title { get; set; } = "视觉静态精度分析仪"; public event Action RequestClose; public bool CanCloseDialog() { return true; } public void OnDialogClosed() { _cts?.Cancel(); } public void OnDialogOpened(IDialogParameters parameters) { SelectProduct = parameters.GetValue("SelectProduct"); Robot = parameters.GetValue("Robot"); //Camera = _cameraService.GetCamera(SelectProcedure.CameraId); //VisionTool = parameters.GetValue("ToolBlock"); ProcedureModels = new ObservableCollection(); foreach (var item in SelectProduct.CameraProcedures) { foreach (var item1 in item.ProcedureModels) { ProcedureModels.Add(item1); } } //VisionTool.Run(); //TestResult = CreateResultDataTable(VisionTool.Outputs); } #endregion } public class DynamicTestResult : BindableBase { private int _Index; /// /// 序号 /// public int Index { get { return _Index; } set { SetProperty(ref _Index, value); } } private DateTime _Timestamp; /// /// 时间戳 /// public DateTime Timestamp { get { return _Timestamp; } set { SetProperty(ref _Timestamp, value); } } private bool _isPhotoSuccess; /// /// 拍照结果 /// public bool IsPhotoSuccess { get { return _isPhotoSuccess; } set { SetProperty(ref _isPhotoSuccess, value); } } private RPoint _PointB; /// /// 机器人拍照的坐标 /// public RPoint PointB { get { return _PointB; } set { SetProperty(ref _PointB, value); } } private double _CycleTime; /// /// 单次节拍 /// public double CycleTime { get { return _CycleTime; } set { SetProperty(ref _CycleTime, value); } } private double _PixelX; /// /// 像素X /// public double PixelX { get { return _PixelX; } set { SetProperty(ref _PixelX, value); } } private double _PixelY; /// /// 像素Y /// public double PixelY { get { return _PixelY; } set { SetProperty(ref _PixelY, value); } } private double _AngleU; /// /// 像素U /// public double AngleU { get { return _AngleU; } set { SetProperty(ref _AngleU, value); } } private double _TransformX; /// /// 转换后的机器人坐标X /// public double TransformX { get { return _TransformX; } set { SetProperty(ref _TransformX, value); } } private double _TransformY; /// /// 转换后的机器人坐标Y /// public double TransformY { get { return _TransformY; } set { SetProperty(ref _TransformY, value); } } public DynamicTestResult() { } public DynamicTestResult(int index, bool isPhotoSuccess, RPoint pointB, double cycleTime, double pixelX, double pixelY, double angleU, double transformX, double transformY) { Index = index; Timestamp = DateTime.Now; IsPhotoSuccess = isPhotoSuccess; PointB = pointB; CycleTime = cycleTime; PixelX = pixelX; PixelY = pixelY; AngleU = angleU; TransformX = transformX; TransformY = transformY; } } /// /// 精度分析结果 /// public class PrecisionAnalysisResult : BindableBase { private double _xPrecision; /// /// X方向精度(标准差) /// public double XPrecision { get { return _xPrecision; } set { SetProperty(ref _xPrecision, value); } } private double _yPrecision; /// /// Y方向精度(标准差) /// public double YPrecision { get { return _yPrecision; } set { SetProperty(ref _yPrecision, value); } } private double _anglePrecision; /// /// 角度精度(标准差) /// public double AnglePrecision { get { return _anglePrecision; } set { SetProperty(ref _anglePrecision, value); } } private double _xThreeSigmaRange; /// /// X方向3σ范围 /// public double XThreeSigmaRange { get { return _xThreeSigmaRange; } set { SetProperty(ref _xThreeSigmaRange, value); } } private double _yThreeSigmaRange; /// /// Y方向3σ范围 /// public double YThreeSigmaRange { get { return _yThreeSigmaRange; } set { SetProperty(ref _yThreeSigmaRange, value); } } private double _angleThreeSigmaRange; /// /// 角度3σ范围 /// public double AngleThreeSigmaRange { get { return _angleThreeSigmaRange; } set { SetProperty(ref _angleThreeSigmaRange, value); } } private double _xMean; /// /// X方向平均值 /// public double XMean { get { return _xMean; } set { SetProperty(ref _xMean, value); } } private double _yMean; /// /// Y方向平均值 /// public double YMean { get { return _yMean; } set { SetProperty(ref _yMean, value); } } private double _angleMean; /// /// 角度平均值 /// public double AngleMean { get { return _angleMean; } set { SetProperty(ref _angleMean, value); } } private double _xRange; /// /// X方向极差 /// public double XRange { get { return _xRange; } set { SetProperty(ref _xRange, value); } } private double _yRange; /// /// Y方向极差 /// public double YRange { get { return _yRange; } set { SetProperty(ref _yRange, value); } } private double _angleRange; /// /// 角度极差 /// public double AngleRange { get { return _angleRange; } set { SetProperty(ref _angleRange, value); } } private double _xKurtosis; /// /// X方向峰度 /// public double XKurtosis { get { return _xKurtosis; } set { SetProperty(ref _xKurtosis, value); } } private double _yKurtosis; /// /// Y方向峰度 /// public double YKurtosis { get { return _yKurtosis; } set { SetProperty(ref _yKurtosis, value); } } private double _xCpk; /// /// X方向CPK /// public double XCpk { get { return _xCpk; } set { SetProperty(ref _xCpk, value); } } private double _yCpk; /// /// Y方向CPK /// public double YCpk { get { return _yCpk; } set { SetProperty(ref _yCpk, value); } } private double _angleCpk; /// /// 角度CPK /// public double AngleCpk { get { return _angleCpk; } set { SetProperty(ref _angleCpk, value); } } private double _overallPrecision; /// /// 综合精度(XY合成标准差) /// public double OverallPrecision { get { return _overallPrecision; } set { SetProperty(ref _overallPrecision, value); } } private double _overallThreeSigmaRange; /// /// 综合3σ范围 /// public double OverallThreeSigmaRange { get { return _overallThreeSigmaRange; } set { SetProperty(ref _overallThreeSigmaRange, value); } } private string _processRating; /// /// 过程能力评级 /// public string ProcessRating { get { return _processRating; } set { SetProperty(ref _processRating, value); } } /// /// 获取CPK评级描述 /// public string GetCpkRating(double cpk) { if (cpk >= 1.67) return "卓越"; else if (cpk >= 1.33) return "良好"; else if (cpk >= 1.00) return "可接受"; else if (cpk >= 0.67) return "不足"; else return "严重不足"; } } }