bereken static method

double bereken({
  1. required List<double> profiel,
  2. required double de,
  3. required double L,
  4. required double xi,
  5. required double tMax,
  6. required double tGr,
  7. required double W,
  8. required int N,
  9. required double dp1,
  10. required bool aanliggend,
})

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;
}