93 lines
2.8 KiB
PHP
93 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace Modules\QualityManagement\Services;
|
|
|
|
use Modules\QualityManagement\Models\SpcMeasurement;
|
|
|
|
class SpcAnalysisService
|
|
{
|
|
public function recordMeasurement(int $businessId, array $data): SpcMeasurement
|
|
{
|
|
$inControl = $this->isInControl(
|
|
(float) $data['measured_value'],
|
|
isset($data['usl']) ? (float) $data['usl'] : null,
|
|
isset($data['lsl']) ? (float) $data['lsl'] : null
|
|
);
|
|
|
|
return SpcMeasurement::create(array_merge($data, [
|
|
'business_id' => $businessId,
|
|
'measured_at' => $data['measured_at'] ?? now(),
|
|
'in_control' => $inControl,
|
|
'recorded_by' => $data['recorded_by'] ?? auth()->id(),
|
|
]));
|
|
}
|
|
|
|
public function isInControl(float $value, ?float $usl, ?float $lsl): bool
|
|
{
|
|
if ($usl !== null && $value > $usl) {
|
|
return false;
|
|
}
|
|
if ($lsl !== null && $value < $lsl) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function characteristicSummary(int $businessId, string $characteristic, int $days = 30): array
|
|
{
|
|
$measurements = SpcMeasurement::forBusiness($businessId)
|
|
->where('characteristic_name', $characteristic)
|
|
->where('measured_at', '>=', now()->subDays($days))
|
|
->orderBy('measured_at')
|
|
->get();
|
|
|
|
if ($measurements->isEmpty()) {
|
|
return ['count' => 0, 'mean' => 0, 'min' => 0, 'max' => 0, 'out_of_control' => 0];
|
|
}
|
|
|
|
$values = $measurements->pluck('measured_value')->map(fn ($v) => (float) $v);
|
|
|
|
return [
|
|
'count' => $measurements->count(),
|
|
'mean' => round($values->avg(), 4),
|
|
'min' => round($values->min(), 4),
|
|
'max' => round($values->max(), 4),
|
|
'out_of_control' => $measurements->where('in_control', false)->count(),
|
|
'cpk_estimate' => $this->estimateCpk($values, $measurements->first()),
|
|
];
|
|
}
|
|
|
|
protected function estimateCpk($values, SpcMeasurement $sample): ?float
|
|
{
|
|
$usl = $sample->usl;
|
|
$lsl = $sample->lsl;
|
|
if ($usl === null || $lsl === null || $values->count() < 2) {
|
|
return null;
|
|
}
|
|
|
|
$mean = $values->avg();
|
|
$std = $this->stdDev($values->all());
|
|
if ($std <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$cpu = ($usl - $mean) / (3 * $std);
|
|
$cpl = ($mean - $lsl) / (3 * $std);
|
|
|
|
return round(min($cpu, $cpl), 3);
|
|
}
|
|
|
|
protected function stdDev(array $values): float
|
|
{
|
|
$n = count($values);
|
|
if ($n < 2) {
|
|
return 0;
|
|
}
|
|
$mean = array_sum($values) / $n;
|
|
$variance = array_sum(array_map(fn ($v) => ($v - $mean) ** 2, $values)) / ($n - 1);
|
|
|
|
return sqrt($variance);
|
|
}
|
|
}
|