bereken static method
Berekent de cyclische factor M.
Parameters:
- profiel : 24 waarden I/Imax per uur (uur 0..23), waarden 0..1
- De : uitwendige diameter kabel/mantel in meters
- L : legdiepte (m)
- xi : thermische grondweerstand (K·m/W)
- tMax : max geleidertemperatuur (°C)
- tGr : grondtemperatuur (°C)
- W : Joule-verliezen per kabel bij Tmax (W/m) = I²·R
- N : aantal kringen in groep (≥1)
- dp1 : hart-op-hart afstand tussen kringen (m); gebruik De voor aanliggende kabels (touching)
- aanliggend : true → T4-formule voor aanliggende legging (touching); false → gespreid (spaced)
Retourneert M ≥ 1.0; bij fouten of N=1 zonder naburige kringen: 1.0.
Implementation
static double bereken({
required List<double> profiel,
required double de,
required double L,
required double xi,
required double tMax,
required double tGr,
required double W,
required int N,
required double dp1,
required bool aanliggend,
}) {
if (profiel.length != 24) return 1.0;
if (N < 1 || de <= 0 || L <= 0 || xi <= 0) return 1.0;
// Yi = (I/Imax)² per uur
final yi = List<double>.generate(24, (h) => profiel[h] * profiel[h]);
// μ = gemiddelde Yi over 24 uur (gelijkwaardige continu-belasting)
final mu = yi.fold(0.0, (s, v) => s + v) / 24;
// ── F: beeldfactor ──────────────────────────────────────────────────────
// Kabels in rechte lijn; afstand kring k naar kring 0 = k × dp1.
// F = ∏ d'k / ∏ dk (k = 1..N-1)
final double F;
if (N <= 1 || dp1 <= 0) {
F = 1.0;
} else {
double prodReal = 1.0;
double prodImg = 1.0;
for (int k = 1; k < N; k++) {
final dk = k * dp1;
prodReal *= dk;
prodImg *= sqrt((2 * L) * (2 * L) + dk * dk);
}
F = prodImg / prodReal;
}
// df: fictieve diameter (equivalent één-kabeldiameter voor de groep)
final double df = (N <= 1 || dp1 <= 0 || F <= 1.0)
? de
: (4 * L) / pow(F, 1.0 / (N - 1)).toDouble();
// δ: thermische diffusiviteit grond (m²/s)
final delta = _diffusiviteit(xi);
// u1 = 2L / de
final u1 = (2 * L) / de;
// T4: externe thermische weerstand (K·m/W)
final t4 = aanliggend ? _t4Aanliggend(u1, xi) : _t4Gespreid(u1, xi);
// ΔT4: bijdrage van de beeldwarmtebron van de groep
final deltaT4 = (N <= 1 || dp1 <= 0 || F <= 1.0)
? 0.0
: (xi * log(F)) / (2 * pi);
// θR(∞) = Tmax − Tgr
final thetaInf = tMax - tGr;
if (thetaInf <= 0 || W <= 0) return 1.0;
final totaalT4 = t4 + deltaT4;
if (totaalT4 <= 0) return 1.0;
// k1 = W · (T4 + ΔT4) / θR(∞)
final k1 = W * totaalT4 / thetaInf;
// θR(i)/θR(∞) voor i = 0..6
// θR(0) = 0 per definitie (beginpunt)
final thetaR = List<double>.filled(7, 0.0);
for (int i = 1; i <= 6; i++) {
final t = 3600.0 * i;
final gamma = _gamma(t, de, df, delta, N, L, F, dp1);
thetaR[i] = 1.0 - k1 + k1 * gamma;
}
// Vind het piekuur (laatste uur met hoogste I/Imax, conform Excel)
final maxI = profiel.reduce(max);
if (maxI <= 0) return 1.0;
int piekUur = 0;
for (int h = 0; h < 24; h++) {
if (profiel[h] >= maxI) piekUur = h;
}
// Y0..Y5: Yi op en voorafgaand aan het piekuur
// Y0 = piekuur zelf, Y1 = uur ervoor, ...
final Y = List<double>.generate(6, (i) => yi[(piekUur - i + 24) % 24]);
// M = 1 / √( Σ(i=0..5) Yi·(θR(i+1) − θR(i)) + μ·(1 − θR(6)) )
double som = 0.0;
for (int i = 0; i < 6; i++) {
som += Y[i] * (thetaR[i + 1] - thetaR[i]);
}
som += mu * (1.0 - thetaR[6]);
if (som <= 0 || som.isNaN || som.isInfinite) return 1.0;
final M = 1.0 / sqrt(som);
return (M.isNaN || M.isInfinite || M < 1.0) ? 1.0 : M;
}