Files
battery-charging-optimizer/SOC_CALIBRATION_GUIDE.md

459 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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