Regelleistung: FCR, aFRR, mFRR

← Learning Hub Lektion 6 · Batterieoptimierungs-Kurs · Geschätzte Dauer: 25 Minuten

Batterien machen nicht nur Preisarbitrage. Sie können auch Netzregelleistung bereitstellen — und die Erlöse sind oft höher und stabiler als reine Spot-Arbitrage. Diese Lektion behandelt die drei wichtigsten Frequenzregelungsprodukte und wie man sie in den Optimierer integriert.

Was ist Regelleistung?

Die Netzfrequenz muss bei 50,000 Hz bleiben (in Europa). Wenn Erzeugung ≠ Verbrauch, weicht die Frequenz ab. ÜNBs (Übertragungsnetzbetreiber) beschaffen Reservekapazität von Anlagen wie Batterien um das Gleichgewicht wiederherzustellen. Du wirst dafür bezahlt, Kapazität bereitzuhalten — selbst wenn du nie tatsächlich Energie lieferst.

Die drei Produkte

FCR — Primärregelleistung (Frequency Containment Reserve)

aFRR — Sekundärregelleistung (Automatic Frequency Restoration Reserve)

mFRR — Minutenreserve (Manual Frequency Restoration Reserve)

Batterie-Sweet-Spot: FCR. Batterien eignen sich hervorragend für FCR, weil sie in Millisekunden reagieren (weit schneller als die 30-Sekunden-Anforderung), die Energiemengen klein sind (symmetrisch um Null), und die Kapazitätszahlungen hoch sind relativ zur reservierten Leistung. Viele Batterien erzielen 60–80% ihres Erlöses allein aus FCR.

FCR und die Batterie: die SoC-Herausforderung

Um symmetrische FCR (±X MW) bereitzustellen, muss deine Batterie jederzeit sowohl erhöhen als auch verringern können. Das bedeutet, den SoC nahe 50% zu halten — wenn sie leer ist, kann sie nicht entladen; wenn voll, nicht laden.

# FCR-Reservierung: ±5 MW für einen 4-Stunden-Block
# Batterie muss genug Spielraum in beide Richtungen halten

fcr_leistung = 5.0  # MW für FCR reserviert
fcr_dauer = 0.25    # Stunden (15 Min. Halteanforderung)
fcr_energie = fcr_leistung * fcr_dauer  # 1,25 MWh Spielraum je Richtung

# SoC muss während FCR-Bereitstellung in diesen Grenzen bleiben:
# SoC ≥ SoC_min + fcr_energie  (kann noch entladen wenn abgerufen)
# SoC ≤ SoC_max - fcr_energie  (kann noch laden wenn abgerufen)

Co-Optimierung: Arbitrage + FCR

Die Schlüsselerkenntnis: Du kannst FCR bereitstellen und gleichzeitig Arbitrage betreiben, solange du die Kapazitätsreservierung respektierst. Der Optimierer entscheidet, wie er die Batterieleistung zwischen den Märkten aufteilt:

"""
co_optimierung.py — Gemeinsame Day-Ahead-Arbitrage + FCR-Gebot
"""
import pyomo.environ as pyo
import numpy as np

T = 24
preise = [28, 25, 22, 20, 19, 21, 35, 55,
          62, 58, 52, 48, 45, 44, 47, 53,
          68, 85, 92, 78, 60, 45, 35, 30]

# FCR-Auktionsergebnisse: Kapazitätspreis pro 4-Stunden-Block (€/MW/h)
# Blöcke: 0-3, 4-7, 8-11, 12-15, 16-19, 20-23
fcr_kapazitaetspreise = [3.5, 4.0, 5.5, 6.0, 12.0, 4.5]  # €/MW/h

P_max = 10.0
E_max = 20.0
eta = 0.90
eta_sqrt = np.sqrt(eta)
soc_init = 10.0
SoC_min = 0.1 * E_max
SoC_max = 0.9 * E_max
deg_kosten = 5.0
fcr_dauer = 0.25  # 15-Min. Halten

model = pyo.ConcreteModel()
model.T = pyo.RangeSet(0, T - 1)
model.B = pyo.RangeSet(0, 5)  # 6 FCR-Blöcke

# Entscheidungsvariablen
model.p_laden = pyo.Var(model.T, bounds=(0, None))
model.p_entladen = pyo.Var(model.T, bounds=(0, None))
model.soc = pyo.Var(model.T, bounds=(SoC_min, SoC_max))
model.y = pyo.Var(model.T, within=pyo.Binary)
model.fcr = pyo.Var(model.B, bounds=(0, P_max))  # MW für FCR pro Block

# Stunden zu FCR-Blöcken zuordnen
def block_von(t):
    return t // 4

# Leistungsgrenzen: Arbitrage-Leistung + FCR-Reservierung ≤ P_max
def leistungsgrenze_laden(m, t):
    b = block_von(t)
    return m.p_laden[t] + m.fcr[b] <= P_max
def leistungsgrenze_entladen(m, t):
    b = block_von(t)
    return m.p_entladen[t] + m.fcr[b] <= P_max
model.lg_l = pyo.Constraint(model.T, rule=leistungsgrenze_laden)
model.lg_e = pyo.Constraint(model.T, rule=leistungsgrenze_entladen)

# SoC muss Spielraum für FCR-Aktivierung haben
def soc_fcr_unten(m, t):
    b = block_von(t)
    return m.soc[t] >= SoC_min + m.fcr[b] * fcr_dauer
def soc_fcr_oben(m, t):
    b = block_von(t)
    return m.soc[t] <= SoC_max - m.fcr[b] * fcr_dauer
model.soc_fcr_u = pyo.Constraint(model.T, rule=soc_fcr_unten)
model.soc_fcr_o = pyo.Constraint(model.T, rule=soc_fcr_oben)

# SoC-Bilanz
def soc_regel(m, t):
    vorher = soc_init if t == 0 else m.soc[t-1]
    return m.soc[t] == vorher + eta_sqrt * m.p_laden[t] - m.p_entladen[t] / eta_sqrt
model.soc_bil = pyo.Constraint(model.T, rule=soc_regel)

# Kein gleichzeitiges Laden/Entladen
def kl(m, t): return m.p_laden[t] <= P_max * (1 - m.y[t])
def ke(m, t): return m.p_entladen[t] <= P_max * m.y[t]
model.kl = pyo.Constraint(model.T, rule=kl)
model.ke = pyo.Constraint(model.T, rule=ke)

# Zielfunktion: Arbitrage-Erlös + FCR-Kapazitätserlös - Degradation
def ziel_regel(m):
    arb_erloes = sum(preise[t] * (m.p_entladen[t] - m.p_laden[t]) for t in m.T)
    fcr_erloes = sum(m.fcr[b] * fcr_kapazitaetspreise[b] * 4 for b in m.B)
    degradation = sum(deg_kosten * (m.p_laden[t] + m.p_entladen[t]) for t in m.T)
    return arb_erloes + fcr_erloes - degradation
model.ziel = pyo.Objective(rule=ziel_regel, sense=pyo.maximize)

# Lösen
solver = pyo.SolverFactory('highs')
ergebnis = solver.solve(model, tee=False)

print(f"Gesamterlös: €{pyo.value(model.ziel):.2f}")
print(f"  Arbitrage: €{sum(preise[t] * (pyo.value(model.p_entladen[t]) - pyo.value(model.p_laden[t])) for t in range(T)):.2f}")
print(f"  FCR:       €{sum(pyo.value(model.fcr[b]) * fcr_kapazitaetspreise[b] * 4 for b in range(6)):.2f}")
print(f"\nFCR-Reservierungen pro Block:")
for b in range(6):
    print(f"  Block {b} (Stunden {b*4}-{b*4+3}): {pyo.value(model.fcr[b]):.1f} MW")

Der Trade-off: FCR vs. Arbitrage

Leistung für FCR zu reservieren reduziert die für Arbitrage verfügbare Leistung. Der Optimierer balanciert:

Praxiserkenntnis: In Deutschland (2023–2025) lagen FCR-Preise durchschnittlich bei €5–15/MW/h. Eine 10 MW Batterie vollständig in FCR verdient €50–150/h = €1.200–3.600/Tag allein aus Kapazität. Vergleiche mit reinen Arbitrage-Erlösen von €500–1.500/Tag. FCR gewinnt oft, besonders an volatilitätsarmen Tagen.

Überprüfe dein Verständnis

Eine 10 MW Batterie reserviert 6 MW für FCR. Wie viel Leistung steht für Day-Ahead-Arbitrage zur Verfügung?

Warum fügt der Optimierer SoC-Spielraum-Nebenbedingungen hinzu (SoC ≥ SoC_min + fcr_energie) während der FCR-Bereitstellung?

An einem Tag mit sehr niedrigen Day-Ahead-Preisspreads aber hohen FCR-Kapazitätspreisen, was sollte der Optimierer tun?

📖 Empfohlene Lektüre

ENTSO-E — Electricity Balancing — der europäische Rahmen für Regelleistungsmärkte (FCR, aFRR, mFRR). Lies den „Implementation"-Abschnitt für PICASSO (aFRR) und MARI (mFRR) Plattformregeln.

💬 Fragen? Die Wechselwirkung zwischen FCR und Arbitrage ist subtil — frag nach Präqualifikationsanforderungen, Pooling-Regeln, oder wie ÜNB-spezifische Regeln (z.B. Deutschland vs. Niederlande) die Formulierung beeinflussen.

Rechtliches: Impressum