Explorar o código

视觉静态精度分析仪支持统计分析与报告导出

新增稳定性分析核心类,支持均值/标准差/峰度等统计指标计算。视图模型增加数据列选择与自动分析,支持CSV和PDF报告导出(集成iTextSharp,含中文字体)。界面优化,统计区可选列并实时显示分析结果。项目文件新增依赖与编译项。大量中文注释,提升可维护性。
孝锋 徐 hai 7 meses
pai
achega
0d0ed9a0d4

+ 334 - 0
TeamAAS-VM/Core/StabilityAnalyzer.cs

@@ -0,0 +1,334 @@
+/* 
+详细的伪代码计划 (以注释形式嵌入文件头部)
+1. 定义 StabilityAnalyzer 类及其内部类 StabilityMetrics:
+   - StabilityMetrics 包含:Mean, StdDeviation, ThreeSigmaRange, Kurtosis, Cpk, Range, CV, Confidence95
+   - 每个属性在注释中说明含义与计算公式
+
+2. AnalyzeStability 方法:
+   - 将输入值转换为数组并验证长度(至少10个数据点)
+   - 计算平均值 mean(data.Average())
+   - 计算标准差 stdDev(调用 CalculateStandardDeviation)
+   - 构建 StabilityMetrics 实例并填充:
+       - Mean = mean
+       - StdDeviation = stdDev
+       - ThreeSigmaRange = 6 * stdDev (表示 ±3σ 的区间宽度)
+       - Kurtosis = CalculateKurtosis(data)
+       - Range = data.Max() - data.Min()
+       - CV = (stdDev / mean) * 100 (百分比)
+       - Confidence95 = Calculate95ConfidenceInterval(data)
+   - 如果提供上下规格限(lowerSpec 和 upperSpec),调用 CalculateProcessCapability 并设置 metrics.Cpk
+   - 返回 metrics
+
+3. GetStabilityRating 方法:
+   - 基于标准差评级返回稳定性评价字符串
+
+4. GetCpkRating 方法:
+   - 根据 cpk 返回等级字符串
+
+5. 统计计算辅助方法:
+   - CalculateStandardDeviation:样本标准差,采用 n-1 分母(样本标准差)
+   - CalculateRange:极差(最大值 - 最小值)
+   - CalculateCV:变异系数,返回百分比
+   - CalculateAccuracy:与理论值的绝对偏差
+   - Calculate95ConfidenceInterval:95%置信区间,使用 1.96 * s / sqrt(n)
+   - GetStdDeviation:封装标准差计算
+   - Get3SigmaRange:返回平均值 ± 3σ 的上下限
+   - CalculateKurtosis:使用 Fisher 定义(正态分布为 0)的峰度计算公式
+   - CalculateProcessCapability:计算 Cp 和 Cpk,使用 6σ 和 3σ 的定义,返回 (cp, cpk)
+
+4. 注释策略:
+   - 对所有公开类、属性和方法添加 XML 注释(供 VS IntelliSense 使用)
+   - 在方法内部添加行内注释,解释关键步骤与公式
+   - 保持注释为中文,简洁明确,便于维护
+
+以上伪代码被置于文件顶部注释中,随后是实现代码,包含完整的中文注释与 XML 文档注释。
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace TeamAAS_VP.Core
+{
+    /// <summary>
+    /// 稳定性分析器:提供一组统计方法用于评估一组数值数据的稳定性与过程能力。
+    /// </summary>
+    public class StabilityAnalyzer
+    {
+        /// <summary>
+        /// 稳定性度量结果集
+        /// </summary>
+        public class StabilityMetrics
+        {
+            /// <summary>
+            /// 样本平均值
+            /// </summary>
+            public double Mean { get; set; }               // 平均值
+
+            /// <summary>
+            /// 样本标准差(使用 n-1 分母的样本标准差)
+            /// </summary>
+            public double StdDeviation { get; set; }       // 标准差 (核心1)
+
+            /// <summary>
+            /// 3σ 区间的宽度(等于 6 * StdDeviation,表示 ±3σ 总宽)
+            /// </summary>
+            public double ThreeSigmaRange { get; set; }    // 3σ范围 (核心2)
+
+            /// <summary>
+            /// 峰度(使用 Fisher 定义,正态分布为 0)
+            /// </summary>
+            public double Kurtosis { get; set; }           // 峰度 (核心3)
+
+            /// <summary>
+            /// 过程能力指数 Cpk(若未提供规格限则为默认 0)
+            /// </summary>
+            public double Cpk { get; set; }                // 过程能力指数 (核心4)
+
+            /// <summary>
+            /// 极差(最大值 - 最小值)
+            /// </summary>
+            public double Range { get; set; }              // 极差
+
+            /// <summary>
+            /// 变异系数(标准差 / 平均值 * 100%)
+            /// </summary>
+            public double CV { get; set; }                 // 变异系数
+
+            /// <summary>
+            /// 95% 置信区间,返回 (Lower, Upper)
+            /// </summary>
+            public (double Lower, double Upper) Confidence95 { get; set; }
+        }
+
+        /// <summary>
+        /// 对一组数值进行稳定性分析,返回各项统计度量。
+        /// </summary>
+        /// <param name="values">输入数据序列(至少 10 个点)</param>
+        /// <param name="lowerSpec">下规格限(可选)</param>
+        /// <param name="upperSpec">上规格限(可选)</param>
+        /// <returns>StabilityMetrics 包含多项指标</returns>
+        /// <exception cref="ArgumentException">当数据点少于 10 个时抛出</exception>
+        public static StabilityMetrics AnalyzeStability(IEnumerable<double> values,
+                                                       double? lowerSpec = null,
+                                                       double? upperSpec = null)
+        {
+            // 将输入转换为数组以便重复使用并获取长度
+            var data = values.ToArray();
+            if (data.Length < 10) throw new ArgumentException("至少需要10个数据点");
+
+            // 计算平均值与标准差(样本标准差)
+            var mean = data.Average();
+            var stdDev = CalculateStandardDeviation(data);
+
+            // 构建指标对象并填充常规统计量
+            var metrics = new StabilityMetrics
+            {
+                Mean = mean,
+                StdDeviation = stdDev,
+                // ThreeSigmaRange 表示 ±3σ 的总宽度(6σ)
+                ThreeSigmaRange = CalculateKurtosis(data),//6 * stdDev,  
+                Kurtosis = CalculateKurtosis(data),
+                Range = data.Max() - data.Min(),
+                // 变异系数以百分比形式表示
+                CV = (stdDev / mean) * 100,
+                Confidence95 = Calculate95ConfidenceInterval(data)
+            };
+
+            // 如果提供了规格限,则计算并设置 Cpk(cp 也被计算但不保存)
+            if (lowerSpec.HasValue && upperSpec.HasValue)
+            {
+                metrics.Cpk = CalculateProcessCapability(data,
+                    lowerSpec.Value, upperSpec.Value).cpk;
+            }
+
+            return metrics;
+        }
+
+        /// <summary>
+        /// 根据标准差(StdDeviation)返回稳定性等级描述。
+        /// 阈值为经验值,可根据业务需求调整。
+        /// </summary>
+        /// <param name="metrics">稳定性度量结果</param>
+        /// <returns>稳定性等级字符串(中文 + 英文)</returns>
+        public static string GetStabilityRating(StabilityMetrics metrics)
+        {
+            // 根据标准差的绝对值分级:阈值为示例值,应结合量纲与业务场景判断
+            if (metrics.StdDeviation < 0.001)
+                return "优秀 (Excellent)";
+            else if (metrics.StdDeviation < 0.005)
+                return "良好 (Good)";
+            else if (metrics.StdDeviation < 0.01)
+                return "合格 (Acceptable)";
+            else
+                return "不稳定 (Unstable)";
+        }
+
+        /// <summary>
+        /// 根据 Cpk 值返回过程能力等级(常用阈值)
+        /// </summary>
+        /// <param name="cpk">Cpk 值</param>
+        /// <returns>等级描述(中文)</returns>
+        public static string GetCpkRating(double cpk)
+        {
+            if (cpk >= 1.67) return "卓越";
+            if (cpk >= 1.33) return "良好";
+            if (cpk >= 1.00) return "可接受";
+            if (cpk >= 0.67) return "不足";
+            return "严重不足";
+        }
+
+        /// <summary>
+        /// 计算样本标准差(除以 n-1),适用于样本数据的离散程度估计。
+        /// 公式:sqrt( Sum((x - mean)^2) / (n - 1) )
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <returns>样本标准差</returns>
+        public static double CalculateStandardDeviation(IEnumerable<double> values)
+        {
+            var vals = values.ToArray();
+            var n = vals.Length;
+            if (n < 2) return 0.0;
+
+            var avg = vals.Average();
+            var sumSq = vals.Sum(v => Math.Pow(v - avg, 2));
+            // 使用样本标准差(除以 n-1)
+            return Math.Sqrt(sumSq / (n - 1));
+        }
+
+        /// <summary>
+        /// 计算极差(最大值 - 最小值)
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <returns>极差</returns>
+        public static double CalculateRange(IEnumerable<double> values)
+        {
+            var vals = values.ToArray();
+            if (vals.Length == 0) return 0.0;
+            return vals.Max() - vals.Min();
+        }
+
+        /// <summary>
+        /// 计算变异系数(标准差 / 平均值 * 100%)
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <returns>变异系数的百分比表示</returns>
+        public static double CalculateCV(IEnumerable<double> values)
+        {
+            var vals = values.ToArray();
+            var stdDev = CalculateStandardDeviation(vals);
+            var mean = vals.Average();
+            if (Math.Abs(mean) < double.Epsilon) return double.NaN; // 避免除以 0
+            return (stdDev / mean) * 100;  // 百分比
+        }
+
+        /// <summary>
+        /// 计算与理论值的绝对偏差(常用于评估准确性)
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <param name="theoreticalValue">理论或目标值</param>
+        /// <returns>平均值与理论值的绝对差</returns>
+        public static double CalculateAccuracy(IEnumerable<double> values, double theoreticalValue)
+        {
+            var mean = values.Average();
+            return Math.Abs(mean - theoreticalValue);
+        }
+
+        /// <summary>
+        /// 计算 95% 置信区间(基于正态近似,使用 z=1.96)
+        /// 置信区间 = mean ± 1.96 * s / sqrt(n)
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <returns>置信区间下限与上限</returns>
+        public static (double lower, double upper) Calculate95ConfidenceInterval(IEnumerable<double> values)
+        {
+            var vals = values.ToArray();
+            var n = vals.Length;
+            if (n == 0) return (0, 0);
+
+            var mean = vals.Average();
+            var stdDev = CalculateStandardDeviation(vals);
+            var margin = 1.96 * stdDev / Math.Sqrt(n);  // 1.96 对应 95% 置信度(正态分布近似)
+
+            return (mean - margin, mean + margin);
+        }
+
+        /// <summary>
+        /// 便捷方法:返回样本标准差
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <returns>样本标准差</returns>
+        public static double GetStdDeviation(IEnumerable<double> values)
+        {
+            return CalculateStandardDeviation(values);
+        }
+
+        /// <summary>
+        /// 返回平均值 ± 3σ 的上下限(约包含 99.73% 的正态分布数据)
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <returns>(lower, upper)</returns>
+        public static (double lower, double upper) Get3SigmaRange(IEnumerable<double> values)
+        {
+            var vals = values.ToArray();
+            if (vals.Length == 0) return (0, 0);
+
+            var mean = vals.Average();
+            var stdDev = CalculateStandardDeviation(vals);
+            return (mean - 3 * stdDev, mean + 3 * stdDev);
+        }
+
+        /// <summary>
+        /// 计算峰度(Kurtosis),使用 Fisher 定义(返回值在正态分布时为 0)
+        /// 公式(简化样本版本): (n * sum((x-mean)^4)) / (sum((x-mean)^2)^2) - 3
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <returns>峰度值</returns>
+        public static double CalculateKurtosis(IEnumerable<double> values)
+        {
+            var vals = values.ToArray();
+            var n = vals.Length;
+            if (n < 4) return 0.0; // 数据过少时峰度意义不大
+
+            var mean = vals.Average();
+            var sum4 = vals.Sum(v => Math.Pow(v - mean, 4));
+            var sum2 = vals.Sum(v => Math.Pow(v - mean, 2));
+
+            if (Math.Abs(sum2) < double.Epsilon) return 0.0;
+
+            // Fisher 峰度(正态分布为 0)
+            return (n * sum4) / Math.Pow(sum2, 2) - 3;
+        }
+
+        /// <summary>
+        /// 计算过程能力指标 Cp 与 Cpk
+        /// Cp = (USL - LSL) / (6 * sigma)
+        /// Cpk = min( (USL - mean) / (3 * sigma), (mean - LSL) / (3 * sigma) )
+        /// </summary>
+        /// <param name="values">输入数据序列</param>
+        /// <param name="lowerSpec">下规格限(LSL)</param>
+        /// <param name="upperSpec">上规格限(USL)</param>
+        /// <returns>(cp, cpk)</returns>
+        public static (double cp, double cpk) CalculateProcessCapability(
+            IEnumerable<double> values,
+            double lowerSpec,
+            double upperSpec)
+        {
+            var vals = values.ToArray();
+            var stdDev = CalculateStandardDeviation(vals);
+            var mean = vals.Average();
+
+            if (stdDev <= 0) return (double.NaN, double.NaN); // 避免除以 0
+
+            // Cp 反映公差带相对于总体变异的宽度
+            var cp = (upperSpec - lowerSpec) / (6 * stdDev);
+
+            // Cpk 考虑均值偏移,取靠近任一边的能力
+            var cpu = (upperSpec - mean) / (3 * stdDev);
+            var cpl = (mean - lowerSpec) / (3 * stdDev);
+            var cpk = Math.Min(cpu, cpl);
+
+            return (cp, cpk);
+        }
+    }
+}

+ 4 - 0
TeamAAS-VM/TeamAAS-VP.csproj

@@ -198,6 +198,9 @@
     <Reference Include="ICSharpCode.AvalonEdit, Version=6.3.0.90, Culture=neutral, PublicKeyToken=9cc39be672370310, processorArchitecture=MSIL">
       <HintPath>..\packages\AvalonEdit.6.3.0.90\lib\net462\ICSharpCode.AvalonEdit.dll</HintPath>
     </Reference>
+    <Reference Include="itextsharp, Version=5.5.13.4, Culture=neutral, PublicKeyToken=8354ae6d2174ddca, processorArchitecture=MSIL">
+      <HintPath>..\packages\iTextSharp.5.5.13.4\lib\net461\itextsharp.dll</HintPath>
+    </Reference>
     <Reference Include="log4net, Version=3.2.0.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
       <HintPath>..\packages\log4net.3.2.0\lib\net462\log4net.dll</HintPath>
     </Reference>
@@ -526,6 +529,7 @@
     <Compile Include="Controls\FeederSystemParam.xaml.cs">
       <DependentUpon>FeederSystemParam.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Core\StabilityAnalyzer.cs" />
     <Compile Include="Events\MainTabSwitchNotification.cs" />
     <Compile Include="Models\Feeder\ScrewFeederInfo.cs" />
     <Compile Include="Models\NumberStatistics.cs" />

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 753 - 125
TeamAAS-VM/ViewModels/Product/VisionStaticAccuracyAnalyzerViewModel.cs


+ 38 - 13
TeamAAS-VM/Views/Product/VisionStaticAccuracyAnalyzer.xaml

@@ -24,6 +24,8 @@
              MinHeight="700"
              MinWidth="900"
              d:Background="White"
+             HorizontalAlignment="Stretch"
+             VerticalAlignment="Stretch"
              FontFamily="{DynamicResource DefaultFont}">
 
     <prism:Dialog.WindowStyle>
@@ -36,8 +38,8 @@
                     Value="True" />
             <!--<Setter Property="SizeToContent"
                  Value="WidthAndHeight" />-->
-            <!--<Setter Property="WindowState"
-                 Value="Maximized" />-->
+            <Setter Property="WindowState"
+                    Value="Maximized" />
             <Setter Property="Topmost"
                     Value="True" />
         </Style>
@@ -53,6 +55,8 @@
                     Value="5" />
             <Setter Property="FontSize"
                     Value="14" />
+            <Setter Property="BorderThickness"
+                    Value="0" />
         </Style>
 
         <Style TargetType="TextBlock">
@@ -334,9 +338,26 @@
                                 Padding="10"
                                 CornerRadius="5">
                             <StackPanel>
-                                <TextBlock Text="精度统计"
-                                           FontWeight="Bold"
-                                           Margin="0 0 0 5" />
+                                <StackPanel Orientation="Horizontal"
+                                            Margin="0 0 0 5">
+                                    <TextBlock Text="精度统计"
+                                               FontWeight="Bold" />
+                                    <ComboBox ItemsSource="{Binding ResultDataColumns}"
+                                              SelectedItem="{Binding SelectedDataColumn, Mode=TwoWay}"
+                                              Margin="5,0">
+                                        <ComboBox.ItemTemplate>
+                                            <DataTemplate>
+                                                <TextBlock Text="{Binding ColumnName}" />
+                                            </DataTemplate>
+                                        </ComboBox.ItemTemplate>
+                                        <b:Interaction.Triggers>
+                                            <b:EventTrigger EventName="SelectionChanged">
+                                                <b:InvokeCommandAction Command="{Binding SelectColumnCommand}"/>
+                                            </b:EventTrigger>
+                                        </b:Interaction.Triggers>
+                                    </ComboBox>
+                                </StackPanel>
+
                                 <Grid>
                                     <Grid.ColumnDefinitions>
                                         <ColumnDefinition Width="*" />
@@ -344,30 +365,34 @@
                                     </Grid.ColumnDefinitions>
 
                                     <StackPanel Grid.Column="0">
-                                        <TextBlock Text="X标准差:">
+                                        <TextBlock Text="标准差:">
                                             <Run x:Name="runStdX"
-                                                 Text="0.000"
+                                                 d:Text="0.000"
+                                                 Text="{Binding StabilityMetrics.StdDeviation,StringFormat={}{0:F3}}"
                                                  Foreground="#2C3E50"
                                                  FontWeight="Bold" />
                                         </TextBlock>
-                                        <TextBlock Text="Y标准差:">
+                                        <TextBlock Text="3σ范围:">
                                             <Run x:Name="runStdY"
-                                                 Text="0.000"
+                                                 d:Text="±0.000"
+                                                 Text="{Binding StabilityMetrics.ThreeSigmaRange,StringFormat={}±{0:F3}}"
                                                  Foreground="#2C3E50"
                                                  FontWeight="Bold" />
                                         </TextBlock>
                                     </StackPanel>
 
                                     <StackPanel Grid.Column="1">
-                                        <TextBlock Text="平均偏差:">
+                                        <TextBlock Text="峰度:">
                                             <Run x:Name="runAvgDeviation"
-                                                 Text="0.000"
+                                                 d:Text="0.000"
+                                                 Text="{Binding StabilityMetrics.Kurtosis,StringFormat={}{0:F3}}"
                                                  Foreground="#2C3E50"
                                                  FontWeight="Bold" />
                                         </TextBlock>
-                                        <TextBlock Text="最大偏差:">
+                                        <TextBlock Text="差:">
                                             <Run x:Name="runMaxDeviation"
-                                                 Text="0.000"
+                                                 d:Text="0.000"
+                                                 Text="{Binding StabilityMetrics.Range,StringFormat={}{0:F3}}"
                                                  Foreground="#2C3E50"
                                                  FontWeight="Bold" />
                                         </TextBlock>

+ 1 - 0
TeamAAS-VM/packages.config

@@ -7,6 +7,7 @@
   <package id="EntityFramework" version="6.5.1" targetFramework="net48" />
   <package id="Enums.NET" version="5.0.0" targetFramework="net48" />
   <package id="ExtendedNumerics.BigDecimal" version="3001.0.1.201" targetFramework="net48" />
+  <package id="iTextSharp" version="5.5.13.4" targetFramework="net48" />
   <package id="log4net" version="3.2.0" targetFramework="net48" />
   <package id="MahApps.Metro" version="2.4.10" targetFramework="net48" />
   <package id="MaterialDesignColors" version="5.2.1" targetFramework="net48" />

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio