459 lines
12 KiB
Markdown
459 lines
12 KiB
Markdown
# SOC-Kalibrierung & Drift-Management
|
||
|
||
## Problem: SOC ist berechnet, nicht gemessen
|
||
|
||
### Wie SOC funktioniert
|
||
|
||
Der State of Charge (SOC) wird vom Battery Management System (BMS) **berechnet**, nicht direkt gemessen:
|
||
|
||
**Berechnungsmethoden:**
|
||
1. **Coulomb Counting** (Hauptmethode)
|
||
- Integriert Strom über Zeit: ∫ I(t) dt
|
||
- Geladen mit 5A für 1h = +5Ah
|
||
- Entladen mit 3A für 1h = -3Ah
|
||
- Netto: +2Ah → SOC steigt um ~2%
|
||
|
||
2. **Spannungsbasiert** (Open Circuit Voltage)
|
||
- Zellspannung korreliert mit SOC
|
||
- 4.2V/Zelle ≈ 100% SOC
|
||
- 3.2V/Zelle ≈ 0% SOC (Minimum)
|
||
|
||
3. **Kalman-Filter / State Estimation**
|
||
- Kombiniert beide Methoden
|
||
- Berücksichtigt Temperatur, Alterung, Laderate
|
||
|
||
### Warum SOC abweicht (Drift)
|
||
|
||
**Hauptursachen:**
|
||
|
||
| Ursache | Effekt | Beispiel |
|
||
|---------|--------|----------|
|
||
| **Keine vollen Zyklen** | BMS verliert Referenzpunkte | Immer 30-92%, nie 20-100% |
|
||
| **Coulomb Counting Fehler** | Akkumuliert über Zeit | 0.1% Fehler/Tag = 3% nach 1 Monat |
|
||
| **Temperatur** | Kapazität ändert sich | 10kWh bei 20°C, 9.5kWh bei 5°C |
|
||
| **Alterung** | Tatsächliche Kapazität sinkt | 10kWh neu, 9.2kWh nach 3 Jahren |
|
||
| **Strommessung** | Sensorfehler (±1-2%) | 5.0A gemessen, 5.1A real |
|
||
| **Selbstentladung** | Nicht im SOC berücksichtigt | 1-2%/Monat |
|
||
|
||
**Beispiel SOC-Drift:**
|
||
```
|
||
Tag 1: BMS kalibriert, SOC = 100% (korrekt)
|
||
Tag 5: SOC = 95% (BMS sagt), real = 96% (+1% Drift)
|
||
Tag 10: SOC = 88% (BMS sagt), real = 91% (+3% Drift)
|
||
Tag 30: SOC = 65% (BMS sagt), real = 72% (+7% Drift)
|
||
→ Nach Vollladung: Kalibriert sich neu
|
||
```
|
||
|
||
## GoodWe-spezifische Einstellungen
|
||
|
||
### Hardware-seitiges 20% Minimum
|
||
|
||
Du hast im GoodWe eingestellt:
|
||
- **Minimum SOC: 20%**
|
||
- **Entladung stoppt bei 20%**
|
||
- **Freigabe nur bei Netzausfall**
|
||
|
||
**Bedeutung:**
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 100% ← Hardware-Maximum │
|
||
│ ↕ │
|
||
│ 80% ← Nutzbare Kapazität │
|
||
│ ↕ │
|
||
│ 20% ← Hardware-Minimum │ ← GoodWe stoppt hier!
|
||
│ ↓ │
|
||
│ 0% ← Nur bei Netzausfall │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
**Effektive Kapazität:**
|
||
- Physisch: 10 kWh (100%)
|
||
- Nutzbar: 8 kWh (80% von 20-100%)
|
||
- Reserve für Netzausfall: 2 kWh (20%)
|
||
|
||
### Integration mit unserem Optimizer
|
||
|
||
**Unser Optimizer:**
|
||
- `min_soc: 20%` (redundant, aber konsistent)
|
||
- `max_soc: 100%`
|
||
- `reserve_capacity: 2 kWh` (entspricht 20%)
|
||
|
||
**Das passt perfekt zusammen!** ✅
|
||
|
||
## Auswirkungen auf die Optimierung
|
||
|
||
### Problem 1: Ungenaue Planung
|
||
|
||
**Szenario:**
|
||
```
|
||
14:05 Uhr (Planung):
|
||
BMS zeigt: SOC 30%
|
||
Real: SOC 35% (5% Drift)
|
||
|
||
Optimizer plant: (100 - 30) × 10kWh - 2kWh = 6.8 kWh
|
||
Tatsächlich braucht: (100 - 35) × 10kWh - 2kWh = 6.3 kWh
|
||
|
||
→ Plant 500Wh zu viel
|
||
→ Nutzt eventuell 1 Stunde mehr als nötig
|
||
→ Könnte teurere Stunde nutzen
|
||
```
|
||
|
||
### Problem 2: Keine Kalibrierung durch Teilzyklen
|
||
|
||
**Typischer Tagesablauf (OHNE Kalibrierung):**
|
||
```
|
||
07:00 → SOC 92% (nicht 100% erreicht)
|
||
↓ PV-Produktion überschuss lädt minimal
|
||
09:00 → SOC 95% (immer noch nicht 100%)
|
||
↓ PV reicht für Eigenverbrauch
|
||
12:00 → SOC 93% (leicht entladen)
|
||
↓ Eigenverbrauch übersteigt PV
|
||
18:00 → SOC 65% (Eigenverbrauch ohne PV)
|
||
↓ Weiterer Eigenverbrauch
|
||
22:00 → SOC 45% (vor Laden)
|
||
↓ Günstige Stunden: Laden
|
||
23:00 → SOC 60% (teilweise geladen)
|
||
00:00 → SOC 75% (weiter geladen)
|
||
↓ Auto-Modus
|
||
07:00 → SOC 92% (nicht 100%)
|
||
|
||
→ Kein voller Zyklus!
|
||
→ BMS hat keine Referenzpunkte
|
||
→ SOC driftet weiter
|
||
```
|
||
|
||
## Lösungen
|
||
|
||
### Lösung 1: Höherer Sicherheitspuffer (Sofort umsetzbar)
|
||
|
||
**Empfehlung: 25-30% statt 20%**
|
||
|
||
```yaml
|
||
input_number:
|
||
battery_optimizer_safety_buffer:
|
||
initial: 30 # Statt 20
|
||
```
|
||
|
||
**Begründung:**
|
||
- SOC kann um 5-10% abweichen
|
||
- Puffer kompensiert Drift
|
||
- Hardware stoppt sowieso bei 100%
|
||
- Lieber eine Stunde mehr laden als 8% zu wenig
|
||
|
||
**Berechnung:**
|
||
```
|
||
Ohne Drift:
|
||
6.8 kWh × 1.20 = 8.16 kWh (20% Puffer)
|
||
|
||
Mit 5% Drift:
|
||
6.8 kWh × 1.30 = 8.84 kWh (30% Puffer)
|
||
→ Kompensiert Drift + normale Schwankungen
|
||
```
|
||
|
||
### Lösung 2: Monatliche Kalibrierung (Empfohlen)
|
||
|
||
**Automatischer Kalibrierungs-Zyklus:**
|
||
|
||
**Phase 1: Entladung** (natürlich durch Eigenverbrauch)
|
||
- Ziel: SOC auf ~20% bringen
|
||
- Dauer: Normalerweise 1-2 Tage
|
||
- Optimizer pausiert (Manual Override)
|
||
|
||
**Phase 2: Vollladung** (erzwungen, unabhängig von Preisen)
|
||
- Ziel: SOC auf 100% laden
|
||
- Dauer: 2-5 Stunden (je nach Start-SOC)
|
||
- Volle Ladeleistung (5kW)
|
||
|
||
**Phase 3: Kalibrierung** (automatisch durch BMS)
|
||
- BMS erkennt: Zellen bei 4.2V = 100% SOC
|
||
- Vergleicht mit berechnetem SOC
|
||
- Korrigiert Coulomb Counter
|
||
- Passt Kapazitäts-Schätzung an
|
||
|
||
**Ergebnis:**
|
||
- ✅ SOC wieder präzise
|
||
- ✅ BMS hat Referenzpunkte
|
||
- ✅ Tatsächliche Kapazität bekannt
|
||
- ✅ Drift zurückgesetzt
|
||
|
||
**Häufigkeit:**
|
||
- **Minimum**: Alle 3 Monate
|
||
- **Empfohlen**: Jeden Monat
|
||
- **Bei Bedarf**: Wenn SOC merklich abweicht
|
||
|
||
**Installation:** Siehe `battery_calibration_automation.yaml`
|
||
|
||
### Lösung 3: SOC-Monitoring (Automatisch)
|
||
|
||
**Erkenne SOC-Drift automatisch:**
|
||
|
||
```yaml
|
||
# Automation: SOC-Drift-Detektor
|
||
alias: "Batterie: SOC-Drift Warnung"
|
||
description: "Warnt wenn SOC wahrscheinlich driftet"
|
||
trigger:
|
||
# Wenn Batterie "voll" ist aber nicht 100%
|
||
- platform: state
|
||
entity_id: input_boolean.goodwe_manual_control
|
||
from: "on"
|
||
to: "off"
|
||
for:
|
||
minutes: 30
|
||
condition:
|
||
# SOC ist unter 98%
|
||
- condition: numeric_state
|
||
entity_id: sensor.esssoc
|
||
below: 98
|
||
|
||
# Aber Laden lief mehr als 2 Stunden
|
||
- condition: template
|
||
value_template: >
|
||
{% set duration = as_timestamp(now()) - as_timestamp(trigger.from_state.last_changed) %}
|
||
{{ duration > 7200 }}
|
||
action:
|
||
- service: notify.persistent_notification
|
||
data:
|
||
title: "SOC-Drift erkannt?"
|
||
message: >
|
||
Laden lief {{ ((as_timestamp(now()) - as_timestamp(trigger.from_state.last_changed)) / 3600) | round(1) }}h,
|
||
aber SOC ist nur {{ states('sensor.esssoc') }}%.
|
||
Eventuell SOC-Drift? Kalibrierung empfohlen.
|
||
```
|
||
|
||
## Installation der Kalibrierung
|
||
|
||
### Schritt 1: Input Helper erstellen
|
||
|
||
```yaml
|
||
# In configuration.yaml
|
||
input_boolean:
|
||
battery_calibration_active:
|
||
name: "Batterie Kalibrierung aktiv"
|
||
icon: mdi:battery-sync
|
||
initial: off
|
||
```
|
||
|
||
**Via UI:**
|
||
1. Einstellungen → Geräte & Dienste → Helfer
|
||
2. "Helfer hinzufügen" → "Toggle/Schalter"
|
||
3. Name: `Batterie Kalibrierung aktiv`
|
||
4. Entity ID: `input_boolean.battery_calibration_active`
|
||
5. Icon: `mdi:battery-sync`
|
||
|
||
### Schritt 2: Automations installieren
|
||
|
||
**Kopiere die 4 Automations aus** `battery_calibration_automation.yaml`:
|
||
1. Kalibrierung starten (jeden 1. des Monats)
|
||
2. Kalibrierungs-Laden (stündlich während aktiv)
|
||
3. Kalibrierung beenden (nach 24h oder bei 100%)
|
||
4. Notfall-Abbruch (bei kritisch niedrigem SOC)
|
||
|
||
**Via UI oder YAML:**
|
||
- UI: Einstellungen → Automationen & Szenen → Neue Automation → YAML-Modus
|
||
- YAML: In `automations.yaml` einfügen
|
||
|
||
### Schritt 3: Testen
|
||
|
||
**Manuelle Kalibrierung triggern:**
|
||
|
||
```yaml
|
||
# Developer Tools → Services
|
||
service: input_boolean.turn_on
|
||
target:
|
||
entity_id: input_boolean.battery_calibration_active
|
||
```
|
||
|
||
**Beobachte:**
|
||
1. Manual Override wird aktiviert
|
||
2. Batterie lädt auf 100%
|
||
3. Nach 24h oder bei 100%: Automatische Deaktivierung
|
||
|
||
## Best Practices
|
||
|
||
### Wann Kalibrierung durchführen?
|
||
|
||
**Automatisch:**
|
||
- ✅ Jeden Monat (1. des Monats)
|
||
- ✅ Nach Software-Updates
|
||
- ✅ Nach längeren Ausfällen
|
||
|
||
**Manuell:**
|
||
- ⚠️ Wenn SOC merklich abweicht
|
||
- ⚠️ Wenn Batterie nie 100% erreicht
|
||
- ⚠️ Wenn Kapazität sich verändert anfühlt
|
||
|
||
**Nicht nötig:**
|
||
- ❌ Wöchentlich (zu häufig)
|
||
- ❌ Wenn SOC präzise ist
|
||
- ❌ Bei normalen Teilzyklen
|
||
|
||
### Optimale Kalibrierungs-Bedingungen
|
||
|
||
| Faktor | Optimal | Warum |
|
||
|--------|---------|-------|
|
||
| **Temperatur** | 15-25°C | Beste Messgenauigkeit |
|
||
| **Laderate** | 0.5C (5kW bei 10kWh) | Minimiert Fehler |
|
||
| **Entladerate** | Natürlich (Eigenverbrauch) | Realistisch |
|
||
| **Dauer** | Mindestens 6h | BMS braucht Zeit |
|
||
|
||
### Was nach Kalibrierung zu erwarten ist
|
||
|
||
**Sofort:**
|
||
- ✅ SOC springt eventuell (z.B. 92% → 97%)
|
||
- ✅ BMS hat neue Referenzpunkte
|
||
- ✅ Kapazitäts-Schätzung aktualisiert
|
||
|
||
**In den nächsten Tagen:**
|
||
- ✅ Präziserer SOC
|
||
- ✅ Bessere Ladeplanung
|
||
- ✅ Weniger "überraschende" SOC-Werte
|
||
|
||
**Langfristig:**
|
||
- ✅ Verlangsamter Drift
|
||
- ✅ Längere Batterielebensdauer
|
||
- ✅ Genauere Kapazitäts-Prognosen
|
||
|
||
## Erweiterte Lösungen
|
||
|
||
### Adaptive Pufferberechnung
|
||
|
||
**Konzept:** Puffer basierend auf historischer Drift anpassen
|
||
|
||
```python
|
||
# Pseudo-Code für zukünftige Version
|
||
historical_drift = learn_from_last_30_days()
|
||
# Beispiel: SOC war durchschnittlich 5% höher als geplant
|
||
|
||
adaptive_buffer = base_buffer + historical_drift
|
||
# 20% + 5% = 25%
|
||
|
||
# Plane mit adaptivem Puffer
|
||
capacity_with_buffer = capacity × (1 + adaptive_buffer)
|
||
```
|
||
|
||
### SOC-Validierung über Spannung
|
||
|
||
**Konzept:** Vergleiche BMS-SOC mit Zellspannung
|
||
|
||
```yaml
|
||
# Sensor für SOC-Validierung
|
||
sensor:
|
||
- platform: template
|
||
sensors:
|
||
battery_soc_validated:
|
||
friendly_name: "SOC (validiert)"
|
||
unit_of_measurement: "%"
|
||
value_template: >
|
||
{% set soc = states('sensor.esssoc') | float %}
|
||
{% set voltage = states('sensor.battery_voltage') | float %}
|
||
|
||
{# Validiere SOC gegen Spannung #}
|
||
{% if voltage > 54.0 and soc < 95 %}
|
||
{{ 'SOC zu niedrig (Voltage hoch)' }}
|
||
{% elif voltage < 50.0 and soc > 30 %}
|
||
{{ 'SOC zu hoch (Voltage niedrig)' }}
|
||
{% else %}
|
||
{{ soc }}
|
||
{% endif %}
|
||
```
|
||
|
||
### Batterie-Gesundheits-Tracking
|
||
|
||
**Konzept:** Überwache tatsächliche Kapazität über Zeit
|
||
|
||
```yaml
|
||
# Berechne echte Kapazität aus Vollzyklus
|
||
sensor:
|
||
- platform: template
|
||
sensors:
|
||
battery_true_capacity:
|
||
friendly_name: "Wahre Batterie-Kapazität"
|
||
unit_of_measurement: "kWh"
|
||
value_template: >
|
||
{% if is_state('input_boolean.battery_calibration_active', 'on') %}
|
||
{# Nach Vollzyklus: Berechne Energie geladen #}
|
||
{% set energy = states('sensor.battery_charged_energy') | float %}
|
||
{% set soc_diff = 80 %} {# 20% → 100% #}
|
||
{{ (energy / (soc_diff / 100)) | round(2) }}
|
||
{% else %}
|
||
{{ states('input_number.battery_capacity_kwh') }}
|
||
{% endif %}
|
||
```
|
||
|
||
## Zusammenfassung
|
||
|
||
### Empfohlene Maßnahmen
|
||
|
||
| Priorität | Maßnahme | Aufwand | Nutzen |
|
||
|-----------|----------|---------|--------|
|
||
| 🔴 **HOCH** | Puffer auf 30% erhöhen | 1 min | Sofort bessere Ergebnisse |
|
||
| 🟡 **MITTEL** | Monatliche Kalibrierung | 30 min | Langfristig präziser SOC |
|
||
| 🟢 **NIEDRIG** | SOC-Monitoring | 15 min | Frühwarnung bei Drift |
|
||
|
||
### Checklist
|
||
|
||
- [ ] Sicherheitspuffer auf 30% erhöhen
|
||
- [ ] Input Helper für Kalibrierung erstellen
|
||
- [ ] 4 Kalibrierungs-Automations installieren
|
||
- [ ] Erste manuelle Kalibrierung durchführen
|
||
- [ ] SOC-Monitoring Automation installieren
|
||
- [ ] Nach 1 Monat: Überprüfen ob Batterie regelmäßig 100% erreicht
|
||
|
||
## Technische Details
|
||
|
||
### GoodWe BMS-Spezifikationen
|
||
|
||
**SOC-Berechnung:**
|
||
- Methode: Coulomb Counting + Voltage Estimation
|
||
- Update-Rate: 1 Hz (jede Sekunde)
|
||
- Genauigkeit: ±3% (typisch), ±5% (maximum)
|
||
- Kalibrierungs-Intervall: Empfohlen alle 30 Tage
|
||
|
||
**Referenzpunkte:**
|
||
- 100% SOC: 54.4V (LiFePO4, 16S × 3.4V)
|
||
- 20% SOC: 51.2V (LiFePO4, 16S × 3.2V)
|
||
- Floating Voltage: 54.0V
|
||
|
||
**Kapazitäts-Learning:**
|
||
- Algorithmus: Adaptive Weighted Integration
|
||
- Lernrate: 0.1-0.5 (abhängig von Confidence)
|
||
- Konvergenz: 3-5 Vollzyklen
|
||
|
||
### Home Assistant Integration
|
||
|
||
**Wichtige Entities:**
|
||
- `sensor.esssoc`: BMS-berechneter SOC
|
||
- `sensor.battery_voltage`: Gesamt-Spannung
|
||
- `sensor.battery_current`: Lade-/Entladestrom
|
||
- `sensor.battery_power`: Leistung (W)
|
||
- `sensor.battery_temperature`: Temperatur
|
||
|
||
**Berechnete Sensoren:**
|
||
- SOC-Validierung
|
||
- Wahre Kapazität
|
||
- Drift-Erkennung
|
||
- Health-Score
|
||
|
||
## Referenzen
|
||
|
||
### Weiterführende Informationen
|
||
|
||
- GoodWe BMS Manual: SOC-Algorithmus Details
|
||
- Battery University: SOC Estimation Techniques
|
||
- OpenEMS Documentation: Battery Management
|
||
- Home Assistant: Template Sensors & Automations
|
||
|
||
### Support & Community
|
||
|
||
- Home Assistant Community Forum
|
||
- GoodWe Support
|
||
- OpenEMS Community
|
||
- Battery Management System Best Practices
|
||
|
||
---
|
||
|
||
**Version**: 1.0
|
||
**Datum**: 2025-11-25
|
||
**Autor**: Felix + Claude
|
||
**Status**: Produktions-bereit
|