Files
WC-SPC/MES_Manage/App_code/drawchart/SpcCaculator.cs
2026-05-27 13:59:56 +08:00

513 lines
17 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
using System.Data;
using ASPNet_Drawing;
/// <summary>
///SpcCaculator 的摘要说明
/// </summary>
public class SpcCaculator
{
/// <summary>
/// SPC系数表
///(0)样本大小 (1)A (2)A2 (3)A3 (4)C4 (5)1/C4 (6)B3 (7)B4 (8)B5 (9)B6 (10)d2 (11)1/d2 (12)d3 (13)D1 (14)D2 (15)D3 (16)D4 (17)M3 (18)M3A2
/// </summary>
static public double[,] SPC_coefficient = { {2,2.121,1.880,2.659,0.798,1.253,0,3.267,0,2.606,1.128,0.887,0.853,0,3.686,0,3.267,1.000,1.880},
{3,1.732,1.023,1.954,0.886,1.128,0,2.568,0,2.276,1.693,0.591,0.888,0,4.358,0,2.574,1.160,1.187},
{4,1.500,0.729,1.628,0.921,1.085,0,2.266,0,2.088,2.059,0.486,0.880,0,4.698,0,2.282,1.092,0.796},
{5,1.342,0.572,1.427,0.940,1.064,0,2.089,0,1.964,2.326,0.430,0.864,0,4.918,0,2.114,1.198,0.691},
{6,1.225,0.483,1.287,0.952,1.051,0.030,1.970,0.029,1.874,2.534,0.395,0.848,0,5.078,0,2.004,1.135,0.549},
{7,1.134,0.419,1.182,0.959,1.042,0.118,1.882,0.113,1.806,2.704,0.370,0.833,0.204,5.204,0.076,1.924,1.214,0.509},
{8,1.061,0.373,1.099,0.965,1.036,0.185,1.815,0.179,1.751,2.847,0.351,0.820,0.388,5.306,0.136,1.864,1.160,0.432},
{9,1.00,0.377,1.032,0.969,1.032,0.29,1.761,0.232,1.707,2.970,0.337,0.808,0.547,5.393,0.184,1.816,1.223,0.412},
{10,0.949,0.308,0.975,0.973,1.028,0.284,1.716,0.276,1.669,3.078,0.325,0.797,0.687,5.469,0.223,1.777,1.176,0.363},
{11,0.905,0.285,0.927,0.975,1.025,0.321,1.679,0.313,1.637,3.173,0.315,0.787,0.811,5.535,0.256,1.744,0,0},
{12,0.886,0.266,0.886,0.978,1.023,0.354,1.646,0.346,1.610,3.258,0.307,0.778,0.922,5.594,0.283,1.717,0,0},
{13,0.832,0.249,0.850,0.979,1.021,0.382,1.618,0.374,1.585,3.336,0.300,0.770,1.025,5.647,0.307,1.693,0,0},
{14,0.802,0.235,0.817,0.981,1.019,0.406,1.594,0.399,1.563,3.407,0.294,0.763,1.118,5.696,0.328,1.672,0,0},
{15,0.775,0.223,0.789,0.982,1.018,0.428,1.157,0.421,1.544,3.472,0.288,0.756,1.203,5.741,0.347,1.653,0,0},
{16,0.750,0.212,0.763,0.984,1.017,0.448,1.552,0.440,1.526,3.532,0.283,0.750,1.282,5.782,0.363,1.637,0,0},
{17,0.728,0.203,0.739,0.985,1.016,0.466,1.534,0.458,1.511,3.588,0.279,0.744,1.356,5.820,0.378,1.622,0,0},
{18,0.707,0.194,0.718,0.985,1.015,0.482,1.518,0.475,1.496,3.640,0.275,0.739,1.424,5.856,0.391,1.608,0,0},
{19,0.688,0.187,0.698,0.986,1.014,0.497,1.503,0.490,1.483,3.689,0.271,0.734,1.487,5.891,0.403,1.597,0,0},
{20,0.671,0.180,0.680,0.987,1.013,0.510,1.490,0.504,1.470,3.735,0.268,0.729,1.549,5.921,0.415,1.585,0,0},
{21,0.655,0.173,0.663,0.988,1.013,0.253,1.477,0.516,1.459,3.778,0.265,0.724,1.605,5.951,0.425,1.575,0,0},
{22,0.640,0.167,0.647,0.988,1.012,0.534,1.466,0.528,1.448,3.819,0.262,0.720,1.659,5.979,0.434,1.566,0,0},
{23,0.626,0.126,0.633,0.989,1.011,0.545,1.455,0.539,1.438,3.858,0.259,0.716,1.710,6.006,0.443,1.557,0,0},
{24,0.612,0.157,0.619,0989,1.011,0.555,1.445,0.549,1.429,3.895,0.257,0.712,1.759,6.031,0.451,1.548,0,0},
{25,0.600,0.153,0.606,0.990,1.011,0.565,1.435,0.559,1.420,3.931,0.254,0.708,1.806,6.056,0.459,1.541,0,0} };
static double QU_k = 0.99865;
static double QL_k = 0.00135;
/// <summary>
/// 计算SPC主要参数
/// 输入:"X"被分析数据组Usl理论上限Lsl理论下限。
/// 输出x平均值"s"均方差;"QU"百分比上限;"QL"百分比下限;"cp"工序能力;"cpk"工序能力指数
/// </summary>
/// <param name="X">被分析数据组</param>
/// <param name="Usl">理论上限</param>
/// <param name="Lsl">理论下限</param>
/// <param name="x">平均值</param>
/// <param name="s">均方差</param>
/// <param name="QU">百分比上限</param>
/// <param name="QL">百分比下限</param>
/// <param name="cp">工序能力</param>
/// <param name="cpk">工序能力指数</param>
public static void SpcValue(double[] X, ref double Usl, ref double Lsl, out double x, out double s,
out double QU, out double QL, out double cp, out double cpk, out double[] sx, out double[] sy)
{
x = AVERAGE(X);
s = STDEV(X);
if (Usl == Lsl)
{
Usl = x + 4.0 * s;
Lsl = x - 4.0 * s;
}
QU_QL(X, out QU, out QL);
cp = Cp(QU, QL, Usl, Lsl);
cpk = Cpk(x, QU, QL, Usl, Lsl);
sxy(s, x, out sx, out sy);
}
/// <summary>
/// 计算SPC主要参数
/// 输入:"X"被分析数据组Usl理论上限Lsl理论下限。
/// 输出x平均值"s"均方差;"QU"百分比上限;"QL"百分比下限;"cp"工序能力;"cpk"工序能力指数
/// </summary>
/// <param name="X">被分析数据组</param>
/// <param name="Usl">理论上限</param>
/// <param name="Lsl">理论下限</param>
/// <param name="x">平均值</param>
/// <param name="s">均方差</param>
/// <param name="QU">百分比上限</param>
/// <param name="QL">百分比下限</param>
/// <param name="cp">工序能力</param>
/// <param name="cpk">工序能力指数</param>
public static void SpcValue(int n,double[] X, ref double Usl, ref double Lsl, out double x, out double s,
out double QU, out double QL, out double cp, out double cpk, out double[] sx, out double[] sy)
{
x = AVERAGE(X);
s = STDEV(X);
if (Usl == Lsl)
{
Usl = x + 4.0 * s;
Lsl = x - 4.0 * s;
}
QU_QL(X, out QU, out QL);
cp = Cp(QU, QL, Usl, Lsl);
cpk = Cpk(x, QU, QL, Usl, Lsl);
sxy(s, x, out sx, out sy);
double X2 = Spc_Data.Average(X, n);
double S2 = Spc_Data.StandardDeviation_S2(X, n);
double R2 = Spc_Data.Range_R2(X, n);
double xiGamaC4;
double xiGamaD2;
double c4 = (double)Spc_Data.Spc_Param.Tables[Xml_Spc_Param.Table_Name].Rows[n - 2][Xml_Spc_Param.Param_C4];
double d2 = (double)Spc_Data.Spc_Param.Tables[Xml_Spc_Param.Table_Name].Rows[n - 2][Xml_Spc_Param.Param_L_D1];
xiGamaC4 = S2 / c4;
xiGamaD2 = R2 / d2;
double USL = Usl;
double LSL = Lsl;
double T = USL - LSL;
double CP = T / (6 * xiGamaD2);
double M = (USL + LSL) / 2.0;
double M1 = M - X2;
M1 = Math.Abs(M1);
double CPK = CP - M1 / (3 * xiGamaD2);
cp = CP;
cpk = CPK;
}
/// <summary>
/// 均方差
/// </summary>
/// <param name="X">被分析数据组</param>
/// <returns>均方差</returns>
public static double STDEV(double[] X)
{
if (X.Length < 2)
return 0;
double s = 0;
//平均值
double x;
x = AVERAGE(X);
for (int i = 0; i < X.Length; i++)
{
s = s + (X[i] - x) * (X[i] - x);
}
s = Math.Sqrt(s / (double)(X.Length - 1));
return s;
}
/// <summary>
/// 平均值
/// </summary>
/// <param name="X">被分析数据组</param>
/// <returns>平均值</returns>
public static double AVERAGE(double[] X)
{
return X.Average();
}
/// <summary>
/// 排序
/// </summary>
/// <param name="X"></param>
/// <returns></returns>
public static double[] Sort(double[] X)
{
ArrayList temp = new ArrayList(X);
temp.Sort();
return X = (double[])temp.ToArray(typeof(double));
}
/// <summary>
/// 已知表格行数为m各行的数值分别记为 ,其中 表示第 行的数值,
/// 将这 个数值由小到大排列,记排列后的数值为 ,其中 表示 个数值经排列之后第k个数值。
/// 给定上下标线数值0.99865和0.00135。计算Q上和Q下的方法为
///a = m - 1* 0.99865
///取a的整数部分为i小数部分为j。
///Q上 = 1 j* xi+1+ j * xi+2
///同理:
///b = m - 1* 0.00135
///取b的整数部分为i小数部分为j。
///Q下 = 1 j* xi+1+ j * xi+2
/// </summary>
/// <param name="X">被分析数据组</param>
/// <param name="QU">百分比上限</param>
/// <param name="QL">百分比下限</param>
public static void QU_QL(double[] X, out double QU, out double QL)
{
QU = 0;
QL = 0;
double QU_n;
int QU_n_i;
double QU_n_j;
double QL_n;
int QL_n_i;
double QL_n_j;
X = Sort(X);
QU_n = (double)(X.Length - 1) * QU_k;
QU_n_i = (int)QU_n;
QU_n_j = QU_n - QU_n_i;
//Q上 = 1 j* xi+1+ j * xi+2
QU = (1 - QU_n_j) * X[QU_n_i] + QU_n_j * X[QU_n_i + 1];
QL_n = (double)(X.Length - 1) * QL_k;
QL_n_i = (int)QL_n;
QL_n_j = QL_n - QL_n_i;
//Q下 = 1 j* xi+1+ j * xi+2
QL = (1 - QL_n_j) * X[QL_n_i] + QL_n_j * X[QL_n_i + 1];
return;
}
/// <summary>
/// 工序能力
/// </summary>
/// <param name="X">被分析数据组</param>
/// <param name="Usl">理论上限</param>
/// <param name="Lsl">理论下限</param>
/// <returns>工序能力</returns>
public static double Cp(double[] X, double Usl, double Lsl)
{
double QU;
double QL;
double cp = 0;
QU_QL(X, out QU, out QL);
cp = (Usl - Lsl) / (QU - QL);
return cp;
}
/// <summary>
/// 工序能力
/// </summary>
/// <param name="QU">百分比上限</param>
/// <param name="QL">百分比下限</param>
/// <param name="Usl">理论上限</param>
/// <param name="Lsl">理论下限</param>
/// <returns></returns>
public static double Cp(double QU, double QL, double Usl, double Lsl)
{
double cp = 0;
cp = (Usl - Lsl) / (QU - QL);
return cp;
}
/// <summary>
/// 工序能力指数
/// </summary>
/// <param name="[] X">被分析数据组</param>
/// <param name="Usl">理论上限</param>
/// <param name="Lsl">理论下限</param>
/// <returns></returns>
public static double Cpk(double[] X, double Usl, double Lsl)
{
double cpk;
double cpkU;
double cpkL;
double QU;
double QL;
double cp = 0;
//均方差
double s;
//均值
double x;
x = AVERAGE(X);
QU_QL(X, out QU, out QL);
cp = (Usl - Lsl) / (QU - QL);
cpkU = (Usl - x) / (QU - x);
cpkL = (Lsl - x) / (QL - x);
cpk = Math.Min(cpkU, cpkL);
return cpk;
}
/// <summary>
/// 工序能力指数
/// </summary>
/// <param name="x">平均值</param>
/// <param name="QU">百分比上限</param>
/// <param name="QL">百分比下限</param>
/// <param name="Usl">理论上限</param>
/// <param name="Lsl">理论下限</param>
/// <returns></returns>
public static double Cpk(double x, double QU, double QL, double Usl, double Lsl)
{
double cpk;
double cpkU;
double cpkL;
double cp = 0;
cp = Cp(QU, QL, Usl, Lsl);
cpkU = (Usl - x) / (QU - x);
cpkL = (x - Lsl) / (x - QL);
cpk = Math.Min(cpkU, cpkL);
return cpk;
}
/// <summary>
/// 计算正态分布的x坐标y坐标
/// </summary>
/// <param name="s">均方差</param>
/// <param name="x">平均值</param>
public static void sxy(double s, double x, out double[] sx, out double[] sy)
{
double S2;
double X2;
X2 = x;
S2 = s;
sx = new double[11];
sy = new double[11];
double tempmaxdouble = 1.0 / (s * Math.Sqrt(2.0 * Math.PI));
sx[0] = X2 - 4.0 * S2;
sx[1] = X2 - 3.0 * S2;
sx[2] = X2 - 2.0 * S2;
sx[3] = X2 - 1.0 * S2;
sx[4] = X2 - 0.5 * S2;
sx[5] = X2;
sx[6] = X2 + 0.5 * S2;
sx[7] = X2 + 1.0 * S2;
sx[8] = X2 + 2.0 * S2;
sx[9] = X2 + 3.0 * S2;
sx[10] = X2 + 4.0 * S2;
sy[0] = tempmaxdouble * Math.Exp(-16.0F / 2.0F);
sy[1] = tempmaxdouble * Math.Exp(-9.0F / 2.0F);
sy[2] = tempmaxdouble * Math.Exp(-4.0F / 2.0F);
sy[3] = tempmaxdouble * Math.Exp(-1.0F / 2.0F);
sy[4] = tempmaxdouble * Math.Exp(-0.25F / 2.0F);
sy[5] = tempmaxdouble;
sy[6] = tempmaxdouble * Math.Exp(-0.25F / 2.0F);
sy[7] = tempmaxdouble * Math.Exp(-1.0F / 2.0F);
sy[8] = tempmaxdouble * Math.Exp(-4.0F / 2.0F);
sy[9] = tempmaxdouble * Math.Exp(-9.0F / 2.0F);
sy[10] = tempmaxdouble * Math.Exp(-16.0F / 2.0F);
double sy_sum = 0;
for (int i = 0; i < sy.Length; i++)
{
sy_sum = sy_sum + sy[i];
}
for (int i = 0; i < sy.Length; i++)
{
sy[i] = sy[i] / sy_sum;
}
}
/// <summary>
/// 根据查询的数据,获得理论上限,理论下限
/// </summary>
/// <param name="dl"></param>
/// <param name="Usl">理论上限</param>
/// <param name="Lsl">理论下限</param>
public static void GetUslLsl(DataTable dt, out double Usl, out double Lsl)
{
Usl = 0;
Lsl = 0;
if (dt != null)
{
if (dt.Rows.Count > 0)
{
try
{
//Usl = Convert.ToDouble(dt.Rows[0]["上限值"]);
//Lsl = Convert.ToDouble(dt.Rows[0]["下限值"]);
Usl = 100;
Lsl = 100;
}
catch
{
Usl = 0;
Lsl = 0;
}
}
}
}
}
/// <summary>
/// 测试数据
/// </summary>
public class Spc_Data_TestData
{
/// <summary>
/// 子组大小。单个子组观测值的个数
/// </summary>
static public int n = 5;
/// <summary>
/// 子组个数
/// </summary>
static public int k = 30;
/// <summary>
/// 特征值上限
/// </summary>
static public double USL = 1.7;
/// <summary>
/// 特征值下限
/// </summary>
static public double LSL = 1.5;
/// <summary>
/// 特征值上限
/// </summary>
static public double USL1 = 1.0;
/// <summary>
/// 特征值下限
/// </summary>
static public double LSL1 = 0.9;
/// <summary>
/// 特征值上限
/// </summary>
static public double USL2 = 1.15;
/// <summary>
/// 特征值下限
/// </summary>
static public double LSL2 = 1.10;
/// <summary>
/// 特征值上限
/// </summary>
static public double USL3 = 129.01;
/// <summary>
/// 特征值下限
/// </summary>
static public double LSL3 = 129;
static public double[] X3 =
{
129.006,129.006,129.006,129.005,129.006,
129.006,129.005,129.005,129.005,129.005,
129.005,129.006,129.007,129.006,129.005,
129.005,129.005,129.006,129.005,129.006,
129.006,129.006,129.007,129.006,129.005,
129.007,129.006,129.005,129.005,129.006,
129.006,129.007,129.005,129.005,129.005,
129.007,129.006,129.006,129.007,129.005,
129.007,129.005,129.005,129.006,129.007,
129.006,129.007,129.005,129.005,129.006
};
static public double[] X2 =
{
1.141,1.130,1.131,1.127,1.137,
1.140,1.137,1.130,1.135,1.125,
1.133,1.133,1.131,1.128,1.127,
1.122,1.131,1.131,1.125,1.123,
1.131,1.128,1.117,1.133,1.136,
1.123,1.128,1.135,1.127,1.130,
1.138,1.126,1.130,1.133,1.133,
1.130,1.127,1.128,1.127,1.128,
1.122,1.142,1.128,1.135,1.133,
1.142,1.127,1.133,1.135,1.135
};
static public double[] X1 =
{ 0.941,0.942,0.947,0.939,0.942,0.943,
0.942,0.950,0.943,0.948,0.941,0.953,
0.944,0.943,0.941,0.933,0.942,0.941,
0.942,0.942,0.942,0.947,0.938,0.941,
0.947,0.943,0.943,0.948,0.938,0.946,
0.946,0.943,0.945,0.946,0.942,0.951,
0.951,0.938,0.938,0.952,0.947,0.945,
0.951,0.948,0.946,0.947,0.947,0.947,
0.953,0.956
};
static public double[] X =
{ 1.55,1.58,1.61,1.60,1.60,//1
1.58,1.63,1.63,1.62,1.63,//2
1.62,1.63,1.62,1.59,1.58,//3
1.58,1.60,1.61,1.62,1.63,//4
1.58,1.64,1.63,1.62,1.62,//5
1.62,1.62,1.63,1.61,1.57,//6
1.64,1.62,1.61,1.60,1.58,//7
1.57,1.59,1.61,1.62,1.63,//8
1.58,1.61,1.60,1.62,1.63,//9
1.60,1.61,1.64,1.64,1.63,//10
1.58,1.60,1.62,1.63,1.65,//11
1.62,1.58,1.59,1.57,1.58,//12
1.57,1.57,1.58,1.59,1.64,//13
1.61,1.64,1.62,1.60,1.59,//14
1.65,1.62,1.62,1.60,1.58,//15
1.57,1.59,1.57,1.59,1.62,//16
1.56,1.57,1.57,1.61,1.62,//17
1.56,1.58,1.59,1.60,1.62,//18
1.58,1.60,1.60,1.62,1.63,//19
1.58,1.59,1.60,1.63,1.62,//20
1.58,1.59,1.62,1.63,1.64,//21
1.58,1.59,1.62,1.63,1.61,//22
1.58,1.59,1.60,1.61,1.63,//23
1.57,1.59,1.61,1.61,1.62,//24
1.58,1.58,1.60,1.61,1.63,//25
1.62,1.58,1.58,1.58,1.57,//26
1.63,1.59,1.57,1.58,1.57,//27
1.58,1.62,1.61,1.63,1.61,//28
1.58,1.57,1.59,1.60,1.62,//29
1.62,1.60,1.60,1.57,1.57 //30
};
}