128 lines
4.8 KiB
PHP
128 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Belevo\EnelixEMS;
|
|
|
|
use InvalidArgumentException;
|
|
|
|
/**
|
|
* Verteilt eine gemeinsame Einspeisegrenze auf regelbare PV-Wechselrichter.
|
|
*
|
|
* Netzleistung: positiv Bezug, negativ Einspeisung.
|
|
*/
|
|
final class EinspeiseRegler
|
|
{
|
|
/**
|
|
* @param list<array{ID: string, Nennleistung_W: float|int, Istleistung_W: float|int}> $wechselrichter
|
|
* @param array<string, float|int> $letzteGrenzen
|
|
* @return array{
|
|
* Netzabweichung_W: float,
|
|
* ZielGesamtleistung_W: float,
|
|
* Abregelbedarf_W: float,
|
|
* Grenzen_W: array<string, float>
|
|
* }
|
|
*/
|
|
public static function verteile(
|
|
float $netzleistung,
|
|
float $einspeisegrenze,
|
|
float $toleranz,
|
|
array $wechselrichter,
|
|
array $letzteGrenzen = []
|
|
): array {
|
|
if ($einspeisegrenze < 0.0) {
|
|
throw new InvalidArgumentException('Einspeisegrenze darf nicht negativ sein.');
|
|
}
|
|
if ($toleranz < 0.0) {
|
|
throw new InvalidArgumentException('Einspeisetoleranz darf nicht negativ sein.');
|
|
}
|
|
if ($wechselrichter === []) {
|
|
throw new InvalidArgumentException('Mindestens ein regelbarer Wechselrichter ist erforderlich.');
|
|
}
|
|
|
|
$nennleistungGesamt = 0.0;
|
|
$istleistungGesamt = 0.0;
|
|
$bisherigeGrenzeGesamt = 0.0;
|
|
$normalisiert = [];
|
|
$kennungen = [];
|
|
|
|
foreach ($wechselrichter as $eintrag) {
|
|
$id = $eintrag['ID'] ?? null;
|
|
$nennleistung = $eintrag['Nennleistung_W'] ?? null;
|
|
$istleistung = $eintrag['Istleistung_W'] ?? null;
|
|
if (!is_string($id) || trim($id) === '' || isset($kennungen[$id])) {
|
|
throw new InvalidArgumentException('Wechselrichter-ID fehlt oder ist mehrfach vorhanden.');
|
|
}
|
|
if (!is_numeric($nennleistung) || (float) $nennleistung <= 0.0) {
|
|
throw new InvalidArgumentException('Wechselrichter-Nennleistung muss groesser als 0 sein.');
|
|
}
|
|
if (!is_numeric($istleistung) || (float) $istleistung < 0.0) {
|
|
throw new InvalidArgumentException('Wechselrichter-Istleistung darf nicht negativ sein.');
|
|
}
|
|
|
|
$nennleistung = (float) $nennleistung;
|
|
$istleistung = min((float) $istleistung, $nennleistung);
|
|
$bisherigeGrenze = $letzteGrenzen[$id] ?? $nennleistung;
|
|
if (!is_numeric($bisherigeGrenze)) {
|
|
throw new InvalidArgumentException('Gespeicherte Wechselrichtergrenze ist ungueltig.');
|
|
}
|
|
$bisherigeGrenze = max(0.0, min((float) $bisherigeGrenze, $nennleistung));
|
|
$normalisiert[] = [
|
|
'ID' => $id,
|
|
'Nennleistung_W' => $nennleistung,
|
|
'Istleistung_W' => $istleistung,
|
|
];
|
|
$kennungen[$id] = true;
|
|
$nennleistungGesamt += $nennleistung;
|
|
$istleistungGesamt += $istleistung;
|
|
$bisherigeGrenzeGesamt += $bisherigeGrenze;
|
|
}
|
|
|
|
$netzabweichung = $netzleistung + $einspeisegrenze;
|
|
$zielGesamt = $bisherigeGrenzeGesamt;
|
|
$nachIstleistungVerteilen = false;
|
|
if ($netzabweichung < -$toleranz) {
|
|
$nachIstleistungVerteilen = $istleistungGesamt > 0.0;
|
|
$wirksameAbweichung = $netzabweichung + $toleranz;
|
|
$zielGesamt = min($bisherigeGrenzeGesamt, $istleistungGesamt) + $wirksameAbweichung;
|
|
} elseif ($netzabweichung > $toleranz) {
|
|
$zielGesamt = $bisherigeGrenzeGesamt + $netzabweichung - $toleranz;
|
|
}
|
|
$zielGesamt = max(0.0, min($zielGesamt, $nennleistungGesamt));
|
|
|
|
$grenzen = [];
|
|
foreach ($normalisiert as $eintrag) {
|
|
$anteil = $nachIstleistungVerteilen
|
|
? $eintrag['Istleistung_W'] / $istleistungGesamt
|
|
: $eintrag['Nennleistung_W'] / $nennleistungGesamt;
|
|
$grenzen[$eintrag['ID']] = round(
|
|
min($eintrag['Nennleistung_W'], $zielGesamt * $anteil),
|
|
3
|
|
);
|
|
}
|
|
|
|
return [
|
|
'Netzabweichung_W' => $netzabweichung,
|
|
'ZielGesamtleistung_W' => round($zielGesamt, 3),
|
|
'Abregelbedarf_W' => round(max(0.0, $istleistungGesamt - $zielGesamt), 3),
|
|
'Grenzen_W' => $grenzen,
|
|
];
|
|
}
|
|
|
|
public static function stellwert(float $grenzeW, float $nennleistungW, string $art): float
|
|
{
|
|
if ($nennleistungW <= 0.0 || $grenzeW < 0.0) {
|
|
throw new InvalidArgumentException('Leistungsgrenzen sind ungueltig.');
|
|
}
|
|
$grenzeW = min($grenzeW, $nennleistungW);
|
|
if ($art === 'percent') {
|
|
return round($grenzeW / $nennleistungW * 100.0, 2);
|
|
}
|
|
if ($art === 'watt') {
|
|
return round($grenzeW, 1);
|
|
}
|
|
|
|
throw new InvalidArgumentException('Begrenzungsart muss percent oder watt sein.');
|
|
}
|
|
}
|