Initial commit
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
/**
|
||||
* Oceny pracy układu pompowego (port func.php: wellEvaluation4_q / _HfQ_new /
|
||||
* _Throt / _LineLoss + setRedYellowLimes / setYellowGreenLimes + sprawność).
|
||||
* Skala m³/h (baza UAT bez ×60 - jak [[use-newest-methods]] / katalog pomp).
|
||||
*
|
||||
* Każda ocena zwraca ['zone' => 'green'|'yellow'|'red', 'text' => string]
|
||||
* albo null gdy nie da się ocenić (brak danych) - jak legacy.
|
||||
*/
|
||||
class WellAssessmentService
|
||||
{
|
||||
private const T_OPT = 'Praca optymalna';
|
||||
private const T_Q_YELLOW = 'Praca na granicy przedziału stosowalności';
|
||||
private const T_Q_RED = 'Praca poza przedziałem stosowalności';
|
||||
private const T_Q_NODATA = 'Brak danych w systemie';
|
||||
private const T_HFQ_YELLOW = 'Charakterystyka pompy ulega odkształcaniu, możliwe przecieki na złączach rurociągu';
|
||||
private const T_HFQ_RED = 'Odkształcona charakterystyka pompy, możliwa utrata szczelności rurociągu';
|
||||
private const T_THROT_YELLOW = 'Wyraźne dławienie w układzie pompowym';
|
||||
private const T_THROT_RED = 'Silne dławienie w układzie pompowym';
|
||||
private const T_LOSS_YELLOW = 'Wyraźne straty liniowe w rurociągu';
|
||||
private const T_LOSS_RED = 'Wysokie straty liniowe w rurociągu';
|
||||
|
||||
/** Przedział Q: porównanie wydajności do nominału. */
|
||||
public function q(float $qn, ?float $q): ?array
|
||||
{
|
||||
if ($q === null || $q <= 0) {
|
||||
return ['zone' => 'red', 'text' => self::T_Q_NODATA];
|
||||
}
|
||||
if (0.7 * $qn <= $q && $q <= 1.22 * $qn) {
|
||||
return ['zone' => 'green', 'text' => self::T_OPT];
|
||||
}
|
||||
if ((0.55 * $qn <= $q && $q < 0.7 * $qn) || (1.22 * $qn < $q && $q <= 1.35 * $qn)) {
|
||||
return ['zone' => 'yellow', 'text' => self::T_Q_YELLOW];
|
||||
}
|
||||
|
||||
return ['zone' => 'red', 'text' => self::T_Q_RED];
|
||||
}
|
||||
|
||||
/** H=f(Q): odchyłka wysokości podnoszenia ze stacji prób (HPS) od (Pp-Hh). */
|
||||
public function hfq(?float $hps, ?float $pp, ?float $hh): ?array
|
||||
{
|
||||
if (! $pp || $hps === null || $hps == 0.0) {
|
||||
return null;
|
||||
}
|
||||
$dev = ($hps - ($pp - $hh)) / $hps;
|
||||
if ($dev >= -0.05 && $dev <= 0.05) {
|
||||
return ['zone' => 'green', 'text' => self::T_OPT];
|
||||
}
|
||||
if (($dev < -0.05 && $dev >= -0.07) || ($dev > 0.05 && $dev <= 0.07)) {
|
||||
return ['zone' => 'yellow', 'text' => self::T_HFQ_YELLOW];
|
||||
}
|
||||
|
||||
return ['zone' => 'red', 'text' => self::T_HFQ_RED];
|
||||
}
|
||||
|
||||
/** Dławienie: spadek P1-P2 na zasuwie dławiącej, progi wg zwierciadła HD. */
|
||||
public function throttling(?float $hd, ?float $p1, ?float $p2): ?array
|
||||
{
|
||||
if ($hd === null || $p1 === null || $p2 === null) {
|
||||
return null;
|
||||
}
|
||||
$hsa = $p1 - $p2;
|
||||
$green = $this->pick($hd, [[50, 6], [100, 8], [200, 10], [350, 13], [450, 16]]);
|
||||
$yellow = $this->pick($hd, [[50, 15], [100, 20], [200, 28], [350, 35], [450, 39]]);
|
||||
if ($green === null) {
|
||||
return null; // HD poza zakresem - brak oceny (jak legacy)
|
||||
}
|
||||
if ($hsa <= $green) {
|
||||
return ['zone' => 'green', 'text' => self::T_OPT];
|
||||
}
|
||||
if ($hsa <= $yellow) {
|
||||
return ['zone' => 'yellow', 'text' => self::T_THROT_YELLOW];
|
||||
}
|
||||
|
||||
return ['zone' => 'red', 'text' => self::T_THROT_RED];
|
||||
}
|
||||
|
||||
/** Straty liniowe: HSL = Pp - Lp - P1, progi wg średnicy rurociągu DR i Lp. */
|
||||
public function lineLoss(?float $p1, ?float $pp, ?float $lp, ?float $dr): ?array
|
||||
{
|
||||
if (! $pp || $p1 === null || $lp === null || $dr === null) {
|
||||
return null;
|
||||
}
|
||||
$hsl = $pp - $lp - $p1;
|
||||
|
||||
// Progi [green, yellow] zależne od DR. Każdy próg to pick() po Lp.
|
||||
if ($dr > 0.04 && $dr < 0.145) {
|
||||
$green = $this->pick($lp, [[50, 3.5], [100, 6.4], [200, 10], [300, 18], [450, 25]]);
|
||||
$yellow = $this->pick($lp, [[50, 4.9], [100, 9.5], [200, 16], [300, 24], [450, 35]]);
|
||||
// legacy: powyżej "yellow" -> wciąż YELLOW + wymóg weryfikacji p1/p2
|
||||
$overText = self::T_LOSS_RED.'. Wymagana weryfikacja p1 i p2';
|
||||
$overZone = 'yellow';
|
||||
} elseif ($dr > 0.145 && $dr <= 0.160) {
|
||||
$green = $this->pick($lp, [[50, 2.3], [100, 4.3], [200, 8.6], [300, 12], [450, 21]]);
|
||||
$yellow = $this->pick($lp, [[50, 4.5], [100, 7.2], [200, 14], [300, 18], [450, 27]]);
|
||||
$overText = self::T_LOSS_RED;
|
||||
$overZone = 'red';
|
||||
} elseif ($dr > 0.195 && $dr <= 0.215) {
|
||||
$green = $this->pick($lp, [[50, 2], [100, 3], [200, 6.5], [300, 9.5], [450, 12]]);
|
||||
$yellow = $this->pick($lp, [[50, 3], [100, 5.5], [200, 11], [300, 15], [450, 18]]);
|
||||
$overText = self::T_LOSS_RED;
|
||||
$overZone = 'red';
|
||||
} else {
|
||||
return null; // DR poza obsługiwanymi zakresami - brak oceny (jak legacy)
|
||||
}
|
||||
|
||||
if ($green === null) {
|
||||
return null;
|
||||
}
|
||||
if ($hsl <= $green) {
|
||||
return ['zone' => 'green', 'text' => self::T_OPT];
|
||||
}
|
||||
if ($hsl <= $yellow) {
|
||||
return ['zone' => 'yellow', 'text' => self::T_LOSS_YELLOW];
|
||||
}
|
||||
|
||||
return ['zone' => $overZone, 'text' => $overText];
|
||||
}
|
||||
|
||||
/** Granica czerwony/żółty energochłonności w funkcji Q (próg sprawności). */
|
||||
public function redYellowLimit(float $q): float
|
||||
{
|
||||
return match (true) {
|
||||
$q > 0 && $q <= 25 => 0.00210526315789473 * $q + 0.267368421052632,
|
||||
$q > 25 && $q <= 40 => 0.00133333333333334 * $q + 0.286666666666667,
|
||||
$q > 40 && $q <= 60 => 0.000749999999999997 * $q + 0.31,
|
||||
$q > 60 && $q <= 260 => 0.000225000000000001 * $q + 0.3415,
|
||||
$q > 260 && $q <= 500 => 4.16666666666662e-5 * $q + 0.389166666666667,
|
||||
$q > 500 => 1.99999999999997e-5 * $q + 0.4,
|
||||
default => 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
/** Granica żółty/zielony energochłonności w funkcji Q. */
|
||||
public function yellowGreenLimit(float $q): float
|
||||
{
|
||||
return match (true) {
|
||||
$q > 0 && $q <= 8 => 0.00999999999999998 * $q + 0.3,
|
||||
$q > 8 && $q <= 19 => 0.00545454545454544 * $q + 0.336363636363637,
|
||||
$q > 19 && $q <= 38 => 0.00210526315789474 * $q + 0.4,
|
||||
$q > 38 && $q <= 60 => 0.000454545454545451 * $q + 0.462727272727273,
|
||||
$q > 60 && $q <= 500 => 0.000170454545454545 * $q + 0.479772727272727,
|
||||
$q > 500 => 9.99999999999959e-6 * $q + 0.560000000000001,
|
||||
default => 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
/** Sprawność układu η = Q·(HD+P2) / (367·Pe). Pe<=0 traktujemy jak 1 (jak legacy). */
|
||||
public function efficiency(?float $q, ?float $hd, ?float $p2, ?float $pe): ?float
|
||||
{
|
||||
if ($q === null || $hd === null || $p2 === null) {
|
||||
return null;
|
||||
}
|
||||
$pe = ($pe === null || $pe <= 0) ? 1.0 : $pe;
|
||||
|
||||
return ($q * ($hd + $p2)) / (367 * $pe);
|
||||
}
|
||||
|
||||
/** Strefa energochłonności: η>=yg zielona, >=ry żółta, inaczej czerwona. */
|
||||
public function energyZone(float $eta, float $ry, float $yg): string
|
||||
{
|
||||
if ($eta >= $yg) {
|
||||
return 'green';
|
||||
}
|
||||
|
||||
return $eta >= $ry ? 'yellow' : 'red';
|
||||
}
|
||||
|
||||
/** Wybór progu po przedziałach: [[górna granica wykluczna, wartość], ...]. */
|
||||
private function pick(float $x, array $bands): ?float
|
||||
{
|
||||
foreach ($bands as [$limit, $value]) {
|
||||
if ($x < $limit) {
|
||||
return (float) $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user