1422 lines
44 KiB
C++
1422 lines
44 KiB
C++
#include "spc_core.h"
|
||
|
||
// ==================== SPC 系数结构实现 ====================
|
||
SpcCoefficient::SpcCoefficient(int id, int num, double a, double a2, double a3, double b3,
|
||
double b4, double b5, double b6, double d1, double d2,
|
||
double d3, double d4, double c4, double c4_1, double l_d1, double l_d1_1)
|
||
: ID(id), NUM(num), A(a), A2(a2), A3(a3), B3(b3), B4(b4), B5(b5), B6(b6),
|
||
D1(d1), D2(d2), D3(d3), D4(d4), C4(c4), C4_1(c4_1), L_D1(l_d1), L_D1_1(l_d1_1) {}
|
||
|
||
// ==================== SPC 系数表类实现 ====================
|
||
std::map<int, SpcCoefficient> SpcCoefficients::coefficientDict;
|
||
|
||
void SpcCoefficients::Initialize()
|
||
{
|
||
static bool initialized = false;
|
||
if (initialized)
|
||
return;
|
||
|
||
std::vector<SpcCoefficient> coefficients = {
|
||
SpcCoefficient(1, 2, 2.121, 1.88, 2.659, 0, 3.267, 0, 2.606, 0, 3.686, 0, 3.267, 0.7979, 1.2533, 1.128, 0.8865),
|
||
SpcCoefficient(2, 3, 1.732, 1.023, 1.954, 0, 2.568, 0, 2.676, 0, 4.358, 0, 2.574, 0.8862, 1.1284, 1.693, 0.5907),
|
||
SpcCoefficient(3, 4, 1.5, 0.729, 1.628, 0, 2.266, 0, 2.088, 0, 4.698, 0, 2.282, 0.9213, 1.0854, 2.059, 0.4857),
|
||
SpcCoefficient(4, 5, 1.342, 0.577, 1.427, 0, 2.089, 0, 1.964, 0, 4.918, 0, 2.114, 0.94, 1.0638, 2.326, 0.4299),
|
||
SpcCoefficient(5, 6, 1.225, 0.483, 1.287, 0.03, 1.97, 0.029, 1.874, 0, 5.078, 0, 2.004, 0.9515, 1.051, 2.534, 0.3946),
|
||
SpcCoefficient(6, 7, 1.134, 0.419, 1.182, 0.118, 1.882, 0.113, 1.806, 0.204, 5.204, 0.076, 1.924, 0.9594, 1.0423, 2.704, 0.3698),
|
||
SpcCoefficient(7, 8, 1.061, 0.373, 1.099, 0.185, 1.815, 0.179, 1.751, 0.338, 5.306, 0.136, 1.864, 0.965, 1.0363, 2.847, 0.3512),
|
||
SpcCoefficient(8, 9, 1, 0.337, 1.032, 0.239, 1.761, 0.232, 1.707, 0.547, 5.393, 0.184, 1.816, 0.9693, 1.0317, 2.97, 0.3367),
|
||
SpcCoefficient(9, 10, 0.949, 0.308, 0.975, 0.284, 1.716, 2.276, 1.669, 0.687, 5.469, 0.223, 1.777, 0.9727, 1.0281, 3.078, 0.3249),
|
||
SpcCoefficient(10, 11, 0.905, 0.285, 0.927, 0.321, 1.679, 0.313, 1.637, 0.811, 5.535, 0.256, 1.744, 0.9754, 1.0252, 3.173, 0.3152),
|
||
SpcCoefficient(11, 12, 0.866, 0.266, 0.886, 0.354, 1.646, 0.346, 1.61, 0.922, 5.594, 0.283, 1.717, 0.9776, 1.0229, 3.258, 0.3069),
|
||
SpcCoefficient(12, 13, 0.832, 0.249, 0.85, 0.382, 1.618, 0.374, 1.585, 1.025, 5.647, 0.307, 1.693, 0.9794, 1.021, 3.336, 0.2998),
|
||
SpcCoefficient(13, 14, 0.802, 0.235, 0.817, 0.406, 1.594, 0.399, 1.563, 1.118, 5.696, 0.328, 1.672, 0.981, 1.0194, 3.407, 0.2935),
|
||
SpcCoefficient(14, 15, 0.775, 0.223, 0.789, 0.428, 1.572, 0.421, 1.544, 1.203, 5.741, 0.347, 1.653, 0.9823, 1.018, 3.472, 0.288),
|
||
SpcCoefficient(15, 16, 0.75, 0.212, 0.763, 0.448, 1.552, 0.44, 1.526, 1.282, 5.782, 0.363, 1.637, 0.9835, 1.0168, 3.532, 0.2831),
|
||
SpcCoefficient(16, 17, 0.728, 0.203, 0.739, 0.466, 1.534, 0.458, 1.511, 1.356, 5.82, 0.378, 1.622, 0.9845, 1.0157, 3.588, 0.2787),
|
||
SpcCoefficient(17, 18, 0.707, 0.194, 0.718, 0.482, 1.518, 0.475, 1.496, 1.424, 5.856, 0.391, 1.608, 0.9854, 1.0148, 3.64, 0.2747),
|
||
SpcCoefficient(18, 19, 0.688, 0.187, 0.698, 0.497, 1.503, 0.49, 1.483, 1.487, 5.891, 0.403, 1.597, 0.9862, 1.014, 3.689, 0.2711),
|
||
SpcCoefficient(19, 20, 0.671, 0.18, 0.68, 0.51, 1.49, 0.504, 1.47, 1.549, 5.921, 0.415, 1.585, 0.9869, 1.0133, 3.735, 0.2677),
|
||
SpcCoefficient(20, 21, 0.655, 0.173, 0.663, 0.523, 1.477, 0.516, 1.459, 1.605, 5.951, 0.425, 1.575, 0.9876, 1.0126, 3.778, 0.2647),
|
||
SpcCoefficient(21, 22, 0.64, 0.167, 0.647, 0.534, 1.466, 0.528, 1.448, 1.659, 5.979, 0.434, 1.566, 0.9882, 1.0119, 3.819, 0.2618),
|
||
SpcCoefficient(22, 23, 0.626, 0.162, 0.633, 0.545, 1.455, 0.539, 1.438, 1.71, 6.006, 0.443, 1.557, 0.9887, 1.0114, 3.858, 0.2592),
|
||
SpcCoefficient(23, 24, 0.612, 0.157, 0.619, 0.555, 1.445, 0.549, 1.429, 1.759, 6.031, 0.451, 1.548, 0.9892, 1.0109, 3.895, 0.2567),
|
||
SpcCoefficient(24, 25, 0.6, 0.153, 0.606, 0.565, 1.435, 0.559, 1.42, 1.806, 6.056, 0.459, 1.541, 0.9896, 1.0105, 3.931, 0.2544)};
|
||
|
||
for (const auto &coeff : coefficients)
|
||
{
|
||
coefficientDict[coeff.NUM] = coeff;
|
||
}
|
||
|
||
initialized = true;
|
||
}
|
||
|
||
const SpcCoefficient &SpcCoefficients::GetBySubgroupSize(int subgroupSize)
|
||
{
|
||
Initialize();
|
||
|
||
auto it = coefficientDict.find(subgroupSize);
|
||
if (it != coefficientDict.end())
|
||
{
|
||
return it->second;
|
||
}
|
||
|
||
throw std::out_of_range("子组大小 " + std::to_string(subgroupSize) + " 不在有效范围 [2-25] 内");
|
||
}
|
||
|
||
double SpcCoefficients::GetA2(int subgroupSize) { return GetBySubgroupSize(subgroupSize).A2; }
|
||
double SpcCoefficients::GetA3(int subgroupSize) { return GetBySubgroupSize(subgroupSize).A3; }
|
||
double SpcCoefficients::GetD3(int subgroupSize) { return GetBySubgroupSize(subgroupSize).D3; }
|
||
double SpcCoefficients::GetD4(int subgroupSize) { return GetBySubgroupSize(subgroupSize).D4; }
|
||
double SpcCoefficients::GetB3(int subgroupSize) { return GetBySubgroupSize(subgroupSize).B3; }
|
||
double SpcCoefficients::GetB4(int subgroupSize) { return GetBySubgroupSize(subgroupSize).B4; }
|
||
double SpcCoefficients::GetC4(int subgroupSize) { return GetBySubgroupSize(subgroupSize).C4; }
|
||
double SpcCoefficients::GetL_D1(int subgroupSize) { return GetBySubgroupSize(subgroupSize).L_D1; }
|
||
|
||
// ==================== 工具函数实现 ====================
|
||
double SpcUtils::Round(double value, int decimals)
|
||
{
|
||
double factor = std::pow(10.0, decimals);
|
||
return std::round(value * factor) / factor;
|
||
}
|
||
|
||
double SpcUtils::Mean(const std::vector<double> &values)
|
||
{
|
||
if (values.empty())
|
||
return 0.0;
|
||
|
||
double sum = 0.0;
|
||
for (double value : values)
|
||
{
|
||
sum += value;
|
||
}
|
||
return sum / values.size();
|
||
}
|
||
|
||
double SpcUtils::Max(const std::vector<double> &values)
|
||
{
|
||
if (values.empty())
|
||
return 0.0;
|
||
|
||
double maxVal = values[0];
|
||
for (double value : values)
|
||
{
|
||
if (value > maxVal)
|
||
maxVal = value;
|
||
}
|
||
return maxVal;
|
||
}
|
||
|
||
double SpcUtils::Min(const std::vector<double> &values)
|
||
{
|
||
if (values.empty())
|
||
return 0.0;
|
||
|
||
double minVal = values[0];
|
||
for (double value : values)
|
||
{
|
||
if (value < minVal)
|
||
minVal = value;
|
||
}
|
||
return minVal;
|
||
}
|
||
|
||
double SpcUtils::Range(const std::vector<double> &values)
|
||
{
|
||
if (values.size() < 2)
|
||
return 0.0;
|
||
return Max(values) - Min(values);
|
||
}
|
||
|
||
double SpcUtils::StandardDeviation(const std::vector<double> &values)
|
||
{
|
||
if (values.size() < 2)
|
||
return 0.0;
|
||
|
||
double mean = Mean(values);
|
||
double sumSquares = 0.0;
|
||
|
||
for (double value : values)
|
||
{
|
||
double diff = value - mean;
|
||
sumSquares += diff * diff;
|
||
}
|
||
|
||
return std::sqrt(sumSquares / (values.size() - 1));
|
||
}
|
||
|
||
double SpcUtils::StandardDeviationPopulation(const std::vector<double> &values)
|
||
{
|
||
if (values.size() < 2)
|
||
return 0.0;
|
||
|
||
double mean = Mean(values);
|
||
double sumSquares = 0.0;
|
||
|
||
for (double value : values)
|
||
{
|
||
double diff = value - mean;
|
||
sumSquares += diff * diff;
|
||
}
|
||
|
||
return std::sqrt(sumSquares / values.size());
|
||
}
|
||
|
||
std::string SpcUtils::GetCurrentTimestamp()
|
||
{
|
||
auto now = std::chrono::system_clock::now();
|
||
auto time = std::chrono::system_clock::to_time_t(now);
|
||
std::tm tm;
|
||
#ifdef _WIN32
|
||
localtime_s(&tm, &time);
|
||
#else
|
||
localtime_r(&time, &tm);
|
||
#endif
|
||
|
||
std::ostringstream oss;
|
||
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
|
||
return oss.str();
|
||
}
|
||
|
||
// ==================== SPC 数据类实现 ====================
|
||
SpcDataXR::SpcDataXR() : n(0), k(0), CL_X(0.0), UCL_X(0.0), LCL_X(0.0),
|
||
CL_R(0.0), UCL_R(0.0), LCL_R(0.0) {}
|
||
|
||
json SpcDataXR::ToJson() const
|
||
{
|
||
json j;
|
||
j["n"] = n;
|
||
j["k"] = k;
|
||
j["CL_X"] = CL_X;
|
||
j["UCL_X"] = UCL_X;
|
||
j["LCL_X"] = LCL_X;
|
||
j["CL_R"] = CL_R;
|
||
j["UCL_R"] = UCL_R;
|
||
j["LCL_R"] = LCL_R;
|
||
j["CL_Xk"] = CL_Xk;
|
||
j["CL_Rk"] = CL_Rk;
|
||
return j;
|
||
}
|
||
|
||
SpcDataXR SpcDataXR::FromJson(const json &j)
|
||
{
|
||
SpcDataXR data;
|
||
data.n = j.value("n", 0);
|
||
data.k = j.value("k", 0);
|
||
data.CL_X = j.value("CL_X", 0.0);
|
||
data.UCL_X = j.value("UCL_X", 0.0);
|
||
data.LCL_X = j.value("LCL_X", 0.0);
|
||
data.CL_R = j.value("CL_R", 0.0);
|
||
data.UCL_R = j.value("UCL_R", 0.0);
|
||
data.LCL_R = j.value("LCL_R", 0.0);
|
||
|
||
if (j.contains("CL_Xk"))
|
||
{
|
||
data.CL_Xk = j["CL_Xk"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("CL_Rk"))
|
||
{
|
||
data.CL_Rk = j["CL_Rk"].get<std::vector<double>>();
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
SpcDataXS::SpcDataXS() : n(0), k(0), CL_X(0.0), UCL_X(0.0), LCL_X(0.0),
|
||
CL_S(0.0), UCL_S(0.0), LCL_S(0.0) {}
|
||
|
||
json SpcDataXS::ToJson() const
|
||
{
|
||
json j;
|
||
j["n"] = n;
|
||
j["k"] = k;
|
||
j["CL_X"] = CL_X;
|
||
j["UCL_X"] = UCL_X;
|
||
j["LCL_X"] = LCL_X;
|
||
j["CL_S"] = CL_S;
|
||
j["UCL_S"] = UCL_S;
|
||
j["LCL_S"] = LCL_S;
|
||
j["CL_Xk"] = CL_Xk;
|
||
j["CL_Sk"] = CL_Sk;
|
||
return j;
|
||
}
|
||
|
||
SpcDataXS SpcDataXS::FromJson(const json &j)
|
||
{
|
||
SpcDataXS data;
|
||
data.n = j.value("n", 0);
|
||
data.k = j.value("k", 0);
|
||
data.CL_X = j.value("CL_X", 0.0);
|
||
data.UCL_X = j.value("UCL_X", 0.0);
|
||
data.LCL_X = j.value("LCL_X", 0.0);
|
||
data.CL_S = j.value("CL_S", 0.0);
|
||
data.UCL_S = j.value("UCL_S", 0.0);
|
||
data.LCL_S = j.value("LCL_S", 0.0);
|
||
|
||
if (j.contains("CL_Xk"))
|
||
{
|
||
data.CL_Xk = j["CL_Xk"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("CL_Sk"))
|
||
{
|
||
data.CL_Sk = j["CL_Sk"].get<std::vector<double>>();
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
SpcDataCpk::SpcDataCpk() : n(0), k(0), SL(0.0), USL(0.0), LSL(0.0), Singma(0.0), SingmaS(0.0),
|
||
Ca(0.0), Cp(0.0), CPU(0.0), CPL(0.0), CR(0.0), Cpk(0.0), Pp(0.0),
|
||
PPU(0.0), PPL(0.0), PR(0.0), Ppk(0.0), ProcessSpread(0.0),
|
||
GroupWidth(0.0), GroupCount(0), ValueMax(0.0), ValueMin(0.0) {}
|
||
|
||
json SpcDataCpk::ToJson() const
|
||
{
|
||
json j;
|
||
j["n"] = n;
|
||
j["k"] = k;
|
||
j["SL"] = SL;
|
||
j["USL"] = USL;
|
||
j["LSL"] = LSL;
|
||
j["Singma"] = Singma;
|
||
j["SingmaS"] = SingmaS;
|
||
j["Ca"] = Ca;
|
||
j["Cp"] = Cp;
|
||
j["CPU"] = CPU;
|
||
j["CPL"] = CPL;
|
||
j["CR"] = CR;
|
||
j["Cpk"] = Cpk;
|
||
j["Pp"] = Pp;
|
||
j["PPU"] = PPU;
|
||
j["PPL"] = PPL;
|
||
j["PR"] = PR;
|
||
j["Ppk"] = Ppk;
|
||
j["ProcessSpread"] = ProcessSpread;
|
||
j["GroupWidth"] = GroupWidth;
|
||
j["GroupCount"] = GroupCount;
|
||
j["ValueMax"] = ValueMax;
|
||
j["ValueMin"] = ValueMin;
|
||
j["Xk"] = Xk;
|
||
j["XkUp"] = XkUp;
|
||
j["XkDown"] = XkDown;
|
||
j["Yk"] = Yk;
|
||
j["YkCount"] = YkCount;
|
||
j["NormalDistributionX"] = NormalDistributionX;
|
||
j["NormalDistributionY"] = NormalDistributionY;
|
||
return j;
|
||
}
|
||
|
||
SpcDataCpk SpcDataCpk::FromJson(const json &j)
|
||
{
|
||
SpcDataCpk data;
|
||
data.n = j.value("n", 0);
|
||
data.k = j.value("k", 0);
|
||
data.SL = j.value("SL", 0.0);
|
||
data.USL = j.value("USL", 0.0);
|
||
data.LSL = j.value("LSL", 0.0);
|
||
data.Singma = j.value("Singma", 0.0);
|
||
data.SingmaS = j.value("SingmaS", 0.0);
|
||
data.Ca = j.value("Ca", 0.0);
|
||
data.Cp = j.value("Cp", 0.0);
|
||
data.CPU = j.value("CPU", 0.0);
|
||
data.CPL = j.value("CPL", 0.0);
|
||
data.CR = j.value("CR", 0.0);
|
||
data.Cpk = j.value("Cpk", 0.0);
|
||
data.Pp = j.value("Pp", 0.0);
|
||
data.PPU = j.value("PPU", 0.0);
|
||
data.PPL = j.value("PPL", 0.0);
|
||
data.PR = j.value("PR", 0.0);
|
||
data.Ppk = j.value("Ppk", 0.0);
|
||
data.ProcessSpread = j.value("ProcessSpread", 0.0);
|
||
data.GroupWidth = j.value("GroupWidth", 0.0);
|
||
data.GroupCount = j.value("GroupCount", 0);
|
||
data.ValueMax = j.value("ValueMax", 0.0);
|
||
data.ValueMin = j.value("ValueMin", 0.0);
|
||
|
||
if (j.contains("Xk"))
|
||
{
|
||
data.Xk = j["Xk"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("XkUp"))
|
||
{
|
||
data.XkUp = j["XkUp"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("XkDown"))
|
||
{
|
||
data.XkDown = j["XkDown"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("Yk"))
|
||
{
|
||
data.Yk = j["Yk"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("YkCount"))
|
||
{
|
||
data.YkCount = j["YkCount"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("NormalDistributionX"))
|
||
{
|
||
data.NormalDistributionX = j["NormalDistributionX"].get<std::vector<double>>();
|
||
}
|
||
|
||
if (j.contains("NormalDistributionY"))
|
||
{
|
||
data.NormalDistributionY = j["NormalDistributionY"].get<std::vector<double>>();
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
// ==================== 统一的 SPC 计算结果 JSON 结构实现 ====================
|
||
SpcResultJson::SpcResultJson() : Timestamp(SpcUtils::GetCurrentTimestamp()), Version("1.0") {}
|
||
|
||
json SpcResultJson::ToJson() const
|
||
{
|
||
json j;
|
||
j["XR"] = XR.ToJson();
|
||
j["XS"] = XS.ToJson();
|
||
j["Cpk"] = Cpk.ToJson();
|
||
j["Timestamp"] = Timestamp;
|
||
j["Version"] = Version;
|
||
return j;
|
||
}
|
||
|
||
SpcResultJson SpcResultJson::FromJson(const json &j)
|
||
{
|
||
SpcResultJson result;
|
||
|
||
if (j.contains("XR"))
|
||
{
|
||
result.XR = SpcDataXR::FromJson(j["XR"]);
|
||
}
|
||
|
||
if (j.contains("XS"))
|
||
{
|
||
result.XS = SpcDataXS::FromJson(j["XS"]);
|
||
}
|
||
|
||
if (j.contains("Cpk"))
|
||
{
|
||
result.Cpk = SpcDataCpk::FromJson(j["Cpk"]);
|
||
}
|
||
|
||
result.Timestamp = j.value("Timestamp", SpcUtils::GetCurrentTimestamp());
|
||
result.Version = j.value("Version", "1.0");
|
||
|
||
return result;
|
||
}
|
||
|
||
// ==================== SPC 计算器实现 ====================
|
||
void SpcCalculator::CalculateHistogramData(const std::vector<double> &data, SpcDataCpk &result)
|
||
{
|
||
result.Xk.resize(result.GroupCount);
|
||
result.XkDown.resize(result.GroupCount);
|
||
result.XkUp.resize(result.GroupCount);
|
||
result.Yk.resize(result.GroupCount);
|
||
result.YkCount.resize(result.GroupCount, 0.0);
|
||
|
||
// 计算组边界
|
||
for (int i = 0; i < result.GroupCount; i++)
|
||
{
|
||
if (i == 0)
|
||
{
|
||
result.XkDown[0] = result.ValueMin;
|
||
result.XkUp[0] = result.ValueMin + result.GroupWidth;
|
||
}
|
||
else
|
||
{
|
||
result.XkDown[i] = result.XkDown[i - 1] + result.GroupWidth;
|
||
result.XkUp[i] = result.XkUp[i - 1] + result.GroupWidth;
|
||
}
|
||
result.Xk[i] = (result.XkDown[i] + result.XkUp[i]) / 2.0;
|
||
}
|
||
|
||
// 最后一组的上边界调整,确保包含最大值
|
||
result.XkUp[result.GroupCount - 1] = result.ValueMax;
|
||
|
||
// 统计频数
|
||
for (double value : data)
|
||
{
|
||
for (int i = 0; i < result.GroupCount; i++)
|
||
{
|
||
if (value >= result.XkDown[i] &&
|
||
(i == result.GroupCount - 1 ? value <= result.XkUp[i] : value < result.XkUp[i]))
|
||
{
|
||
result.YkCount[i]++;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 计算频率百分比
|
||
for (int i = 0; i < result.GroupCount; i++)
|
||
{
|
||
result.Yk[i] = result.YkCount[i] / data.size() * 100.0;
|
||
}
|
||
}
|
||
|
||
void SpcCalculator::CalculateNormalDistributionCurve(double mean, double sigma, SpcDataCpk &result)
|
||
{
|
||
result.NormalDistributionX.resize(9);
|
||
result.NormalDistributionY.resize(9);
|
||
|
||
// X坐标:-3σ到+3σ
|
||
for (int i = 0; i < 9; i++)
|
||
{
|
||
double sigmaMultiple = (i - 4) * 0.5;
|
||
result.NormalDistributionX[i] = mean + sigmaMultiple * sigma;
|
||
}
|
||
|
||
// 计算最大频数用于缩放
|
||
double maxCount = result.YkCount.empty() ? 1.0 : *std::max_element(result.YkCount.begin(), result.YkCount.end());
|
||
|
||
// Y坐标:正态分布概率密度(按最大频数缩放)
|
||
for (int i = 0; i < 9; i++)
|
||
{
|
||
double x = result.NormalDistributionX[i];
|
||
double exponent = -0.5 * std::pow((x - mean) / sigma, 2);
|
||
result.NormalDistributionY[i] = maxCount * std::exp(exponent);
|
||
}
|
||
}
|
||
|
||
SpcDataXR SpcCalculator::CalculateXR(const std::vector<double> &data, int subgroupSize)
|
||
{
|
||
SpcDataXR result;
|
||
|
||
if (data.empty() || subgroupSize < MIN_SUBGROUP_SIZE)
|
||
{
|
||
return result;
|
||
}
|
||
|
||
int k = data.size() / subgroupSize;
|
||
if (k == 0)
|
||
return result;
|
||
|
||
result.n = subgroupSize;
|
||
result.k = k;
|
||
|
||
// 获取 SPC 系数
|
||
const SpcCoefficient &coeff = SpcCoefficients::GetBySubgroupSize(subgroupSize);
|
||
|
||
// 计算各子组平均值和极差
|
||
result.CL_Xk.resize(k);
|
||
result.CL_Rk.resize(k);
|
||
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
|
||
result.CL_Xk[i] = SpcUtils::Mean(subgroup);
|
||
result.CL_Rk[i] = SpcUtils::Range(subgroup);
|
||
}
|
||
|
||
// 计算中心线
|
||
result.CL_X = SpcUtils::Mean(result.CL_Xk);
|
||
result.CL_R = SpcUtils::Mean(result.CL_Rk);
|
||
|
||
// 计算控制限
|
||
result.UCL_X = result.CL_X + coeff.A2 * result.CL_R;
|
||
result.LCL_X = result.CL_X - coeff.A2 * result.CL_R;
|
||
result.UCL_R = coeff.D4 * result.CL_R;
|
||
result.LCL_R = coeff.D3 * result.CL_R;
|
||
|
||
return result;
|
||
}
|
||
|
||
SpcDataXS SpcCalculator::CalculateXS(const std::vector<double> &data, int subgroupSize)
|
||
{
|
||
SpcDataXS result;
|
||
|
||
if (data.empty() || subgroupSize < MIN_SUBGROUP_SIZE)
|
||
{
|
||
return result;
|
||
}
|
||
|
||
int k = data.size() / subgroupSize;
|
||
if (k == 0)
|
||
return result;
|
||
|
||
result.n = subgroupSize;
|
||
result.k = k;
|
||
|
||
// 获取 SPC 系数
|
||
const SpcCoefficient &coeff = SpcCoefficients::GetBySubgroupSize(subgroupSize);
|
||
|
||
// 计算各子组平均值和标准差
|
||
result.CL_Xk.resize(k);
|
||
result.CL_Sk.resize(k);
|
||
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
|
||
result.CL_Xk[i] = SpcUtils::Mean(subgroup);
|
||
result.CL_Sk[i] = SpcUtils::StandardDeviation(subgroup); // 样本标准差
|
||
}
|
||
|
||
// 计算中心线
|
||
result.CL_X = SpcUtils::Mean(result.CL_Xk);
|
||
result.CL_S = SpcUtils::Mean(result.CL_Sk);
|
||
|
||
// 使用极差计算控制限(与原始代码一致)
|
||
double rBar = 0.0;
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
rBar += SpcUtils::Range(subgroup);
|
||
}
|
||
rBar /= k;
|
||
|
||
// 计算控制限
|
||
result.UCL_X = result.CL_X + coeff.A3 * rBar;
|
||
result.LCL_X = result.CL_X - coeff.A3 * rBar;
|
||
result.UCL_S = coeff.B4 * result.CL_S;
|
||
result.LCL_S = coeff.B3 * result.CL_S;
|
||
|
||
return result;
|
||
}
|
||
|
||
SpcDataCpk SpcCalculator::CalculateCpk(const std::vector<double> &data, int subgroupSize, double usl, double lsl)
|
||
{
|
||
SpcDataCpk result;
|
||
|
||
if (data.empty() || subgroupSize < MIN_SUBGROUP_SIZE)
|
||
{
|
||
return result;
|
||
}
|
||
|
||
int k = data.size() / subgroupSize;
|
||
if (k == 0)
|
||
return result;
|
||
|
||
result.n = subgroupSize;
|
||
result.k = k;
|
||
result.USL = usl;
|
||
result.LSL = lsl;
|
||
|
||
// 如果没给出规格限,使用3σ限
|
||
if (std::abs(usl - lsl) < 0.000001)
|
||
{
|
||
double overallMean1 = SpcUtils::Mean(data);
|
||
double overallStd = SpcUtils::StandardDeviationPopulation(data);
|
||
usl = overallMean1 + 3 * overallStd;
|
||
lsl = overallMean1 - 3 * overallStd;
|
||
result.USL = usl;
|
||
result.LSL = lsl;
|
||
}
|
||
|
||
// 计算总体平均值
|
||
double overallMean = SpcUtils::Mean(data);
|
||
|
||
// 获取 SPC 系数
|
||
const SpcCoefficient &coeff = SpcCoefficients::GetBySubgroupSize(subgroupSize);
|
||
|
||
// 计算组内标准差估计值(使用R-bar/d2)
|
||
double rBar = 0.0;
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
rBar += SpcUtils::Range(subgroup);
|
||
}
|
||
rBar /= k;
|
||
|
||
result.Singma = rBar / coeff.L_D1; // 组内标准差
|
||
|
||
// 计算标准差平均值
|
||
double sBar = 0.0;
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
sBar += SpcUtils::StandardDeviation(subgroup);
|
||
}
|
||
sBar /= k;
|
||
result.SingmaS = sBar;
|
||
|
||
// 计算能力指数
|
||
double tolerance = usl - lsl;
|
||
|
||
if (tolerance > 0)
|
||
{
|
||
result.Cp = tolerance / (6 * result.Singma);
|
||
result.CPU = (usl - overallMean) / (3 * result.Singma);
|
||
result.CPL = (overallMean - lsl) / (3 * result.Singma);
|
||
result.Cpk = std::min(result.CPU, result.CPL);
|
||
|
||
result.Pp = tolerance / (6 * result.SingmaS);
|
||
result.PPU = (usl - overallMean) / (3 * result.SingmaS);
|
||
result.PPL = (overallMean - lsl) / (3 * result.SingmaS);
|
||
result.Ppk = std::min(result.PPU, result.PPL);
|
||
|
||
// 计算 Ca(过程准确度)
|
||
double center = (usl + lsl) / 2.0;
|
||
result.Ca = std::abs(overallMean - center) / (tolerance / 2.0);
|
||
|
||
// 计算 CR 和 PR
|
||
result.CR = 6 * result.Singma / tolerance;
|
||
result.PR = 6 * result.SingmaS / tolerance;
|
||
|
||
result.SL = center;
|
||
}
|
||
|
||
// 计算直方图数据
|
||
result.ValueMax = SpcUtils::Max(data);
|
||
result.ValueMin = SpcUtils::Min(data);
|
||
result.ProcessSpread = result.ValueMax - result.ValueMin;
|
||
|
||
// 分组数(Sturges公式)
|
||
result.GroupCount = 1 + static_cast<int>(3.32 * std::log10(data.size()));
|
||
result.GroupWidth = result.ProcessSpread / result.GroupCount;
|
||
|
||
// 计算分组数据
|
||
CalculateHistogramData(data, result);
|
||
|
||
// 计算正态分布曲线
|
||
CalculateNormalDistributionCurve(overallMean, result.SingmaS, result);
|
||
|
||
return result;
|
||
}
|
||
json SpcCalculator::Spc(const json ¶m)
|
||
{
|
||
try
|
||
{
|
||
SpcTestData req_param = SpcTestData::FromJson(param);
|
||
// 使用测试数据
|
||
const std::vector<double> &testData = req_param.x; // 改为小写 x
|
||
int subgroupSize = req_param.n;
|
||
double usl = req_param.usl;
|
||
double lsl = req_param.lsl;
|
||
|
||
// 计算并获取整合的 JSON
|
||
SpcDataXR xr = CalculateXR(testData, subgroupSize);
|
||
SpcDataXS xs = CalculateXS(testData, subgroupSize);
|
||
SpcDataCpk cpk = CalculateCpk(testData, subgroupSize, usl, lsl);
|
||
|
||
// 四舍五入所有数值
|
||
RoundSpcData(xr, xs, cpk);
|
||
|
||
SpcResultJson result;
|
||
result.XR = xr;
|
||
result.XS = xs;
|
||
result.Cpk = cpk;
|
||
|
||
return result.ToJson();
|
||
}
|
||
catch (const std::exception &e)
|
||
{
|
||
json error;
|
||
error["error"] = "SPC calculation failed: " + std::string(e.what());
|
||
return error;
|
||
}
|
||
}
|
||
json SpcCalculator::CalculateAllToJson(const std::vector<double> &data, int subgroupSize, double usl, double lsl)
|
||
{
|
||
SpcDataXR xr = CalculateXR(data, subgroupSize);
|
||
SpcDataXS xs = CalculateXS(data, subgroupSize);
|
||
SpcDataCpk cpk = CalculateCpk(data, subgroupSize, usl, lsl);
|
||
|
||
// 四舍五入所有数值
|
||
RoundSpcData(xr, xs, cpk);
|
||
|
||
SpcResultJson result;
|
||
result.XR = xr;
|
||
result.XS = xs;
|
||
result.Cpk = cpk;
|
||
|
||
return result.ToJson(); // 缩进2个空格
|
||
// return result.ToJson().dump(2); // 缩进2个空格
|
||
}
|
||
|
||
void SpcCalculator::RoundSpcData(SpcDataXR &xr, SpcDataXS &xs, SpcDataCpk &cpk, int decimals)
|
||
{
|
||
RoundSpcDataXR(xr, decimals);
|
||
RoundSpcDataXS(xs, decimals);
|
||
RoundSpcDataCpk(cpk, decimals);
|
||
}
|
||
|
||
void SpcCalculator::RoundSpcDataXR(SpcDataXR &data, int decimals)
|
||
{
|
||
data.CL_X = SpcUtils::Round(data.CL_X, decimals);
|
||
data.UCL_X = SpcUtils::Round(data.UCL_X, decimals);
|
||
data.LCL_X = SpcUtils::Round(data.LCL_X, decimals);
|
||
data.CL_R = SpcUtils::Round(data.CL_R, decimals);
|
||
data.UCL_R = SpcUtils::Round(data.UCL_R, decimals);
|
||
data.LCL_R = SpcUtils::Round(data.LCL_R, decimals);
|
||
|
||
for (double &value : data.CL_Xk)
|
||
{
|
||
value = SpcUtils::Round(value, decimals);
|
||
}
|
||
|
||
for (double &value : data.CL_Rk)
|
||
{
|
||
value = SpcUtils::Round(value, decimals);
|
||
}
|
||
}
|
||
|
||
void SpcCalculator::RoundSpcDataXS(SpcDataXS &data, int decimals)
|
||
{
|
||
data.CL_X = SpcUtils::Round(data.CL_X, decimals);
|
||
data.UCL_X = SpcUtils::Round(data.UCL_X, decimals);
|
||
data.LCL_X = SpcUtils::Round(data.LCL_X, decimals);
|
||
data.CL_S = SpcUtils::Round(data.CL_S, decimals);
|
||
data.UCL_S = SpcUtils::Round(data.UCL_S, decimals);
|
||
data.LCL_S = SpcUtils::Round(data.LCL_S, decimals);
|
||
|
||
for (double &value : data.CL_Xk)
|
||
{
|
||
value = SpcUtils::Round(value, decimals);
|
||
}
|
||
|
||
for (double &value : data.CL_Sk)
|
||
{
|
||
value = SpcUtils::Round(value, decimals);
|
||
}
|
||
}
|
||
|
||
void SpcCalculator::RoundSpcDataCpk(SpcDataCpk &data, int decimals)
|
||
{
|
||
data.SL = SpcUtils::Round(data.SL, decimals);
|
||
data.USL = SpcUtils::Round(data.USL, decimals);
|
||
data.LSL = SpcUtils::Round(data.LSL, decimals);
|
||
data.Singma = SpcUtils::Round(data.Singma, decimals);
|
||
data.SingmaS = SpcUtils::Round(data.SingmaS, decimals);
|
||
data.Ca = SpcUtils::Round(data.Ca, decimals);
|
||
data.Cp = SpcUtils::Round(data.Cp, decimals);
|
||
data.CPU = SpcUtils::Round(data.CPU, decimals);
|
||
data.CPL = SpcUtils::Round(data.CPL, decimals);
|
||
data.CR = SpcUtils::Round(data.CR, decimals);
|
||
data.Cpk = SpcUtils::Round(data.Cpk, decimals);
|
||
data.Pp = SpcUtils::Round(data.Pp, decimals);
|
||
data.PPU = SpcUtils::Round(data.PPU, decimals);
|
||
data.PPL = SpcUtils::Round(data.PPL, decimals);
|
||
data.PR = SpcUtils::Round(data.PR, decimals);
|
||
data.Ppk = SpcUtils::Round(data.Ppk, decimals);
|
||
data.ProcessSpread = SpcUtils::Round(data.ProcessSpread, decimals);
|
||
data.GroupWidth = SpcUtils::Round(data.GroupWidth, decimals);
|
||
data.ValueMax = SpcUtils::Round(data.ValueMax, decimals);
|
||
data.ValueMin = SpcUtils::Round(data.ValueMin, decimals);
|
||
|
||
for (double &value : data.Xk)
|
||
value = SpcUtils::Round(value, decimals);
|
||
for (double &value : data.XkUp)
|
||
value = SpcUtils::Round(value, decimals);
|
||
for (double &value : data.XkDown)
|
||
value = SpcUtils::Round(value, decimals);
|
||
for (double &value : data.Yk)
|
||
value = SpcUtils::Round(value, decimals);
|
||
for (double &value : data.YkCount)
|
||
value = SpcUtils::Round(value, decimals);
|
||
for (double &value : data.NormalDistributionX)
|
||
value = SpcUtils::Round(value, decimals);
|
||
for (double &value : data.NormalDistributionY)
|
||
value = SpcUtils::Round(value, decimals);
|
||
}
|
||
|
||
double SpcCalculator::CalculateCp(const std::vector<double> &data, int subgroupSize, double usl, double lsl)
|
||
{
|
||
const SpcCoefficient &coeff = SpcCoefficients::GetBySubgroupSize(subgroupSize);
|
||
|
||
int k = data.size() / subgroupSize;
|
||
double rBar = 0.0;
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
rBar += SpcUtils::Range(subgroup);
|
||
}
|
||
rBar /= k;
|
||
|
||
double sigma = rBar / coeff.L_D1;
|
||
return (usl - lsl) / (6 * sigma);
|
||
}
|
||
|
||
double SpcCalculator::CalculatePp(const std::vector<double> &data, int subgroupSize, double usl, double lsl)
|
||
{
|
||
double sigma = SpcUtils::StandardDeviationPopulation(data);
|
||
return (usl - lsl) / (6 * sigma);
|
||
}
|
||
|
||
double SpcCalculator::CalculateCpu(const std::vector<double> &data, int subgroupSize, double usl)
|
||
{
|
||
const SpcCoefficient &coeff = SpcCoefficients::GetBySubgroupSize(subgroupSize);
|
||
|
||
double overallMean = SpcUtils::Mean(data);
|
||
|
||
int k = data.size() / subgroupSize;
|
||
double rBar = 0.0;
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
rBar += SpcUtils::Range(subgroup);
|
||
}
|
||
rBar /= k;
|
||
|
||
double sigma = rBar / coeff.L_D1;
|
||
return (usl - overallMean) / (3 * sigma);
|
||
}
|
||
|
||
double SpcCalculator::CalculateCpl(const std::vector<double> &data, int subgroupSize, double lsl)
|
||
{
|
||
const SpcCoefficient &coeff = SpcCoefficients::GetBySubgroupSize(subgroupSize);
|
||
|
||
double overallMean = SpcUtils::Mean(data);
|
||
|
||
int k = data.size() / subgroupSize;
|
||
double rBar = 0.0;
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
rBar += SpcUtils::Range(subgroup);
|
||
}
|
||
rBar /= k;
|
||
|
||
double sigma = rBar / coeff.L_D1;
|
||
return (overallMean - lsl) / (3 * sigma);
|
||
}
|
||
|
||
double SpcCalculator::CalculateXbarbar(const std::vector<double> &data, int subgroupSize)
|
||
{
|
||
int k = data.size() / subgroupSize;
|
||
std::vector<double> subgroupMeans(k);
|
||
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
subgroupMeans[i] = SpcUtils::Mean(subgroup);
|
||
}
|
||
|
||
return SpcUtils::Mean(subgroupMeans);
|
||
}
|
||
|
||
double SpcCalculator::CalculateRbar(const std::vector<double> &data, int subgroupSize)
|
||
{
|
||
int k = data.size() / subgroupSize;
|
||
std::vector<double> subgroupRanges(k);
|
||
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
subgroupRanges[i] = SpcUtils::Range(subgroup);
|
||
}
|
||
|
||
return SpcUtils::Mean(subgroupRanges);
|
||
}
|
||
|
||
double SpcCalculator::CalculateSbar(const std::vector<double> &data, int subgroupSize)
|
||
{
|
||
int k = data.size() / subgroupSize;
|
||
std::vector<double> subgroupStdDevs(k);
|
||
|
||
for (int i = 0; i < k; i++)
|
||
{
|
||
std::vector<double> subgroup(subgroupSize);
|
||
std::copy(data.begin() + i * subgroupSize,
|
||
data.begin() + (i + 1) * subgroupSize,
|
||
subgroup.begin());
|
||
subgroupStdDevs[i] = SpcUtils::StandardDeviation(subgroup);
|
||
}
|
||
|
||
return SpcUtils::Mean(subgroupStdDevs);
|
||
}
|
||
|
||
// ==================== 直方图计算器实现 ====================
|
||
void HistogramCalculator::CalculateHistogram(const std::vector<double> &data, int numBins,
|
||
std::vector<int> &frequencies, std::vector<double> &cumulativePercentages)
|
||
{
|
||
frequencies.clear();
|
||
cumulativePercentages.clear();
|
||
|
||
if (data.empty() || numBins <= 0)
|
||
return;
|
||
|
||
frequencies.resize(numBins, 0);
|
||
cumulativePercentages.resize(numBins, 0.0);
|
||
|
||
double min = SpcUtils::Min(data);
|
||
double max = SpcUtils::Max(data);
|
||
double binWidth = (max - min) / numBins;
|
||
|
||
// 调整边界,确保所有数据都能被包含
|
||
min = std::floor(min / binWidth) * binWidth;
|
||
max = std::ceil(max / binWidth) * binWidth;
|
||
binWidth = (max - min) / numBins;
|
||
|
||
// 统计频数
|
||
for (double value : data)
|
||
{
|
||
int binIndex = static_cast<int>(std::floor((value - min) / binWidth));
|
||
if (binIndex == numBins)
|
||
binIndex--; // 处理最大值的情况
|
||
frequencies[binIndex]++;
|
||
}
|
||
|
||
// 计算累计百分比
|
||
int total = data.size();
|
||
int cumulative = 0;
|
||
for (int i = 0; i < numBins; i++)
|
||
{
|
||
cumulative += frequencies[i];
|
||
cumulativePercentages[i] = static_cast<double>(cumulative) / total * 100.0;
|
||
}
|
||
}
|
||
|
||
double HistogramCalculator::CalculateBinWidth(const std::vector<double> &data, int numBins)
|
||
{
|
||
if (data.size() < 2 || numBins <= 0)
|
||
return 0.0;
|
||
|
||
double min = SpcUtils::Min(data);
|
||
double max = SpcUtils::Max(data);
|
||
double binWidth = (max - min) / numBins;
|
||
|
||
// 舍入组距的内部函数
|
||
auto RoundInterval = [](double interval) -> double
|
||
{
|
||
if (interval == 0.0)
|
||
{
|
||
throw std::out_of_range("组距不能为零");
|
||
}
|
||
|
||
// 处理大于1的情况
|
||
double step = -1.0;
|
||
double tempValue = interval;
|
||
while (tempValue > 1.0)
|
||
{
|
||
step++;
|
||
tempValue = tempValue / 10.0;
|
||
if (step > 1000)
|
||
{
|
||
throw std::runtime_error("自动组距计算错误");
|
||
}
|
||
}
|
||
|
||
// 处理小于1的情况
|
||
tempValue = interval;
|
||
if (tempValue < 1.0)
|
||
{
|
||
step = 0.0;
|
||
}
|
||
|
||
while (tempValue < 1.0)
|
||
{
|
||
step--;
|
||
tempValue = tempValue * 10.0;
|
||
if (step < -1000)
|
||
{
|
||
throw std::runtime_error("自动组距计算错误");
|
||
}
|
||
}
|
||
|
||
double tempDiff = interval / std::pow(10.0, step);
|
||
if (tempDiff < 3.0)
|
||
{
|
||
tempDiff = 2.0;
|
||
}
|
||
else if (tempDiff < 7.0)
|
||
{
|
||
tempDiff = 5.0;
|
||
}
|
||
else
|
||
{
|
||
tempDiff = 10.0;
|
||
}
|
||
|
||
return tempDiff * std::pow(10.0, step);
|
||
};
|
||
|
||
return RoundInterval(binWidth);
|
||
}
|
||
|
||
// ==================== API 响应和请求类实现 ====================
|
||
SpcTestData::SpcTestData() : n(0), k(0), usl(0.0), lsl(0.0) {}
|
||
|
||
json SpcTestData::ToJson() const
|
||
{
|
||
json j;
|
||
j["n"] = n;
|
||
j["k"] = k;
|
||
j["usl"] = usl;
|
||
j["lsl"] = lsl;
|
||
j["x"] = x;
|
||
return j;
|
||
}
|
||
|
||
SpcTestData SpcTestData::FromJson(const json &j)
|
||
{
|
||
SpcTestData data;
|
||
data.n = j.value("n", 0);
|
||
data.k = j.value("k", 0);
|
||
data.usl = j.value("usl", 0.0);
|
||
data.lsl = j.value("lsl", 0.0);
|
||
|
||
if (j.contains("x"))
|
||
{
|
||
data.x = j["x"].get<std::vector<double>>();
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
// ApiResponseSpc::ApiResponseSpc() : success(false), code(0) {}
|
||
|
||
// json ApiResponseSpc::ToJson() const
|
||
// {
|
||
// json j;
|
||
// j["success"] = success;
|
||
// j["code"] = code;
|
||
// j["msg"] = msg;
|
||
// j["req_code"] = req_code;
|
||
// j["req_from"] = req_from;
|
||
// j["req_cmd"] = req_cmd;
|
||
|
||
// if (req_param)
|
||
// {
|
||
// j["req_param"] = req_param->ToJson();
|
||
// }
|
||
|
||
// return j;
|
||
// }
|
||
|
||
// ApiResponseSpc ApiResponseSpc::FromJson(const json &j)
|
||
// {
|
||
// ApiResponseSpc response;
|
||
// response.success = j.value("success", false);
|
||
// response.code = j.value("code", 0);
|
||
// response.msg = j.value("msg", "");
|
||
// response.req_code = j.value("req_code", "");
|
||
// response.req_from = j.value("req_from", "");
|
||
// response.req_cmd = j.value("req_cmd", "");
|
||
|
||
// if (j.contains("req_param"))
|
||
// {
|
||
// response.req_param = std::make_shared<SpcRequestParam>();
|
||
// *response.req_param = SpcRequestParam::FromJson(j["req_param"]);
|
||
// }
|
||
|
||
// return response;
|
||
// }
|
||
|
||
// ==================== SPC 数据处理工具实现 ====================
|
||
// ApiResponseSpc SpcDataProcessor::DeserializeApiResponseSpc(const std::string &jsonStr)
|
||
// {
|
||
// ApiResponseSpc response;
|
||
// response.success = true;
|
||
|
||
// if (jsonStr.empty())
|
||
// {
|
||
// response.success = false;
|
||
// response.msg = "JSON 字符串不能为空";
|
||
// return response;
|
||
// }
|
||
|
||
// try
|
||
// {
|
||
// json j = json::parse(jsonStr);
|
||
// response = ApiResponseSpc::FromJson(j);
|
||
|
||
// // 验证响应
|
||
// ApiResponseSpc validationResult = ValidateResponse(response);
|
||
// response.success = validationResult.success;
|
||
// response.msg = validationResult.msg;
|
||
|
||
// return response;
|
||
// }
|
||
// catch (const std::exception &ex)
|
||
// {
|
||
// response.success = false;
|
||
// response.msg = "JSON 字符串符不合理: " + std::string(ex.what());
|
||
// return response;
|
||
// }
|
||
// }
|
||
|
||
// SpcTestData SpcDataProcessor::ExtractSpcTestData(const ApiResponseSpc &response)
|
||
// {
|
||
// if (!response.success || !response.req_param)
|
||
// {
|
||
// return SpcTestData();
|
||
// }
|
||
|
||
// SpcTestData data;
|
||
// data.n = response.req_param->n;
|
||
// data.k = response.req_param->k;
|
||
// data.usl = response.req_param->usl;
|
||
// data.lsl = response.req_param->lsl;
|
||
// data.x = response.req_param->x;
|
||
|
||
// return data;
|
||
// }
|
||
|
||
// ApiResponseSpc SpcDataProcessor::ValidateResponse(const ApiResponseSpc &response)
|
||
// {
|
||
// ApiResponseSpc result;
|
||
// result.success = true;
|
||
|
||
// if (!response.req_param)
|
||
// {
|
||
// result.success = false;
|
||
// result.msg = "请求参数为空";
|
||
// return result;
|
||
// }
|
||
|
||
// const auto &data = *response.req_param;
|
||
|
||
// // 验证 SPC 数据完整性
|
||
// if (data.n <= 0)
|
||
// {
|
||
// result.success = false;
|
||
// result.msg = "n=" + std::to_string(data.n) + "子组大小必须大于0";
|
||
// return result;
|
||
// }
|
||
|
||
// if (data.k <= 0)
|
||
// {
|
||
// result.success = false;
|
||
// result.msg = "k=" + std::to_string(data.k) + "子组个数必须大于0";
|
||
// return result;
|
||
// }
|
||
|
||
// if (data.x.empty())
|
||
// {
|
||
// result.success = false;
|
||
// result.msg = "测量数据不能为空";
|
||
// return result;
|
||
// }
|
||
|
||
// // 验证数据个数是否匹配
|
||
// int expectedDataCount = data.n * data.k;
|
||
// if (data.x.size() != expectedDataCount)
|
||
// {
|
||
// result.success = false;
|
||
// result.msg = "数据个数不匹配:子组大小(n)=" + std::to_string(data.n) +
|
||
// ", 子组个数(k)=" + std::to_string(data.k) +
|
||
// ", 期望数据个数=" + std::to_string(expectedDataCount) +
|
||
// ", 实际数据个数=" + std::to_string(data.x.size());
|
||
// return result;
|
||
// }
|
||
|
||
// if (data.usl <= data.lsl)
|
||
// {
|
||
// result.success = true;
|
||
// result.msg = "警告: 规格上限应大于规格下限,SPC 数据完整";
|
||
// return result;
|
||
// }
|
||
|
||
// result.success = true;
|
||
// result.msg = "SPC 数据完整";
|
||
// return result;
|
||
// }
|
||
|
||
// ==================== 示例数据实现 ====================
|
||
namespace Spc_Data_TestData
|
||
{
|
||
const int n = 5;
|
||
const int k = 30;
|
||
const double USL = 1.7;
|
||
const double LSL = 1.5;
|
||
|
||
const std::vector<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
|
||
};
|
||
}
|
||
|
||
// ==================== 示例函数实现 ====================
|
||
void RunJsonExample_5_30()
|
||
{
|
||
std::cout << "=== SPC JSON 计算示例 (n=5, k=30) ===" << std::endl;
|
||
|
||
// 使用测试数据
|
||
const std::vector<double> &testData = Spc_Data_TestData::X;
|
||
int subgroupSize = Spc_Data_TestData::n;
|
||
double usl = Spc_Data_TestData::USL;
|
||
double lsl = Spc_Data_TestData::LSL;
|
||
|
||
// 计算并获取整合的 JSON
|
||
std::string jsonResult = SpcCalculator::CalculateAllToJson(testData, subgroupSize, usl, lsl);
|
||
std::cout << "整合的 SPC JSON 结果:" << std::endl;
|
||
std::cout << jsonResult << std::endl;
|
||
|
||
// 也可以单独计算
|
||
SpcDataXR xr = SpcCalculator::CalculateXR(testData, subgroupSize);
|
||
SpcDataXS xs = SpcCalculator::CalculateXS(testData, subgroupSize);
|
||
SpcDataCpk cpk = SpcCalculator::CalculateCpk(testData, subgroupSize, usl, lsl);
|
||
|
||
// 四舍五入
|
||
SpcCalculator::RoundSpcData(xr, xs, cpk);
|
||
|
||
// 创建结果对象
|
||
SpcResultJson result;
|
||
result.XR = xr;
|
||
result.XS = xs;
|
||
result.Cpk = cpk;
|
||
|
||
std::string json = result.ToJson().dump(2);
|
||
std::cout << "\n单独序列化的结果:" << std::endl;
|
||
std::cout << json << std::endl;
|
||
}
|
||
|
||
void RunSpcExample()
|
||
{
|
||
std::cout << "=== SPC 计算示例 ===" << std::endl;
|
||
|
||
// 示例数据
|
||
std::vector<double> testData = {
|
||
1.55, 1.58, 1.61, 1.60, 1.60,
|
||
1.58, 1.63, 1.63, 1.62, 1.63,
|
||
1.62, 1.63, 1.62, 1.59, 1.58,
|
||
1.58, 1.60, 1.61, 1.62, 1.63};
|
||
|
||
int subgroupSize = 5;
|
||
double usl = 1.70;
|
||
double lsl = 1.50;
|
||
|
||
std::cout << "数据点数: " << testData.size() << std::endl;
|
||
std::cout << "子组大小: " << subgroupSize << std::endl;
|
||
std::cout << "规格上限: " << usl << std::endl;
|
||
std::cout << "规格下限: " << lsl << std::endl;
|
||
std::cout << std::endl;
|
||
|
||
// 1. 计算 X-R 控制图
|
||
SpcDataXR xrResult = SpcCalculator::CalculateXR(testData, subgroupSize);
|
||
std::cout << "X-R控制图结果:" << std::endl;
|
||
std::cout << "X图中心线 (CL_X): " << xrResult.CL_X << std::endl;
|
||
std::cout << "X图上控制限 (UCL_X): " << xrResult.UCL_X << std::endl;
|
||
std::cout << "X图下控制限 (LCL_X): " << xrResult.LCL_X << std::endl;
|
||
std::cout << "R图中心线 (CL_R): " << xrResult.CL_R << std::endl;
|
||
std::cout << "R图上控制限 (UCL_R): " << xrResult.UCL_R << std::endl;
|
||
std::cout << "R图下控制限 (LCL_R): " << xrResult.LCL_R << std::endl;
|
||
std::cout << std::endl;
|
||
|
||
// 2. 计算 X-S 控制图
|
||
SpcDataXS xsResult = SpcCalculator::CalculateXS(testData, subgroupSize);
|
||
std::cout << "X-S控制图结果:" << std::endl;
|
||
std::cout << "X图中心线 (CL_X): " << xsResult.CL_X << std::endl;
|
||
std::cout << "X图上控制限 (UCL_X): " << xsResult.UCL_X << std::endl;
|
||
std::cout << "X图下控制限 (LCL_X): " << xsResult.LCL_X << std::endl;
|
||
std::cout << "S图中心线 (CL_S): " << xsResult.CL_S << std::endl;
|
||
std::cout << "S图上控制限 (UCL_S): " << xsResult.UCL_S << std::endl;
|
||
std::cout << "S图下控制限 (LCL_S): " << xsResult.LCL_S << std::endl;
|
||
std::cout << std::endl;
|
||
|
||
// 3. 计算过程能力指数
|
||
SpcDataCpk cpkResult = SpcCalculator::CalculateCpk(testData, subgroupSize, usl, lsl);
|
||
std::cout << "过程能力指数结果:" << std::endl;
|
||
std::cout << "Cp: " << cpkResult.Cp << std::endl;
|
||
std::cout << "Cpk: " << cpkResult.Cpk << std::endl;
|
||
std::cout << "Cpu: " << cpkResult.CPU << std::endl;
|
||
std::cout << "Cpl: " << cpkResult.CPL << std::endl;
|
||
std::cout << "Pp: " << cpkResult.Pp << std::endl;
|
||
std::cout << "Ppk: " << cpkResult.Ppk << std::endl;
|
||
std::cout << "Ca: " << cpkResult.Ca << std::endl;
|
||
std::cout << std::endl;
|
||
|
||
// 4. 计算其他统计指标
|
||
std::cout << "其他统计指标:" << std::endl;
|
||
std::cout << "总体平均值: " << SpcCalculator::CalculateXbarbar(testData, subgroupSize) << std::endl;
|
||
std::cout << "R-bar: " << SpcCalculator::CalculateRbar(testData, subgroupSize) << std::endl;
|
||
std::cout << "S-bar: " << SpcCalculator::CalculateSbar(testData, subgroupSize) << std::endl;
|
||
std::cout << "Cp值: " << SpcCalculator::CalculateCp(testData, subgroupSize, usl, lsl) << std::endl;
|
||
std::cout << "Pp值: " << SpcCalculator::CalculatePp(testData, subgroupSize, usl, lsl) << std::endl;
|
||
std::cout << std::endl;
|
||
|
||
// 5. 计算直方图数据
|
||
std::vector<int> frequencies;
|
||
std::vector<double> cumulativePercentages;
|
||
HistogramCalculator::CalculateHistogram(testData, 6, frequencies, cumulativePercentages);
|
||
|
||
std::cout << "直方图数据 (前3组):" << std::endl;
|
||
for (int i = 0; i < std::min(3, static_cast<int>(frequencies.size())); i++)
|
||
{
|
||
std::cout << "组" << i + 1 << ": 频数=" << frequencies[i]
|
||
<< ", 累计%=" << cumulativePercentages[i] << std::endl;
|
||
}
|
||
std::cout << std::endl;
|
||
|
||
// 6. 获取 SPC 系数
|
||
const SpcCoefficient &coeff = SpcCoefficients::GetBySubgroupSize(subgroupSize);
|
||
std::cout << "SPC系数 (n=" << subgroupSize << "):" << std::endl;
|
||
std::cout << "A2: " << coeff.A2 << std::endl;
|
||
std::cout << "D4: " << coeff.D4 << std::endl;
|
||
std::cout << "d2 (L_D1): " << coeff.L_D1 << std::endl;
|
||
}
|
||
|
||
// ==================== 主函数 ====================
|
||
int main_spc()
|
||
{
|
||
try
|
||
{
|
||
// 运行示例
|
||
RunJsonExample_5_30();
|
||
std::cout << "\n\n";
|
||
RunSpcExample();
|
||
|
||
return 0;
|
||
}
|
||
catch (const std::exception &ex)
|
||
{
|
||
std::cerr << "错误: " << ex.what() << std::endl;
|
||
return 1;
|
||
}
|
||
} |