# skaduz & Universal Solar Studio – Technische Gesamtdokumentation (v3.9.8 / v15.16) > 100 % clientseitiges Photovoltaik-Ökosystem unter freier MIT-Lizenz. > Beinhaltet die mobile Web-AR-Horizontmessung per Smartphone/Tablet und die sensorbasierte physikalische 3D-Balkonsimulation im DACH-Raum. > Alle Berechnungen laufen lokal im Browser-Arbeitsspeicher des Nutzers (Zero-Backend, vollständige Privatsphäre). > Domain: https://skaduz.de/ > Scanner (App 1): https://skaduz.de/scan/ > Solar Studio (App 2): https://skaduz.de/studio/ > Index: https://skaduz.de/llms.txt > Manifest: https://skaduz.de/ai-manifest.json > Prompt Blueprint: https://skaduz.de/AI_PROMPT_BLUEPRINT.md > Lizenz: MIT License (Open Source) --- # TEIL I: skaduz (v3.9.8) – Web-AR Horizont- & Sonnenbahn-Scanner URL: https://skaduz.de/scan/ ## 1. Systemübersicht & Gelöste Probleme skaduz löst drei fundamentale messtechnische Hürden bei der Planung dezentraler Photovoltaik (Balkonkraftwerke, Fassadenanlagen, Terrassen-PV): ### Problem A: Magnetische Missweisung auf Balkonen Smartphones orientieren sich über Magnetfeldsensoren (Hall-Sensoren). Auf Balkonen und Terrassen wird das Erdmagnetfeld durch Bewehrungsstahl in Deckenplatten, massive Stahlgeländer und Mikrowechselrichter massiv verzerrt. Abweichungen von 15° bis 45° sind die Regel. *Lösung in skaduz:* Der **Sonnen- und Schatten-Anker**. skaduz berechnet aus Standort und Systemzeit den astronomisch exakten Sonnenstand. Durch kurzes Anvisieren der Sonne wird die Himmelsrichtung (Azimut) optisch absolut geeicht. Das gestörte Magnetometer wird vollständig umgangen. Der **Schatten-Anker** erlaubt alternativ das Anvisieren des Smartphoneschattens auf dem Boden (180°-Inversion des Sonnenazimuts), was bei hohem Sonnenstand oder starker Blendung ergonomischer ist. ### Problem B: Parallaxe und unzuverlässige Winkelschätzung Das menschliche Auge kann Höhenwinkel am Himmel nicht präzise schätzen; Hindernisse werden systematisch über- oder unterschätzt. *Lösung in skaduz:* Die Kamera wird mit dem **Erdbeschleunigungsvektor (Gravitations-Lot)** gekoppelt. Der physikalische 0°-Horizont wird mit Sub-Grad-Genauigkeit als Flight-Director-Linie eingeblendet. ### Problem C: Varianz der Smartphone-Linsen (Brennweitenfehler) Web-Browser verwehren aus Datenschutzgründen (Anti-Fingerprinting) den Zugriff auf die intrinsische Kameramatrix (Focal Length / FOV). Feste Annahmen führen zu 5–15 % Skalierungsfehlern bei Hindernishöhen. *Lösung in skaduz:* **Passive 1D-Skyline-Kreuzkorrelation**. Während des natürlichen Schwenks vergleicht die App die Pixelverschiebung markanter Dachkanten mit der Drehrate des Gyroskops und ermittelt das Sichtfeld (HFOV/VFOV) ohne jegliche Nutzereingabe. ### Problem D: Verdeckungen des Horizonts in Astronomie-Software skaduz exportiert den erfassten Horizont als `.zip`-Landschaftspaket für Stellarium, KStars und N.I.N.A., inklusive realer Panoramatextur und Polygonvektoren. --- ## 2. Mathematische & Physikalische Algorithmen ### 2.1 Himmelsmechanik (Spencer 1971 / DIN EN ISO 9488) Die Sonnenposition wird für Tag $d_n \in [1, 365]$ und UTC-Dezimalstunde $t_{\text{utc}}$ analytisch bestimmt: $$\Gamma_0 = \frac{2\pi (d_n - 1)}{365}$$ $$\delta = 0{,}006918 - 0{,}399912 \cos(\Gamma_0) + 0{,}070257 \sin(\Gamma_0) - 0{,}006758 \cos(2\Gamma_0) + 0{,}000907 \sin(2\Gamma_0) - 0{,}002697 \cos(3\Gamma_0) + 0{,}00148 \sin(3\Gamma_0)$$ $$\text{EoT} = 229{,}18 \cdot (0{,}000075 + 0{,}001868 \cos(\Gamma_0) - 0{,}032077 \sin(\Gamma_0) - 0{,}014615 \cos(2\Gamma_0) - 0{,}040849 \sin(2\Gamma_0))$$ $$\text{SolarTime} = t_{\text{utc}} + \frac{4 \cdot \lambda + \text{EoT}}{60}, \quad \omega = (\text{SolarTime} - 12) \cdot 15^\circ$$ $$\sin(\alpha_{\text{geo}}) = \sin(\delta) \sin(\phi) + \cos(\delta) \cos(\phi) \cos(\omega)$$ Atmosphärische Refraktionskorrektur nach Saemundsson (1986): $$\Delta\alpha_{\text{refr}} = \frac{1{,}02}{\tan\left(\alpha_{\text{geo}} + \frac{10{,}3}{\alpha_{\text{geo}} + 5{,}11}\right)} \quad [\text{Bogenminuten}], \quad \alpha_{\text{sun}} = \alpha_{\text{geo}} + \frac{\Delta\alpha_{\text{refr}}}{60^\circ}$$ ### 2.2 Pinhole-Projektion & Rückrechnung Für jeden Bildpunkt mit normierten Sensorkoordinaten $u \in [-0{,}5; +0{,}5]$ (horizontal) und $v \in [-0{,}5; +0{,}5]$ (vertikal, positiv nach oben): $$\Delta\alpha = \arctan\left(-v \cdot 2 \cdot \tan\left(\frac{\text{VFOV}}{2}\right)\right), \quad \text{Elevation} = \theta_{\text{pitch}} + \Delta\alpha$$ $$\Delta\psi = \frac{u \cdot \text{HFOV}}{\cos(\theta_{\text{pitch}})}, \quad \text{Azimut} = (\psi_{\text{heading}} + \Delta\psi + 360^\circ) \bmod 360^\circ$$ ### 2.3 Slit-Scan Panorama-Akkumulation Ein interner Canvas ($1440 \times 360\,\text{px}$) deckt ein vollständiges $360^\circ$-Zylinderpanorama von $+60^\circ$ bis $-30^\circ$ Elevation ab ($4\,\text{Pixel pro Grad}$). - Bei jedem Frame mit gültiger Drehrate ($\omega < 70^\circ/\text{s}$) wird ein schmaler vertikaler Bildstreifen mit Roll-Kompensation ($\mathbf{R}(-\phi_{\text{roll}})$) an Position $x_{\text{dest}} = (\psi / 360^\circ) \cdot 1440$ gestempelt. - Streifenhöhe: $\text{destH} = \operatorname{round}(\text{VFOV} \cdot 4\,\text{px/deg})$. ### 2.4 Dynamic-Programming Skyline-Extraktion Im verkleinerten Verarbeitungs-Puffer ($120 \times 160\,\text{px}$) durchläuft ein Viterbi-artiger Dynamic-Programming-Algorithmus das Bild von links nach rechts: $$C(x, y) = 210 - \Big(|\nabla L(x, y)| + 180 \cdot \max(0, \Delta \text{BlueRatio}) + 1{,}6 \cdot \text{Texture}(x, y)\Big)$$ $$\text{DP}(x, y) = C(x, y) + \min_{dy \in [-6, 6]} \Big(\text{DP}(x - 1, y + dy) + 2{,}5 \cdot |dy|\Big)$$ Der Pfad mit minimalen kumulierten Kosten liefert die exakte Konturlinie zwischen Himmel und Bauwerken/Bäumen. ### 2.5 Passive Zero-UI FOV-Autokalibrierung Zwischen zwei Frames mit Gyro-Drehwinkel $\Delta\psi \in [1{,}8^\circ; 6{,}0^\circ]$ wird die 1D-Skyline-Verschiebung $\Delta x$ via Sum of Squared Differences (SSD) minimiert: $$\Delta x = \operatorname{argmin}_{\delta} \sum_{x} \Big(\text{skyline}_t(x) - \text{skyline}_{t+\Delta t}(x + \delta)\Big)^2$$ $$\text{PPD} = \frac{|\Delta x|}{\Delta\psi} \cdot \left(\frac{W_{\text{real}}}{W_{\text{proc}}}\right) \implies \text{HFOV} = \frac{W_{\text{real}}}{\text{PPD}}, \quad \text{VFOV} = 2 \cdot \arctan\left(\frac{H_{\text{real}}}{W_{\text{real}}} \cdot \tan\left(\frac{\text{HFOV}}{2}\right)\right)$$ Die Werte durchlaufen einen 6-fach Medianfilter und werden auf physikalische Schranken ($38^\circ \le \text{HFOV} \le 88^\circ$) begrenzt. ### 2.6 Biomechanische Rumpf-Parallaxe Das Smartphone wird mit am Oberkörper fixierten Armen geführt ($r_{\text{arm}} \approx 25\text{--}30\,\text{cm}$ Drehachsenabstand). Bei typischen Hindernisdistanzen $D \ge 20\,\text{m}$ beträgt der Parallaxenfehler: $$\Delta\alpha_{\text{para}} \le \frac{r_{\text{arm}} \cdot \sin(\Delta\psi)}{D} \le \frac{0{,}28\,\text{m} \cdot \sin(2^\circ)}{20\,\text{m}} \approx 0{,}028^\circ \quad (< 1{,}4\,\% \text{ der Eigenrotation})$$ Die Bewegung ist zu $> 98{,}6\,\%$ eine reine Dreh-Homographie. --- ## 3. Datenformate & Schnittstellen-Spezifikation ### 3.1 Das PVGIS-Horizontformat (.hor) Textdatei mit 72 Zeilen à 5° Intervall (Standard für PVGIS, PV*SOL und Polysun): - Spalte 1: Azimut in Grad von $-180{,}0^\circ$ bis $+180{,}0^\circ$ ($0^\circ = \text{Süd}$, $-90^\circ = \text{Ost}$, $+90^\circ = \text{West}$, $\pm 180^\circ = \text{Nord}$). - Spalte 2: Elevationswinkel der Horizontsilhouette in Grad über dem mathematischen 0°-Horizont. - Trennzeichen: Tabulator (`\t`). Lücken werden durch zweiseitige Nachbarschafts-Interpolation geschlossen. ### 3.2 Das 3D-Zylinderkörper-Format (.glb) Binäre glTF-2.0-Datei (`model/gltf-binary`) für CAD-Software und 3D-Engines: - Geometrie: Zylindrisches Polygonnetz mit Radius $R = 18{,}0\,\text{m}$. * Unterkante: Fest auf Bodenniveau $Y = 0{,}0\,\text{m}$. * Oberkante: Abgeschnitten entlang der gemessenen Silhouette ($Y = R \cdot \tan(\alpha)$). * Dreiecksanzahl: 144 Dreiecke (72 Segmente à 2 Quads). - Texturierung: Vollständiges UV-Mapping auf das $1440 \times 360\,\text{px}$ Panoramabild (reale Fototextur). * Material: `MeshStandardMaterial`, beidseitig gerendert (`side: DoubleSide`), Textur im GLB eingebettet. - Metadaten (glTF `asset.extras` bzw. `nodes[0].userData`): ```json { "generator": "skaduz v3.9.8", "latitude": 51.312, "longitude": 9.491, "locationSource": "gps_approximate", "azimuthShift": 0.0, "facadeAzimuth": 180.0, "panelMountHeight": 0.95, "created": "2026-09-30T12:00:00.000Z" } ``` ### 3.3 Zero-Copy postMessage RAM-Transfer (Solar Studio Bridge) Protokoll zur verlustfreien Übergabe des Modells an Universal Solar Studio ohne Serverübertragung: 1. `skaduz` öffnet Ziel-URL synchron im Klick-Event: `const win = window.open('https://skaduz.de/studio/#obstmode=scan&source=skaduz...', '_blank');` 2. `Solar Studio` sendet nach Boot-Abschluss: `window.opener.postMessage({ type: 'SOLAR_STUDIO_READY_FOR_GLB' }, '*');` 3. `skaduz` antwortet mit dem Binärpuffer: ```javascript win.postMessage({ type: 'TRANSFER_SKADUZ_GLB', buffer: glbArrayBuffer, metadata: { coords: { lat: 51.31, lon: 9.49 }, azimuthShift: 0.0, facadeAzimuth: 180.0, yOffset: 0.0 } }, 'https://skaduz.de'); ``` 4. `Solar Studio` bestätigt den Empfang: `window.opener.postMessage({ type: 'SOLAR_STUDIO_GLB_ACK' }, '*');` --- ## 4. Plattform-Matrix & Betriebsmodi | Plattform | Eingabemodus | Sensorpfad | Besonderheiten | | :--- | :--- | :--- | :--- | | **iOS (iPhone)** | Portrait (Hochkant) | `DeviceOrientation` (Permission via Klick) | HFOV $44^\circ$, VFOV $56^\circ$, Zielneigung $+10^\circ$. | | **iPadOS (Tablet)** | Landscape (Querformat) | `DeviceOrientation` (Erkennung via `maxTouchPoints > 1`) | Achsentausch: HFOV $68^\circ$, VFOV $42^\circ$, Zielneigung $+14^\circ$, Daumen-Buttons seitlich. | | **Android Phone** | Portrait | `deviceorientationabsolute` (Primär) | Hardware-Zoom-Constraint für Ultraweitwinkel. | | **Android Tablet** | Landscape | `deviceorientationabsolute` | Adaptive Slit-Scan Streifenhöhe. | | **Desktop / PC** | Desktop-Maus | Watchdog fällt auf Demo-Modus zurück | Simuliert künstlichen Taghimmel und Test-Skyline ohne Kamera. | --- # TEIL II: Universal Solar Studio (v15.16) – 3D-Balkonsimulator URL: https://skaduz.de/studio/ ## 1. Duale URL-Schnittstelle (#ai= und #cfg=) ### Format A: Das semantische Format (#ai=) – Für Chatbots, Assistenten & Deep-Links Kompakt, fehlertolerant und menschenlesbar. Fehlende Parameter werden automatisch durch bewährte DACH-Standardwerte ergänzt. Syntax: `https://skaduz.de/studio/#ai=key:val;key:val;action:calc` ### Format B: Das verlustfreie Vollzustands-Format (#cfg=) – Für 1:1 Geometrie-Klone Nimmt ein vollständiges, URI-kodiertes JSON-Objekt entgegen. Ermöglicht es KI-Agenten, millimetergenaue Wandplatzierungen, 3D-Fotozylinder-Winkel und komplexe 3D-Scan-Transformationen absolut verlustfrei als Link zu teilen. Syntax: `https://skaduz.de/studio/#cfg=%7B%22preset%22%3A%22balcony_south%22%2C...%7D` --- ## 2. Vollständige Parameter-Referenz für #ai= Trennzeichen ist das Semikolon (`;`). Schlüssel und Werte werden mit Doppelpunkt (`:`) getrennt. Zahlenwerte werden ohne Maßeinheiten übergeben. #### Standort & Meteorologie - `loc:`: DWD-Klimastützpunkt (2D-IDW-Interpolation über 20 Referenzstationen in Deutschland inkl. Mini-DEM Geländehöhe). * Gültige Kernwerte: `kassel` (Standard), `erfurt`, `frankfurt`, `norderney`, `rostock`, `hamburg`, `bremen`, `hannover`, `koeln`, `muenster`, `trier`, `berlin`, `leipzig`, `dresden`, `magdeburg`, `stuttgart`, `freiburg`, `nuernberg`, `muenchen`, `kempten`. * DACH-Aliase (z. B. `wien`, `graz`, `zuerich`, `basel`, `cologne`, `ruhrgebiet`, `augsburg`, `kiel`, `frankfurtoder`) werden automatisch aufgelöst. Alternativ Koordinaten: `loc:51.31,9.49` oder `lat:51.31;lon:9.49`. - `climate:`: Meteorologische Datengrundlage des Deutschen Wetterdienstes (DWD). * `norm`: DWD-Klimanormalperiode 1991–2020 (30-Jahres-Mittel der WMO). Aliase: `1991_2020`, `30y`. * `recent` (Standard): DWD-Messdatenreihe 2015–2024 (10-Jahres-Mittel aus CDC-Rasterdaten, +4,6 % Global Brightening). Aliase: `2015_2024`, `10y`. #### Geometrie-Presets - `preset:`: Lädt ein vollständiges Setup inklusive Wand-, Decken- und Ausrichtungsgeometrie: * `balcony_south`: 2 Module Querformat, 25° Süd, Standard-Geländer (0,90 m). * `balcony_vertical`: 2 Module Querformat, 90° Süd senkrecht an Reling. * `loggia_south`: 2 Module Hochkant, 25° Süd, Hitzestau (`therm:stau`), 3 geschlossene Wände und Deckenüberstand. * `east_west_split`: Ost-West-Satteldach, 15° Neigung, G1: 90° Ost, G2: 270° West. * `table_oso`: Solartisch 15° OSO, 1x 380 Wp Sicherheitsglas, 400 W AC, freistehend. * `garden_south`: 4 Module Hochkant, 30° Süd im Garten, freistehend (`therm:free`). #### Freier 4-Kanal-CAD-Editor (Modus 5) - `cad:<0|1>`: Aktiviert den CAD-Editor für unkonventionelle, asymmetrische Aufstellungen. - `m1..m4:`: Individuelle Parametrisierung jedes Kanals: * Format: `m1:1_L_-0.90_0.95_0.0_25_180_A` (1=aktiv, L=Landscape, X, Y, Z, Tilt, Azimut, Gruppe). * Autarke MPPTs: Jeder aktive Kanal regelt unabhängig; die Gesamtsumme wird gegen das AC-Limit abgeregelt. * OBB-SAT-Kollision: Verhindert räumliche Durchdringungen und Überlappungen von Modulen. #### Kinematik & Ausrichtung - `baz:<0-360>`: Fassaden-/Balkon-Ausrichtung in Grad (180 = Süd). Dreht das gesamte Bauwerk starr mit. - `az:<0-360>`: Modul-Ausrichtung in Grad (Standard: gekoppelt an `baz`). - `tilt:<0-90>`: Neigungswinkel in Grad (Standard: 25). - `h:<0.0-4.0>`: Montagehöhe der Modulunterkante über dem Balkonboden in Metern (Standard: 0.95). - `split:`: Aktiviert die getrennte Ausrichtung (Ost-West-Split). - `t1:<0-90>` / `a1:<0-360>`: Neigung und Azimut für Gruppe 1 (z. B. `t1:15;a1:85` für Ost). - `t2:<0-90>` / `a2:<0-360>`: Neigung und Azimut für Gruppe 2 (z. B. `t2:20;a2:265` für West). - `orient:`: * `landscape` (Querformat – Standard und Empfehlung für Brüstungen wegen horizontaler Bypass-Diodenstränge). * `portrait` (Hochkant – Standard für offene Gitter oder Freiflächen). * Geometrie-Aliase: `reling` (90° S), `split`, `loggia`, `table_oso`, `garden_south`. #### Hardware & Elektrik - `modp:`: Modultyp (`topcon_440` = 440 Wp TOPCon Bifazial; `classic_400` = 400 Wp PERC; `table_380` = 380 Wp Sicherheitsglas; `light_330` = Ultraleicht; `power_500` = 500 Wp XL). - `panels:<1|2|4>`: Modulanzahl (1 = Single/Tisch, 2 = Standard, 4 = Quad-Set bis 2.000 Wp nach Solarpaket 1). - `wp:<100-800>`: Nennleistung pro Modul in Watt-Peak (Standard: 440). - `inv:<400|600|800>`: Wechselrichter AC-Grenze in Watt (Standard: 800). - `therm:`: Belüftungssituation nach Faiman-Modell. - `bat:<0.0-15.0>`: LiFePO4-Speicherkapazität in kWh stufenlos (Standard: 0 = Direktnutzung; z. B. `bat:1.6`, `bat:2.0`, `bat:2.4`). - `bat_max_p:<100-800>`: Maximale AC-Entladeleistung des Batteriespeichers in Watt (Standard: 500). - `bat_bypass:<0-800>`: Feste Grundlast-Einspeisung / Standby-Abgabe in Watt (Standard: 0 = bedarfsorientiert). - `bat_mode:`: Speicherstrategie (smart = dynamischer Eigenbedarf; bypass = feste Grundabgabe). #### Haushalt, Lastprofil & Finanzen - `prof:`: Lastprofil nach VDI 4655 (`homeoffice`, `commuter`, `seniors`, `couple`, `family`, `smarthome`). - `kwh:<200-25000>`: Tatsächlicher Jahresstromverbrauch in kWh/a (überschreibt den Nennwert des Profils). - `base:<0-500>`: Dauerhafte Ruhelast / Standby-Grundlast des Haushalts in Watt (Standard: 20). - `price:`: Stromtarif in ct/kWh brutto (Standard: 31.48). - `capex:`: Anschaffungskosten des PV-Sets in Euro (Standard: 399). - `cost_bat:`: Anschaffungskosten des Speichers in Euro für die Amortisationsberechnung. - `feed:`: Einspeisevergütung in ct/kWh (Standard: 0.0). - `inflation:<0-10>`: Strompreissteigerung in %/a für die 10-Jahres-Barwertrechnung nach VDI 2067 (Standard: 2.0). - `degradation:<0-2>`: Modul-Degradation in %/a (Standard: 0.5). #### Wände & Decke (Modus 1) - `wall:`: Frontgeländer-Art (`solid` = Mauerwerk/Beton; `grid` = offene Streben; `none` = ohne Geländer). - `wall_front:` / `wf:`: Frontbrüstung mit Distanz und Höhe in Metern (z. B. `wall_front:0.95_0.90`). - `wall_back:` / `wb:`: Hauswand hinten mit Distanz und Höhe (z. B. `wall_back:1.30_2.80`). - `wall_left:>` / `wl:`: Seitenwand links (z. B. `wall_left:1.80_2.40`). - `wall_right:>` / `wr:`: Seitenwand rechts (z. B. `wall_right:1.80_2.40`). - `overhang:|>`: Deckenüberstand mit Ausladung und lichter Höhe (z. B. `overhang:1.20_2.60`). - Exakte Maße (optional als Tupel `[on,distanz,hoehe]`): * `wf:` (Frontbrüstung, z. B. `wf:true,0.95,1.10`) * `wb:` (Hauswand hinten, z. B. `wb:true,1.40,2.80`) * `wl:` (Linke Seitenwand) * `wr:` (Rechte Seitenwand) * `wt:` (Decke / Überstand: Tiefe und lichte Höhe) #### 360°-Horizont-Vorhang (Modus 2) - `shade_preset:`: * `clear`: Freihorizont (0 m Hindernishöhe). * `terraced`: Siedlung / Nachbardächer (9 m Firsthöhe auf SO, S, SW). * `tree_sw`: Großer Laubbaum im Südwesten (18 m Krone in 14 m Distanz). * `courtyard`: Enger Innenhof (13,5 m Kesselwand). - `shade:`: Benutzerdefinierte Hindernisse. Sektoren: `no`, `ono`, `oso`, `so`, `sso`, `sued`, `ssw`, `sw`, `wsw`, `wnw`, `nw`. Format: `__` (z. B. `shade:sw_15_12`). #### Aktionen & Zeitsteuerung - `action:`: * `calc`: Führt direkt nach Laden die 365-Tage-Jahresbilanz aus. * `optimize`: Startet die mathematische LOD-Suche nach dem wirtschaftlich optimalen Neigungswinkel. * `print`: Öffnet das druckfertige A4-Muster zur Vermieter-Voranfrage (§ 554 BGB / § 20 WEG). * `telemetry`: Öffnet den CSV-Messdaten-Importbereich für den Soll-Ist-Abgleich. * `verify`: Führt die interne 41-Punkte-Modellverifikation aus und zeigt den Audit-Bericht. - `hour:<3-21>`: Uhrzeit für die Sonnenstandssimulation (Dezimalstunden oder HH:MM). - `day:<1-365>`: Kalendertag des Jahres (z. B. 80 = Frühlings-Äquinoktium, 230 = 18. August). - `mode:`: Aktiver Hindernismodus. --- ## 3. Formale JSON-Schema-Definition (Draft-07) ```json { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SolarStudioConfig", "description": "Parameter für die Universal Solar Studio 3D-Balkon-Photovoltaik-Planungshilfe (v15.16)", "type": "object", "properties": { "loc": { "type": "string", "default": "kassel", "description": "Standort oder Stadtname im DACH-Raum" }, "climatePeriod": { "type": "string", "enum": ["dwd_1991_2020", "dwd_2015_2024"], "default": "dwd_2015_2024" }, "preset": { "type": "string", "enum": ["balcony_south", "balcony_vertical", "loggia_south", "east_west_split", "table_oso", "garden_south"] }, "az": { "type": "number", "minimum": 0, "maximum": 360, "default": 180 }, "baz": { "type": "number", "minimum": 0, "maximum": 360, "default": 180 }, "tilt": { "type": "number", "minimum": 0, "maximum": 90, "default": 25 }, "h": { "type": "number", "minimum": 0.0, "maximum": 4.0, "default": 0.95 }, "split": { "type": "boolean", "default": false }, "t1": { "type": "number", "minimum": 0, "maximum": 90, "default": 20 }, "a1": { "type": "number", "minimum": 0, "maximum": 360, "default": 90 }, "t2": { "type": "number", "minimum": 0, "maximum": 90, "default": 20 }, "a2": { "type": "number", "minimum": 0, "maximum": 360, "default": 270 }, "orient": { "type": "string", "enum": ["landscape", "portrait", "sued", "sw", "so", "west", "ost", "reling", "split", "loggia", "table_oso", "garden_south"], "default": "landscape" }, "modp": { "type": "string", "enum": ["topcon_440", "classic_400", "table_380", "light_330", "power_500", "custom"], "default": "topcon_440" }, "panels": { "type": "integer", "enum": [1, 2, 4], "default": 2 }, "wp": { "type": "number", "minimum": 100, "maximum": 800, "default": 440 }, "inv": { "type": "integer", "enum": [400, 600, 800], "default": 800 }, "therm": { "type": "string", "enum": ["standard", "stau", "free"], "default": "standard" }, "wall": { "type": "string", "enum": ["solid", "grid", "glass", "none"], "default": "solid" }, "wall_left": { "type": "string", "default": "none" }, "wall_right": { "type": "string", "default": "none" }, "overhang": { "type": ["string", "number"], "default": "none" }, "shade": { "type": "string" }, "shade_preset": { "type": "string", "enum": ["clear", "terraced", "tree_sw", "courtyard"] }, "bat": { "type": "number", "minimum": 0.0, "maximum": 15.0, "default": 0 }, "bat_max_p": { "type": "integer", "minimum": 100, "maximum": 800, "default": 500 }, "bat_bypass": { "type": "number", "minimum": 0, "maximum": 800, "default": 0 }, "bat_mode": { "type": "string", "enum": ["smart", "bypass_100", "bypass_150"], "default": "smart" }, "prof": { "type": "string", "enum": ["homeoffice", "commuter", "seniors", "couple", "family", "smarthome"], "default": "homeoffice" }, "kwh": { "type": "integer", "minimum": 200, "maximum": 25000, "default": 1300 }, "base": { "type": "number", "minimum": 0, "maximum": 500, "default": 20 }, "price": { "type": "number", "minimum": 5.0, "maximum": 100.0, "default": 31.48 }, "capex": { "type": "number", "minimum": 0, "maximum": 5000, "default": 399 }, "cost_bat": { "type": "number", "minimum": 0, "maximum": 5000, "default": 0 }, "feed": { "type": "number", "minimum": 0.0, "maximum": 30.0, "default": 0.0 }, "inflation": { "type": "number", "minimum": 0.0, "maximum": 10.0, "default": 2.0 }, "degradation": { "type": "number", "minimum": 0.0, "maximum": 2.0, "default": 0.5 }, "hour": { "type": "number", "minimum": 3.0, "maximum": 21.0, "default": 10.0 }, "day": { "type": "integer", "minimum": 1, "maximum": 365, "default": 230 }, "obstMode": { "type": "string", "enum": ["walls", "panorama", "photo", "scan"], "default": "walls" }, "action": { "type": "string", "enum": ["calc", "optimize", "print", "telemetry", "verify"], "default": "calc" } }, "required": ["loc", "panels", "action"] } ``` --- ## 4. TypeScript-Typdefinitionen ```typescript export interface SolarStudioConfig { loc?: string; climatePeriod?: 'dwd_1991_2020' | 'dwd_2015_2024'; preset?: 'balcony_south' | 'balcony_vertical' | 'loggia_south' | 'east_west_split' | 'table_oso' | 'garden_south'; lat?: number; lon?: number; az?: number; baz?: number; tilt?: number; h?: number; split?: boolean; t1?: number; a1?: number; t2?: number; a2?: number; orient?: 'landscape' | 'portrait' | string; modp?: 'topcon_440' | 'classic_400' | 'table_380' | 'light_330' | 'power_500' | 'custom'; panels?: 1 | 2 | 4; count?: 1 | 2 | 4; wp?: number; inv?: 400 | 600 | 800; therm?: 'standard' | 'stau' | 'free'; wall?: 'solid' | 'grid' | 'glass' | 'none'; wall_left?: 'solid' | 'none' | string; wall_right?: 'solid' | 'none' | string; overhang?: 'deep' | 'small' | 'none' | number; wf?: [boolean, number, number]; wb?: [boolean, number, number]; wl?: [boolean, number, number]; wr?: [boolean, number, number]; wt?: [boolean, number, number]; shade?: string; shade_preset?: 'clear' | 'terraced' | 'tree_sw' | 'courtyard'; sky?: Array<[number, number]>; bat?: number; bat_max_p?: number; batMaxP?: number; bat_bypass?: number; batBypass?: number; bat_mode?: 'smart' | 'bypass_100' | 'bypass_150'; prof?: 'homeoffice' | 'commuter' | 'seniors' | 'couple' | 'family' | 'smarthome'; kwh?: number; base?: number; price?: number; capex?: number; costPv?: number; costBat?: number; feed?: number; inflation?: number; degradation?: number; hour?: number; day?: number; obstMode?: 'walls' | 'panorama' | 'photo' | 'scan'; photoLeftAz?: number; photoRightAz?: number; photoTopDeg?: number; photoBottomDeg?: number; photoOpacity?: number; scanCfg?: [number, number, number, number, number, boolean]; action?: 'calc' | 'optimize' | 'print' | 'telemetry' | 'verify'; } export interface SolarStudioSimulationResult { valid: boolean; version: string; timestamp: string; summary_for_llm: string; parse_report?: { applied_parameters: Record; warnings: string[]; }; metrics: { climate_period: string; annual_prod_kwh: number; self_consumption_kwh: number; grid_feed_kwh: number; battery_discharge_kwh: number; annual_savings_eur: number; autarky_pct: number; self_consumption_pct: number; usable_battery_wh: number; }; monthly: { prod_kwh: number[]; self_kwh: number[]; grid_kwh: number[]; }; waterfall_pct: { geometry_loss: number; shading_loss: number; thermal_iam_loss: number; inverter_loss: number; }; hints: string[]; share_url: string; } export interface SolarStudioOptimizeResult { valid: boolean; best_tilt_deg: number; payback_years: number; annual_savings_eur: number; annual_prod_kwh: number; self_consumption_kwh: number; autarky_pct: number; share_url: string; } ``` --- ## 5. Model Context Protocol (MCP) – Tool-Definition ```json { "name": "simulate_balcony_solar", "description": "Erzeugt eine physikalische 3D-Balkon-Photovoltaik-Planung mit Verschattungsberechnung, Lastprofil, DWD-Klimadaten, Neigungsoptimierung und Ertragsbilanz.", "inputSchema": { "type": "object", "properties": { "location": { "type": "string", "description": "Standort oder Stadt im DACH-Raum" }, "climate_period": { "type": "string", "enum": ["dwd_1991_2020", "dwd_2015_2024"] }, "facade_azimuth": { "type": "number", "description": "Ausrichtung der Fassade in Grad (180 = Süd, 90 = Ost, 270 = West)" }, "tilt_angle": { "type": "number", "description": "Neigungswinkel der Module (z. B. 25 oder 90)" }, "panel_count": { "type": "integer", "enum": [1, 2, 4], "description": "Anzahl der Solarmodule" }, "mounting_height": { "type": "number", "description": "Montagehöhe der Modulunterkante über Balkonboden in m" }, "module_orientation": { "type": "string", "enum": ["landscape", "portrait"] }, "balcony_wall_type": { "type": "string", "enum": ["solid", "grid", "glass", "none"] }, "roof_overhang": { "type": "string", "enum": ["deep", "small", "none"] }, "annual_kwh": { "type": "integer", "description": "Jahresstromverbrauch des Haushalts in kWh" }, "battery_kwh": { "type": "number", "minimum": 0.0, "maximum": 15.0, "description": "LiFePO4-Speicherkapazität in kWh" }, "load_profile": { "type": "string", "enum": ["homeoffice", "commuter", "family", "couple", "seniors", "smarthome"] }, "action": { "type": "string", "enum": ["calc", "optimize", "print"], "default": "calc" } }, "required": ["facade_azimuth", "panel_count"] } } ``` --- ## 6. Physikalische & Mathematische Berechnungsmodelle ### 6.1 DWD-Klimadaten & Geländehöhe (Mini-DEM) - Duale Datenbasis über 20 DWD-Stationen (2D-IDW-Interpolation): * `dwd_1991_2020`: WMO-Klimanormale (1.036 kWh/m²a Referenz Kassel). * `dwd_2015_2024`: 10-Jahres-Mittel aus CDC-Rasterdaten (1.044 kWh/m²a Referenz Kassel). - Bilineares Mini-DEM Geländemodell (47°N–55°N, 6°O–15°O) mit Lapse-Rate-Temperaturkorrektur ($-0{,}0065\ \text{K/m}$) und barometrischer ICAO-Druckanpassung. ### 6.2 Strahlungstransposition & Diffusmodell (Bimodales Perez 1990) - Erbs-Dekomposition in Direkt- und Diffusstrahlung. - Anisotrope 8-Bin Perez-Verteilung für zirkumsolare, horizontnahe und isotrope Anteile. - Bimodale Trennung jedes Stütztages in klare und bedeckte Stunden mit $k_t$-Gewichtung. - Temperaturabhängige Albedo ($\rho = 0{,}20$; Schneekopplung bei $T_{\text{amb}} \le 2\,^\circ\text{C}$). ### 6.3 Optik & Verschmutzung - Incident Angle Modifier nach Martin & Ruiz ($a_r = 0{,}16$). - Spektrale Airmass-Korrektur $f_{\text{spec}}(m)$ für N-Type TOPCon und c-Si. - Sky View Factor über 64 lambertsche Fibonacci-Halbkugelstrahlen. - Neigungsabhängige Selbstreinigung nach Kimber/IEC 61724-1 ($4{,}5\,\%$ bei $0^\circ$; $1{,}5\,\%$ bei $25^\circ$; $0{,}6\,\%$ bei $90^\circ$). ### 6.4 BIPV-Thermik (Faiman / DIN EN 61724-1) - Zelltemperatur: $T_{\text{cell}} = T_{\text{amb}} + \frac{G_{\text{POA}}}{u_0 + u_1 \cdot v}$ mit regionalem DWD-Windfeld. - Parameter: Hinterlüftet ($u_0=29, u_1=1.5$); Hitzestau ($u_0=15, u_1=0.0$); Freistehend ($u_0=31, u_1=2.8$). - Leistungskoeffizient: $\gamma = -0{,}35\,\%/\text{K}$ bezogen auf 25 °C STC. ### 6.5 Halbzellen-Raycasting & Dioden (DIN EN 50530) - 24-Punkte-Sampling (96 Strahlen im HQ-Scan) mit Penumbra-Halbschattenauflösung. - Modellierung von 3 Bypass-Dioden pro Modul mit Shockley-Thermalgang ($-2{,}0\ \text{mV/K}$). - Mindestspannungssperre: Bei $V_{\text{MPP}} < 16{,}0\ \text{V}$ schaltet der MPPT-Kanal ab. - Wechselrichterkennlinie nach DIN EN 50530 mit Leerlaufverlusten und NREL SAM Sub-Hourly Clipping-Modellierung. ### 6.6 Speicher & Haushaltslast (VDI 4655 / VDI 2067) - LiFePO4-Batteriemodell mit ca. 88 % Roundtrip-Wirkungsgrad und BMS-Standby. - Koinzidenter Eigenverbrauch über Minkowski-P-Norm ($\beta = 3{,}5$) mit VDI 4655 Lastprofilen. - 10-Jahres-Barwertrechnung (NPV) nach VDI 2067 mit Diskontierungszins ($2{,}0\,\%$) und Degradation ($0{,}5\,\%/\text{a}$). --- ## 7. Headless JavaScript API & IPC Das globale Objekt `window.SolarStudio` ermöglicht lokale Headless-Aufrufe: ```javascript // 1. Simulation durchführen: const sim = window.SolarStudio.simulate({ loc: "muenchen", climatePeriod: "dwd_2015_2024", baz: 180, tilt: 25, panels: 2, wp: 440, inv: 800, bat: 2.4, prof: "homeoffice", kwh: 2400 }); console.log(sim.metrics.annual_prod_kwh); // Jahresertrag in kWh/a console.log(sim.metrics.self_consumption_kwh); // Eigennutzung in kWh/a console.log(sim.metrics.annual_savings_eur); // Ersparnis in EUR/a // 2. Neigungs-Optimum ermitteln (LOD Golden Section Search): const opt = await window.SolarStudio.optimize({ loc: "koeln", panels: 2 }); console.log(opt.best_tilt_deg, opt.payback_years); // 3. System-Selbsttest ausführen (41 Prüfpunkte nach DIN/VDI): const audit = await window.SolarStudio.verify(); console.log(audit.meta.overallPassed, audit.meta.integrityChecksum); ``` --- ## 8. Rechtlicher Status & Haftungsausschluss - **Solarpaket 1 (EEG / VDE-AR-N 4105):** Bis zu 800 W AC Wechselrichterleistung und bis zu 2.000 Wp Modulleistung sind als Steckersolargerät gesetzlich geregelt. - **Unverbindliche Planungshilfe:** Die Berechnungen sind rechnerische Modell-Schätzungen auf Basis langjähriger DWD-Mittelwerte. Reale Erträge unterliegen wetter-, montage- und standortbedingten Schwankungen. - **Keine Rechts- oder Statikberatung:** Die Software und erzeugte PDF-Voranfragen für Vermieter/WEGs (§ 554 Abs. 1 BGB, § 20 Abs. 2 WEG) sind unverbindliche Orientierungshilfen. - **Open Source:** Bereitgestellt unter freier MIT-Lizenz ohne Mängelgewähr und ohne vertragliche Leistungsgarantien. # TEIL III: Dokumentation # Universal Solar Studio & skaduz – Technical Reference & Physical Model Specification > **Document ID:** SPEC-USS-SKADUZ-V15-V3-EN > **Software Versions:** Universal Solar Studio v15.16 / skaduz v3.9.8 > **Classification:** Technical Reference Architecture, Numerical Physics & Model Specification > **Target Audience:** Solar PV Engineers, Numerical Modellers, Autonomous AI Agents (LLMs via `llms-full.txt`) > **Execution Runtime:** 100% Client-Side JavaScript (Browser RAM / WebGL), Single-File PWA, Zero-Cloud Dependency > **License:** MIT License (Open Source) --- ## 1. System Overview & Architectural Philosophy ### 1.1 Single-File PWA & Zero-Backend Paradigm Universal Solar Studio and skaduz are engineered as Progressive Web Apps (PWAs) that run entirely without server-side computational resources (Zero-Backend) inside the user's browser runtime. All geometric raycasting, atmospheric radiation transposition, diode-level shading analysis, and annual dispatch simulations execute inside the client's JavaScript engine (V8 / JavaScriptCore). Personal data, geographic coordinates, live video streams, and CSV telemetry never leave the client environment. ### 1.2 Zero-Allocation Register Architecture (`ZeroAlloc`) To prevent Garbage Collection latency spikes (GC jank) during interactive 60 FPS 3D rendering and during full-year 8,760-hour calculations, the computational core performs zero dynamic heap allocations during simulation loops. All scratch vectors, quaternions, coordinate matrices, and intermediary state buffers are pre-allocated within the `ZeroAlloc` namespace using static TypedArrays: | Buffer Identifier | Type & Size | Physical Representation / Purpose | | :--- | :--- | :--- | | `ZeroAlloc.vSunDir` | `THREE.Vector3` (1x3) | Normalized solar incidence vector in world coordinates | | `ZeroAlloc.vPanelCenter` | `THREE.Vector3` (1x3) | Geometric center anchor of PV module in world space | | `ZeroAlloc.vNormal1..4` | `THREE.Vector3` (4x3) | Surface normal vectors for PV channels 1 through 4 | | `ZeroAlloc.qRot1..4` | `THREE.Quaternion` (4x4) | Rigid-body kinematic rotation quaternions | | `ZeroAlloc.matrixClearDC` | `Float32Array` (6,912) | 72 baseline days $\times$ 96 quarter-hour steps of clear-sky DC power ($W$) | | `ZeroAlloc.matrixOvercastDC`| `Float32Array` (6,912) | 72 baseline days $\times$ 96 quarter-hour steps of overcast DC power ($W$) | | `ZeroAlloc.syntheticYearKt` | `Float32Array` (365) | Deterministic daily clearness index time-series ($k_t$) | | `ZeroAlloc.heatBeamActual` | `Float32Array` (384) | 4 modules $\times$ 96 points absorbed direct beam irradiance ($W/\text{m}^2$) | | `ZeroAlloc.heatBeamIdeal` | `Float32Array` (384) | 4 modules $\times$ 96 points unshaded reference beam irradiance ($W/\text{m}^2$) | | `ZeroAlloc.FIBONACCI_64` | `Array` (64) | Lambertian hemispherical sampling vectors for Sky View Factor | | `ZeroAlloc.monthlyProd` | `Float64Array` (12) | Monthly aggregated AC energy generation ($\text{kWh}$) | | `ZeroAlloc.monthlySelf` | `Float64Array` (12) | Monthly coincident on-site self-consumption ($\text{kWh}$) | | `ZeroAlloc.monthlyGrid` | `Float64Array` (12) | Monthly grid export energy ($\text{kWh}$) | | `ZeroAlloc.monthlyBat` | `Float64Array` (12) | Monthly battery discharge energy ($\text{kWh}$) | ### 1.3 Bitmask Dirty-Flag State Machine The graphics pipeline and numerical engines are decoupled via a 32-bit unsigned integer bitmask to eliminate redundant recalculations: $$\text{dirtyMask} = \bigvee_{i} \text{FLAG}_i$$ * `DIRTY_NONE = 0`: Idle state (0% CPU/GPU overhead) * `DIRTY_ASTRO = 1 << 0`: Timestamp, calendar day, or geographic position modified * `DIRTY_KINEMATICS = 1 << 1`: Tilt angle, azimuth, elevation, or individual CAD placement modified * `DIRTY_OBSTACLES = 1 << 2`: Parametric walls, parapets, roof overhang, or 3D scan geometry modified * `DIRTY_ELECTRICAL = 1 << 3`: Module rating ($W_p$), inverter AC threshold, load profile, or battery modified * `DIRTY_RENDER_ONLY = 1 << 4`: Viewport camera motion (OrbitControls) without physics state alteration ### 1.4 BVH-Accelerated Raycasting (`three-mesh-bvh`) Spatial occlusion queries between PV module cell sampling points and the solar disc utilize an Axis-Aligned Bounding Box (AABB) Bounding Volume Hierarchy. All structural obstacles (parapets, walls, ceiling slabs) are compiled into a single contiguous triangular mesh (`Unified_World_Collision_Mesh`) with identity world transformation. * **Intersection Routine:** `THREE.Raycaster.firstHitOnly = true` * **Numerical Offset:** $\text{near} = 0.005\,\text{m}$ (5 mm bias preventing self-shadowing artefacts) * **Range Limit:** $\text{far} = 120.0\,\text{m}$ (Urban obstruction boundary) * **Time Complexity:** Search complexity scales at $O(\log N)$ instead of brute-force $O(N)$ --- ## 2. Celestial Mechanics & Astronomical Core ### 2.1 Solar Position Algorithm (Spencer 1971 / DIN EN ISO 9488) For any calendar day $d_n \in [1; 365]$ and decimal UTC hour $t_{\text{utc}} \in [0.0; 24.0)$, the day angle $\Gamma_0$ (in radians) is given by: $$\Gamma_0 = \frac{2\pi (d_n - 1)}{365}$$ Solar declination $\delta$ is computed using Spencer's 7-term Fourier series (1971): $$\begin{aligned} \delta = 0.006918 &- 0.399912 \cos(\Gamma_0) + 0.070257 \sin(\Gamma_0) \\ &- 0.006758 \cos(2\Gamma_0) + 0.000907 \sin(2\Gamma_0) \\ &- 0.002697 \cos(3\Gamma_0) + 0.001480 \sin(3\Gamma_0) \quad [\text{rad}] \end{aligned}$$ The Equation of Time ($\text{EoT}$) in minutes is evaluated as: $$\begin{aligned} \text{EoT} = 229.18 \cdot \Big(&0.000075 + 0.001868 \cos(\Gamma_0) - 0.032077 \sin(\Gamma_0) \\ &- 0.014615 \cos(2\Gamma_0) - 0.040849 \sin(2\Gamma_0)\Big) \quad [\text{min}] \end{aligned}$$ Given geographic longitude $\lambda$ (degrees, East positive), Local Solar Time $t_{\text{sol}}$ and hour angle $\omega$ are: $$t_{\text{sol}} = t_{\text{utc}} + \frac{4 \cdot \lambda + \text{EoT}}{60} \quad [\text{h}]$$ $$\omega = (t_{\text{sol}} - 12.0) \cdot 15^\circ \cdot \frac{\pi}{180^\circ} \quad [\text{rad}]$$ The unrefracted geometric solar altitude $\alpha_{\text{geo}}$ above geographic latitude $\phi$ is: $$\sin(\alpha_{\text{geo}}) = \sin(\delta) \sin(\phi) + \cos(\delta) \cos(\phi) \cos(\omega)$$ $$\alpha_{\text{geo}} = \arcsin\Big(\max(-1.0, \min(1.0, \sin(\alpha_{\text{geo}})))\Big) \quad [\text{rad}]$$ Solar azimuth $\gamma_{\text{sun}}$ (measured from South positive westward according to DIN EN ISO 9488) is determined by: $$\gamma_{\text{sun}} = \operatorname{atan2}\left(\sin(\omega), \cos(\omega) \sin(\phi) - \tan(\delta) \cos(\phi)\right)$$ $$\psi_{\text{az}} = (\gamma_{\text{sun}} + \pi) \bmod 2\pi \quad (0 = \text{North}, \pi/2 = \text{East}, \pi = \text{South}, 3\pi/2 = \text{West})$$ ### 2.2 Keplerian Orbit Eccentricity & Extraterrestrial Irradiance $G_0(d_n)$ Earth's orbital eccentricity modulates extraterrestrial irradiance throughout the year. With true anomaly $\nu$ referenced to perihelion (January 3rd, $d_{\text{peri}} = 3.0$): $$\nu(d_n) = \frac{2\pi (d_n - 3.0)}{365.25}$$ Using orbital eccentricity $e = 0.0167086$ (IAU), the distance correction factor $E_0$ is: $$E_0 = \left(\frac{1 + e \cos(\nu)}{1 - e^2}\right)^2$$ With the ASTM E-490 solar constant $G_{\text{sc}} = 1366.1\,\text{W/m}^2$ (AM0 spectrum): $$G_0(d_n) = G_{\text{sc}} \cdot E_0 = 1366.1 \cdot \left(\frac{1 + 0.0167086 \cos(\nu)}{1 - 0.0167086^2}\right)^2 \quad [\text{W/m}^2]$$ * *Extrema:* Perihelion ($d_n = 3$): $G_0 \approx 1412.5\,\text{W/m}^2$; Aphelion ($d_n = 185$): $G_0 \approx 1321.7\,\text{W/m}^2$ (seasonal spread: $6.87\%$). ### 2.3 Atmospheric Refraction Correction Near-horizon apparent solar elevation is corrected using Saemundsson’s formula (1986) calibrated for $1010\,\text{hPa}$ and $10\,^\circ\text{C}$: For $\alpha_{\text{geo}} > -0.75^\circ$ (with $\alpha_{\text{geo}}$ expressed in degrees): $$\Delta\alpha_{\text{refr}} = \frac{1.02}{\tan\left(\left(\alpha_{\text{geo}} + \frac{10.3}{\alpha_{\text{geo}} + 5.11}\right) \cdot \frac{\pi}{180^\circ}\right)} \quad [\text{arcminutes}]$$ $$\alpha_{\text{sun}} = \min\left(\frac{\pi}{2}, \alpha_{\text{geo}} + \frac{\Delta\alpha_{\text{refr}}}{60^\circ} \cdot \frac{\pi}{180^\circ}\right) \quad [\text{rad}]$$ For $\alpha_{\text{geo}} \le -0.75^\circ$, refraction is omitted ($\alpha_{\text{sun}} = \alpha_{\text{geo}}$). --- ## 3. Radiation Physics, Atmosphere & Climate Data ### 3.1 Optical Air Mass Modeling (Kasten-Young 1989 & ICAO) With solar zenith angle $\theta_z = \frac{\pi}{2} - \alpha_{\text{sun}}$, relative optical air mass $m_{\text{rel}}$ is modeled via Kasten & Young (1989): $$m_{\text{rel}}(\theta_z) = \frac{1}{\cos(\theta_z) + 0.1500 \cdot \left(93.885^\circ - \theta_z \cdot \frac{180^\circ}{\pi}\right)^{-1.253}}$$ Bounded to prevent horizon singularities: $m_{\text{rel}} \in [1.0; 20.0]$. Barometric pressure correction follows the ICAO Standard Atmosphere for terrain elevation $h_{\text{elev}}$ (meters above sea level): $$p_{\text{ratio}} = \frac{p(h_{\text{elev}})}{p_0} = \left(1.0 - \frac{0.0065 \cdot h_{\text{elev}}}{288.15}\right)^{5.255}$$ Absolute optical air mass $m$ is: $$m = \max(1.0, m_{\text{rel}} \cdot p_{\text{ratio}})$$ ### 3.2 Rayleigh Optical Thickness & ESRA Clear-Sky Model The spectrally integrated Rayleigh optical thickness $\delta_R(m_{\text{rel}})$ is evaluated via Kasten (1996): $$\delta_R(m_{\text{rel}}) = \frac{1}{6.6296 + 1.7513\,m_{\text{rel}} - 0.1202\,m_{\text{rel}}^2 + 0.0065\,m_{\text{rel}}^3 - 0.00013\,m_{\text{rel}}^4}$$ Given monthly climatological Linke turbidity $T_L(m) \in [2.0; 3.7]$ for Central Europe, the direct beam transmission coefficient $\tau_b$ is: $$\tau_b = \exp\left(-m_{\text{rel}} \cdot \delta_R(m_{\text{rel}}) \cdot T_L \cdot p_{\text{ratio}}\right)$$ Direct Normal Irradiance ($\text{DNI}$) is: $$\text{DNI} = \max(0.0, G_0(d_n) \cdot \tau_b) \quad [\text{W/m}^2]$$ Diffuse Horizontal Irradiance under clear skies ($\text{DHI}_{\text{clear}}$) uses diffuse transmission $\tau_d = \max(0.05, 0.271 - 0.294\,\tau_b)$: $$\text{DHI}_{\text{clear}} = G_0(d_n) \cdot \tau_d \cdot \cos(\theta_z) + 0.045 \cdot G_0(d_n) \cdot \sqrt{\sin(\alpha_{\text{sun}})} \quad [\text{W/m}^2]$$ $$\text{GHI}_{\text{clear}} = \text{DNI} \cdot \cos(\theta_z) + \text{DHI}_{\text{clear}} \quad [\text{W/m}^2]$$ Under standard overcast conditions (ISO 15469 / CIE S 011), direct beam is extinguished ($\text{DNI} = 0$), yielding: $$\text{DHI}_{\text{overcast}} = \text{GHI}_{\text{overcast}} = G_0(d_n) \cdot 0.22 \cdot \left(\sin(\alpha_{\text{sun}})\right)^{0.80} \quad [\text{W/m}^2]$$ ### 3.3 Erbs Diffuse Fraction Decomposition (1982) When synthesizing historical irradiance from global horizontal clearness index $k_t = \frac{\text{GHI}}{G_0 \cos(\theta_z)}$, diffuse separation follows Erbs, Klein & Duffie (1982): $$\frac{\text{DHI}}{\text{GHI}} = \begin{cases} 1.0 - 0.09\,k_t & \text{for } k_t \le 0.22 \\ 0.9511 - 0.1604\,k_t + 4.388\,k_t^2 - 16.638\,k_t^3 + 12.336\,k_t^4 & \text{for } 0.22 < k_t \le 0.80 \\ 0.165 & \text{for } k_t > 0.80 \end{cases}$$ Hard limits enforced by the engine: $\frac{\text{DHI}}{\text{GHI}} \in [0.165; 1.0]$. ### 3.4 Bimodal Perez Transposition Model (Perez et al. 1990) Plane-of-Array ($G_{\text{POA}}$) diffuse irradiance separates diffuse flux into isotropic, circumsolar, and horizon-brightening components. Geometric brightening parameters are: $$a = \max(0.0, \cos(\theta_{\text{inc}})), \quad b = \max(\cos(85^\circ), \cos(\theta_z))$$ Where $\theta_{\text{inc}} = \arccos(\mathbf{n}_{\text{mod}} \cdot \mathbf{s}_{\text{sun}})$ is the incidence angle on the PV module face. Sky brightness $\Delta$ and clearness parameter $\varepsilon$ are: $$\Delta = m \cdot \frac{\text{DHI}}{G_0(d_n)}, \quad \varepsilon = \frac{\frac{\text{DHI} + \text{DNI}}{\text{DHI}} + 1.041\,\theta_z^3}{1.0 + 1.041\,\theta_z^3}$$ The parameter $\varepsilon$ maps into 8 empirical brightness bins: | Bin $k$ | Range $\varepsilon$ | $f_{11}$ | $f_{12}$ | $f_{13}$ | $f_{21}$ | $f_{22}$ | $f_{23}$ | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | | 1 | $[1.000; 1.065)$ | $-0.008$ | $0.588$ | $-0.062$ | $-0.060$ | $0.072$ | $-0.022$ | | 2 | $[1.065; 1.230)$ | $+0.130$ | $0.683$ | $-0.151$ | $-0.019$ | $0.066$ | $-0.029$ | | 3 | $[1.230; 1.500)$ | $+0.330$ | $0.487$ | $-0.221$ | $+0.055$ | $-0.064$ | $-0.026$ | | 4 | $[1.500; 1.950)$ | $+0.568$ | $0.187$ | $-0.295$ | $+0.109$ | $-0.152$ | $-0.014$ | | 5 | $[1.950; 2.800)$ | $+0.873$ | $-0.392$ | $-0.362$ | $+0.226$ | $-0.462$ | $+0.001$ | | 6 | $[2.800; 4.500)$ | $+1.132$ | $-1.237$ | $-0.412$ | $+0.288$ | $-0.823$ | $+0.056$ | | 7 | $[4.500; 6.200)$ | $+1.060$ | $-1.600$ | $-0.359$ | $+0.264$ | $-1.127$ | $+0.131$ | | 8 | $[6.200; \infty)$ | $+0.678$ | $-0.327$ | $-0.250$ | $+0.156$ | $-1.377$ | $+0.251$ | Brightening factors $F_1$ (circumsolar) and $F_2$ (horizon) are: $$F_1 = \max(0.0, f_{11} + f_{12}\Delta + f_{13}\theta_z), \quad F_2 = f_{21} + f_{22}\Delta + f_{23}\theta_z$$ The POA diffuse flux components are: $$G_{\text{diff,circum}} = \text{DHI} \cdot F_1 \cdot \frac{a}{b}$$ $$G_{\text{diff,sky}} = \text{DHI} \cdot \left((1 - F_1) \left(\frac{1 + \cos\beta}{2}\right) \cdot \text{SVF} + \max(0, F_2) \sin\beta \cdot \text{SVF}\right)$$ $$G_{\text{ground}} = \text{GHI} \cdot \rho_{\text{albedo}} \cdot \left(\frac{1 - \cos\beta}{2}\right)$$ Where $\beta$ is surface tilt from horizontal and $\rho_{\text{albedo}}$ is ground albedo (default $\rho = 0.20$; temperature-driven snow albedo when $T_{\text{amb}} \le 2\,^\circ\text{C}$: $\rho = 0.20 + \min(0.12, (2 - T_{\text{amb}}) \cdot 0.03)$). ### 3.5 Anisotropic Sky View Factor (SVF) via 64-Ray Fibonacci Dome Each PV module computes an anisotropic $\text{SVF}$ to account for sky obstruction from overhangs and side walls. 64 sampling rays are distributed over the hemisphere using a Fibonacci spiral: $$\mathbf{r}_k = \begin{pmatrix} \sqrt{1 - z_k^2} \cos(\phi_k) \\ z_k \\ \sqrt{1 - z_k^2} \sin(\phi_k) \end{pmatrix}, \quad z_k = \sqrt{\frac{k + 0.5}{N}}, \quad \phi_k = 2\pi k \cdot \frac{\sqrt{5} - 1}{2}, \quad k \in [0; 63]$$ Vectors are transformed into world space via the module's rotation quaternion $\mathbf{q}_{\text{mod}}$. Only rays directed above the horizon ($y > 0$) capture sky diffuse radiation. In accordance with ISO 15469 / CIE S 011 standard overcast luminance distributions, each ray carries weight $w_k$: $$w_k = \frac{1 + 2 \sin(\alpha_k)}{3}$$ With BVH raycast binary hit visibility $T_k \in \{0, 1\}$: $$\text{SVF} = \frac{\sum_{k=0}^{63} T_k \cdot w_k}{\sum_{k=0}^{63} w_k}$$ ### 3.6 DWD Meteorological Stations, 2D-IDW & Mini-DEM Universal Solar Studio incorporates station data from the German Weather Service (DWD CDC network) across 20 reference stations. Spatial interpolation uses a 2nd-order 2D Inverse Distance Weighting (IDW): $$w_i = \frac{1}{d_i^2} = \frac{1}{(\phi - \phi_i)^2 + \Big((\lambda - \lambda_i) \cos(\phi \cdot \frac{\pi}{180^\circ})\Big)^2}$$ A bilinear Mini-DEM ($9 \times 10$ elevation grid spanning 47°N to 55°N and 6°E to 15°E) supplies local elevation $h_{\text{elev}}$. Ambient temperature is altitude-corrected via the environmental lapse rate: $$T_{\text{amb}}(m) = \frac{\sum w_i (T_{0,i}(m) + 0.0065 \cdot h_{\text{station},i})}{\sum w_i} - 0.0065 \cdot h_{\text{elev}} \quad [^\circ\text{C}]$$ Three climatological epochs are available: 1. `dwd_1991_2020`: WMO 30-year climate normal period (baseline reference). 2. `dwd_2005_2023`: 19-year average concurrent with PVGIS 5.3 SARAH-3. 3. `dwd_2015_2024`: Most recent 10-year decade (+4.6% Global Brightening relative to 1991–2020). --- ## 4. 3D Shading, Half-Cell Topology & BIPV Thermals ### 4.1 Discrete Sampling for 108 Half-Cell Modules Standard 108 half-cell modules (M10 wafer, dimensions approx. $1.76 \times 1.04\,\text{m}$) feature twin parallel sub-circuits across two halves, protected by three bypass diodes. * **Standard Sampling (24 Points):** 12 points per module half arranged in 3 diode strings $\times$ 4 sampling locations along the sub-string. * **HQ Sampling (96 Rays):** Used during complex 3D scan evaluations and dense railing grids. * *Landscape:* 3 diode strings $\times$ 2 cell rows $\times$ 16 rays $= 96$ points. * *Portrait:* 6 cell columns $\times$ 16 vertical steps $= 96$ points. ``` +-------------------------------------------------------------------+ | MODULE LANDSCAPE TOPOLOGY | | String 1: [ . . . . . . . . ] | [ . . . . . . . . ] | | String 2: [ . . . . . . . . ] | [ . . . . . . . . ] | | String 3: [ . . . . . . . . ] | [ . . . . . . . . ] | +-------------------------------------------------------------------+ <- Half 1 (X < 0) -> <- Half 2 (X > 0) -> ``` ### 4.2 Analytical Penumbra Circular-Segment Transmission The solar disc subtends an angular diameter of $2 R_{\text{sun}} \approx 32'$ ($0.533^\circ$, radius $r_s = \tan(0.266^\circ) \approx 0.00465$). When an obstacle edge partially occults the solar disc at distance $d_{\text{hit}}$, the normalized distance from center $x \in [-1.0; +1.0]$ is $x = \frac{y_{\text{top}} - y_{\text{hit}}}{d_{\text{hit}} \cdot r_s}$. Transmission is calculated via circular segment integration: $$T_{\text{ray}}(x) = \frac{\arccos(x) - x \sqrt{1 - x^2}}{\pi}$$ ### 4.3 Bypass Diode Dynamics & DIN EN 50530 MPPT Tracking For each sub-string $s \in \{0, 1, 2\}$, the photogenerated current fraction is: $$I_{\text{sub}, s} = \frac{T_{\text{half1}, s} + T_{\text{half2}, s}}{2}$$ Currents are sorted: $s_{\min} \le s_{\text{mid}} \le s_{\max}$. Bypass diode forward voltage drop follows the Shockley thermal relation: $$V_{\text{diode}}(T_{\text{cell}}) = \max\Big(0.40, \min(0.75, 0.65 - 0.0020 \cdot (T_{\text{cell}} - 25.0))\Big) \quad [\text{V}]$$ Sub-string open-circuit potential is $V_{\text{sub}} = \frac{V_{\text{cell,MPP}}}{3}$. The inverter evaluates three discrete electrical operating states: 1. **State 3 (All 3 sub-strings active, no diode conducting):** $$V_3 = V_{\text{cell,MPP}}, \quad P_3 = \begin{cases} (G_{\text{dir}} \cdot s_{\min} \cdot \text{IAM} + G_{\text{diff,POA}}) \cdot V_3 & \text{if } V_3 \ge 16.0\,\text{V} \\ 0 & \text{if } V_3 < 16.0\,\text{V} \end{cases}$$ 2. **State 2 (1 diode forward-biased, weakest sub-string bypassed):** $$V_2 = 2 \cdot V_{\text{sub}} - V_{\text{diode}}, \quad P_2 = \begin{cases} (G_{\text{dir}} \cdot s_{\text{mid}} \cdot \text{IAM} + G_{\text{diff,POA}}) \cdot V_2 & \text{if } V_2 \ge 16.0\,\text{V} \\ 0 & \text{if } V_2 < 16.0\,\text{V} \end{cases}$$ 3. **State 1 (2 diodes forward-biased, two sub-strings bypassed):** $$V_1 = 1 \cdot V_{\text{sub}} - 2 \cdot V_{\text{diode}}, \quad P_1 = \begin{cases} (G_{\text{dir}} \cdot s_{\max} \cdot \text{IAM} + G_{\text{diff,POA}}) \cdot V_1 & \text{if } V_1 \ge 16.0\,\text{V} \\ 0 & \text{if } V_1 < 16.0\,\text{V} \end{cases}$$ Global MPPT selects the maximum operating power point: $$P_{\text{MPP}} = \max(P_1, P_2, P_3)$$ * *Lockout Limit (DIN EN 50530):* If module terminal voltage drops below $16.0\,\text{V}$, the inverter channel shuts down completely ($P_{\text{MPP}} = 0$). ### 4.4 Incidence Angle Modifier (IAM) Direct beam optical reflection on solar glass uses the Martin & Ruiz parameterization (2001) with $a_r = 0.16$: $$\text{IAM}(\theta_{\text{inc}}) = 1.0 - \frac{\exp(-\cos(\theta_{\text{inc}}) / a_r) - \exp(-1 / a_r)}{1.0 - \exp(-1 / a_r)}$$ ### 4.5 BIPV Thermal Modeling (Faiman / DIN EN 61724-1) Cell operating temperature $T_{\text{cell}}$ is evaluated using Faiman’s steady-state heat balance: $$T_{\text{cell}} = T_{\text{amb}} + \frac{G_{\text{POA}}}{u_0 + u_1 \cdot v} \quad [^\circ\text{C}]$$ | Thermal Mode (`therm`) | $u_0\,[\text{W/m}^2\text{K}]$ | $u_1\,[\text{W/m}^2\text{K}/(\text{m/s})]$ | Effective Wind $v$ | Physical Description / German Meaning | | :--- | :---: | :---: | :---: | :--- | | `standard` | $29.0$ | $1.5$ | $v_{\text{DWD}}$ | Well-ventilated railing with stack effect | | `stau` | $15.0$ | $0.0$ | $0.0$ | Heat accumulation behind solid parapet / loggia (*Hitzestau*) | | `free` | $31.0$ | $2.8$ | $1.3 \cdot v_{\text{DWD}}$ | Ground/rack mount with uninhibited airflow (*Freiaufstellung*) | Temperature derating with $\gamma = -0.35\%/\text{K}$ is: $$f_{\text{temp}} = \max\Big(0.65, \min(1.10, 1.0 + (T_{\text{cell}} - 25.0) \cdot (-0.0035))\Big)$$ ### 4.6 Soiling Losses (Kimber et al. / IEC 61724-1) Tilt-dependent soiling factor $L_{\text{soil}}(\beta)$ for rainfall regimes in Central Europe is: $$L_{\text{soil}}(\beta) = \begin{cases} 0.045 & \text{for } \beta < 12^\circ \quad (\text{Puddle accumulation}) \\ 0.045 - \frac{\beta - 12^\circ}{13^\circ} \cdot (0.045 - 0.015) & \text{for } 12^\circ \le \beta < 25^\circ \\ 0.015 - \frac{\beta - 25^\circ}{45^\circ} \cdot (0.015 - 0.006) & \text{for } 25^\circ \le \beta < 70^\circ \\ 0.006 & \text{for } \beta \ge 70^\circ \quad (\text{Vertical facade self-cleaning}) \end{cases}$$ --- ## 5. Inverter Characteristics & Grid Coupling (DIN EN 50530) ### 5.1 Efficiency Curve & Quiescent Losses Inverter conversion losses follow the DIN EN 50530 polynomial formulation: $$P_{\text{loss}}(P_{\text{DC}}) = P_0 + k_1 \cdot P_{\text{DC}} + \frac{k_2}{P_{\text{nom}}} \cdot P_{\text{DC}}^2 \quad [\text{W}]$$ * $P_0 = 3.6\,\text{W}$ (Quiescent controller and driver power) * $k_1 = 0.0085$ (Semiconductor threshold and switching losses) * $k_2 = 0.0210$ (Ohmic filter and copper resistance losses) * $P_{\text{nom}} = \max(300, P_{\text{AC,limit}})$ (Nominal AC capacity, e.g., 800 W) Turn-on threshold is $P_{\text{DC,min}} = 3.5\,\text{W}$. For $P_{\text{DC}} < 3.5\,\text{W}$, $P_{\text{AC}} = 0.0\,\text{W}$. European weighted efficiency $\eta_{\text{euro}}$ evaluates to: $$\begin{aligned} \eta_{\text{euro}} = 0.03 \eta(5\%) &+ 0.06 \eta(10\%) + 0.13 \eta(20\%) \\ &+ 0.10 \eta(30\%) + 0.48 \eta(50\%) + 0.20 \eta(100\%) = 96.55\% \end{aligned}$$ ### 5.2 Sub-Hourly Clipping Integration (NREL SAM / DiOrio et al.) To capture intra-step irradiance fluctuations without sub-minute time-series computation, Gaussian variance convolution is applied around the 800 W AC rating: $$\sigma_{\text{rel}} = 0.30 \cdot \Big(4.0 \cdot k_t \cdot (1.0 - k_t)\Big), \quad \sigma = P_{\text{DC}} \cdot \sigma_{\text{rel}}$$ With $P_{\text{clip,DC}} = P_{\text{AC,limit}} + P_{\text{loss}}(P_{\text{AC,limit}})$ and normalized offset $z = \frac{P_{\text{clip,DC}} - P_{\text{DC}}}{\sigma}$: $$P_{\text{excess}} = \sigma \cdot \Big(\phi(z) - z \cdot (1 - \Phi(z))\Big)$$ Where $\phi(z) = \frac{1}{\sqrt{2\pi}} e^{-\frac{1}{2} z^2}$ and $\Phi(z) = \frac{1}{2} \left(1 + \operatorname{erf}\left(\frac{z}{\sqrt{2}}\right)\right)$. Final inverter output is: $$P_{\text{AC}} = \min(P_{\text{AC,limit}}, P_{\text{DC}} - P_{\text{loss}}) - \max(0.0, P_{\text{excess}} \cdot 0.965)$$ --- ## 6. Load Profiles, Battery Storage & Financial Mathematics ### 6.1 VDI 4655 Standard Load Profiles Household power demand $P_{\text{load}}(t)$ comprises three additive components: 1. Basal standby load $P_{\text{base}}$: $0$ to $500\,\text{W}$ (default $20\,\text{W}$). 2. Refrigeration cycle $P_{\text{fridge}}(t)$: 15 W base with diurnal temperature modulation: $$P_{\text{fridge}}(t) = 15.0 \cdot \left(1.0 + 0.20 \cos\left((t_{\text{local}} - 15.0) \cdot \frac{\pi}{12}\right)\right) \quad [\text{W}]$$ 3. User active load $\Delta P_{\text{profile}}(t)$: Stepwise profiles (`homeoffice`, `commuter`, `seniors`, `couple`, `family`, `smarthome`), normalized by $k_{\text{scale}} = \frac{W_{\text{annual}}}{W_{\text{nominal}}}$. ### 6.2 Coincident Self-Consumption (Minkowski $p$-Norm, $\beta = 3.5$) Quarter-hourly averages overestimate self-consumption due to brief unaligned power spikes. The Minkowski $p$-norm provides a non-linear coincidence correction: $$P_{\text{direct}} = P_{\text{pv}} + P_{\text{load}} - \left(P_{\text{pv}}^\beta + P_{\text{load}}^\beta\right)^{\frac{1}{\beta}} \quad \text{with } \beta = 3.5$$ $$P_{\text{self}} = \max\Big(0.0, \min(P_{\text{pv}}, \min(P_{\text{load}}, P_{\text{direct}}))\Big) \quad [\text{W}]$$ ### 6.3 LiFePO4 Battery Dispatch Engine Continuous storage capacity $C_{\text{bat}} \in [0.0; 15.0]\,\text{kWh}$ is modeled with: * **Usable Capacity:** $C_{\text{usable}} = C_{\text{bat}} \cdot 0.90$ (90% Depth of Discharge). * **Efficiency:** Charge/discharge efficiency $\eta_{\text{charge}} = \eta_{\text{discharge}} = 0.94$ (Roundtrip $\approx 88.36\%$). * **BMS Quiescent Loss:** $P_{\text{BMS}} = 6.5\,\text{W}$ (active cycling), $P_{\text{BMS}} = 2.5\,\text{W}$ (night standby). * **Operating Modes (`bat_mode`):** * `smart`: Real-time on-site load tracking, charging from $35\,\text{W}$ PV surplus. * `bypass_100` / `bypass_150`: Fixed continuous baseline export of $100\,\text{W}$ or $150\,\text{W}$; remainder charges the battery. ### 6.4 Net Present Value (NPV according to VDI 2067 / DIN EN 17463) Over economic evaluation horizon $N = 10\,\text{years}$ with retail price inflation $e_{\text{inf}} \in [0; 10]\%$, degradation $d_{\text{deg}} \in [0; 2]\%$, and discount rate $i_{\text{disc}} = 2.0\%$: $$S(y) = \left(W_{\text{self}} \cdot p_{\text{grid}} + W_{\text{feed}} \cdot p_{\text{feed}}\right) \cdot (1 + e_{\text{inf}})^{y-1} \cdot (1 - d_{\text{deg}})^{y-1}$$ $$\text{NPV}_{10} = -I_{\text{invest}} + \sum_{y=1}^{10} \frac{S(y)}{(1 + i_{\text{disc}})^y} \quad [\text{EUR}]$$ --- ## 7. skaduz: AR Horizon Scanning & Sensor Fusion ### 7.1 Magnetic Distortion & Optical Anchor Calibration Structural reinforced concrete and steel railings induce local magnetometer deflections of $15^\circ$ to $45^\circ$. skaduz bypasses internal compass sensors through optical anchoring: 1. **Sun-Anchor:** The user centers the visible sun inside the AR crosshair. Astronomical solar azimuth $\psi_{\text{sun}}(t, \phi, \lambda)$ provides absolute true-North calibration: $$\Delta\psi_{\text{offset}} = (\psi_{\text{sun}} - \psi_{\text{raw}} + 360^\circ) \bmod 360^\circ$$ 2. **Shadow-Anchor:** At high solar elevations or severe glare, the user targets the phone's projected shadow on the floor (exact $180^\circ$ inversion): $$\psi_{\text{shadow}} = (\psi_{\text{sun}} + 180^\circ) \bmod 360^\circ$$ ### 7.2 Sensor Fusion: Hybrid-Mahony AHRS & 2-Band Optical Flow Orientation updates execute at 60–120 Hz: 1. **Tilt-Invariant Yaw Rate:** $$\omega_{\text{raw}} = - \frac{\mathbf{a} \cdot \mathbf{g}}{\|\mathbf{a}\|}$$ 2. **Centripetal Acceleration Damping:** During pan motions exceeding $12^\circ/\text{s}$, centripetal acceleration corrupts the gravity vector. The tilt gain $k_{\text{tilt}}$ is suppressed by up to 92%: $$k_{\text{tilt,eff}} = k_{\text{tilt}} \cdot \left(1.0 - 0.92 \cdot \min\left(1.0, \frac{|\omega_{\text{yaw}}| - 12^\circ/\text{s}}{24^\circ/\text{s}}\right)\right)$$ 3. **2-Band Optical Flow Engine:** * *Band A (Rows 35 to 75):* Skyline silhouette edge detection. * *Band B (Rows 80 to 125):* Architectural surface texture tracking. Weighted SAD block matching and sub-pixel peak interpolation provide horizontal displacement $\Delta x_{\text{sub}}$ to correct gyroscopic drift. ### 7.3 Dynamic Programming Skyline Extraction Skyline segmentation operates via global energy minimization along a directed acyclic graph: $$C(x, y) = 210 - \Big(\text{TransitionGate}(x, y) \cdot \text{EdgeEnergy}(x, y)\Big)$$ $$\text{TransitionGate}(x, y) = P_{\text{sky}}(x, y-3) \cdot \max\Big(0.04, 1.0 - P_{\text{sky}}(x, y+3)\Big)$$ $$\text{DP}(x, y) = C(x, y) + \min_{dy \in [-7; 7]} \Big(\text{DP}(x - 1, y + dy) + \text{Penalty}(dy)\Big)$$ * *Transition Gate:* Activates only when moving from bright sky downward into dense structural obstacles, eliminating cloud halo traps. * *Airlight Immunity:* Pixels with luminance $L > 205$ and dark channel prior $\text{DCP} > 120$ are classified as sky to prevent locking onto specular solar reflections. ### 7.4 Cylindrical Slit-Scan Panorama * **Buffer Resolution:** $1440 \times 360\,\text{pixels}$ ($4\,\text{px per degree}$, $+60^\circ$ to $-30^\circ$ elevation). * **Virtual Pitch Gimbal:** Dual-rate IIR low-pass filtering stabilizes hand tremor during horizontal sweep. * **Soft-Edge Feathering:** Stamped vertical strips use a raised-cosine alpha mask to avoid seam artefacts. ### 7.5 Geometric Parallax Compensation To bridge the vertical offset between user eye height ($h_{\text{eye}} \approx 1.55\,\text{m}$) and final module mounting height ($h_{\text{mod}} \approx 0.95\,\text{m}$, $\Delta h = 0.60\,\text{m}$), observed elevation $\alpha_{\text{eye}}$ is transformed using a distance prior $D(\alpha) = \max(6.0, \min(80.0, H_{\text{prior}} / \tan(\alpha_{\text{eye}})))$ with $H_{\text{prior}} = 6.0\,\text{m}$: $$\tan(\alpha_{\text{panel}}) = \tan(\alpha_{\text{eye}}) + \frac{\Delta h \cdot S(\alpha_{\text{eye}})}{D(\alpha_{\text{eye}})}$$ Where $S(t) = t^2 (3 - 2t)$ is a $C^1$-smooth cubic transition across $[0.0^\circ; 2.5^\circ]$. ### 7.6 Standard Export Formats 1. **Stellarium Package (`.zip`):** Uncompressed PKZIP Store container generated in-memory containing `landscape.ini`, $2048 \times 512\,\text{px}$ texture `panorama.png`, and vector horizon `horizon.txt`. 2. **N.I.N.A. / KStars / Cartes du Ciel (`.hor`):** Azimuth/elevation vector profile (72 points at $5^\circ$ spacing). 3. **PVGIS / PV\*SOL (`.hor`):** Tab-separated horizon profile from $-180^\circ$ to $+180^\circ$ ($0^\circ = \text{South}$). 4. **3D Mesh (`.glb`):** Binary glTF 2.0 geometry ($R = 18.0\,\text{m}$, 144 triangles, UV mapping, closed ground baseline at $Y = 0.0\,\text{m}$). --- ## 8. Verification & Quality Assurance ### 8.1 The 41 Automated Regression Smoke-Tests Universal Solar Studio includes an automated verification harness (`window.SolarStudio.verify()`) auditing 41 test vectors against PVGIS 5.3 and 6.x SARAH-3 benchmarks: | Domain | Test ID | Reference Standard | Validation Criterion & Tolerance | | :--- | :--- | :--- | :--- | | **1. Astronomy** | `ASTRO-01` | Kepler / DIN EN ISO 9488 | $G_0(\text{Day } 3) = 1412.5\,\text{W/m}^2$, $G_0(\text{Day } 185) = 1321.7\,\text{W/m}^2$ ($6.87\%$ ratio) | | | `ASTRO-02` | Bennett / Saemundsson | Equinox culmination at Kassel: $38.676^\circ \pm 0.10^\circ$ | | | `ASTRO-03` | DIN EN ISO 9488 | Dynamic EoT azimuth shift (Nov vs. Feb): $\Delta\psi \in [7.2^\circ; 8.2^\circ]$ | | **2. Radiation** | `RAD-01` | DIN EN 61724-1 | Clear-sky $G_0$ modulation: Winter/Summer ratio $1.069 \pm 0.025$ | | | `RAD-02` | CIE Overcast Sky | Diffuse-only overcast generation: $P_{\text{DC}} \in [8\%; 30\%]$ STC | | | `RAD-03` | Kasten-Young (1989) | Optical air mass at $89^\circ$ zenith: $m \in [15.0; 20.0]$ | | | `RAD-04` | Perez (1990) | Perez stability at $5^\circ$ grazing elevation: $0 < P_{\text{DC}} < 150\,\text{W}$ | | | `RAD-05` | DWD CDC Solaratlas | Horizontal integration vs. DWD pyranometer: residual $\le 3.8\%$ | | **3. Optics** | `OPT-01` | Martin & Ruiz (2001) | Glass IAM reflection at $75^\circ$: $\text{IAM} = 1.0 - (\dots) \pm 0.01\%$ | | | `OPT-02` | VDI 3789 / Oke | 3D Raycast Sky View Factor for wall: $\text{SVF} = 0.50 \pm 0.05$ | | | `OPT-03` | ASTM E490 | Penumbra split: intermediate transmission steps $0.33 \pm 0.05$ and $0.67 \pm 0.05$ | | | `OPT-04` | NREL / PVSyst | Bifacial structure shading: delta for $1.15\,\text{m}$ vs. $15\,\text{cm}$ wall distance $\ge 0.8\,\text{W}$ | | | `OPT-05` | Kimber / IEC 61724-1 | Soiling curve: $0^\circ = 4.5\%$, $25^\circ = 1.5\%$, $90^\circ = 0.6\%$ | | **4. Thermals** | `THERM-01` | DIN EN 61724-1 / Faiman | Faiman equilibrium ($1000\,\text{W/m}^2, v=1.5\,\text{m/s}$): $\Delta T = 31.63\,\text{K} \pm 0.10\,\text{K}$ | | | `THERM-02` | IEC 60891 | Temperature coefficient $\gamma = -0.35\%/\text{K}$: $20\,\text{K}$ step $= -7.00\% \pm 0.02\%$ | | | `THERM-03` | DWD / Faiman | Wind cooling: Coast (Norderney $5.8\,\text{m/s}$) vs. Valley ($2.4\,\text{m/s}$): $\Delta T \in [4.0; 7.0]\,\text{K}$ | | | `THERM-04` | Fraunhofer ISE BIPV | Solid parapet heat accumulation vs. railing: $\Delta T \in [25.0; 40.0]\,\text{K}$ | | **5. Cells** | `CELL-01` | IEC 60904-1 | 3D Raycast bypass activation on parapet shade: $\Delta V \in [-13.0; -8.5]\,\text{V}$ | | | `CELL-02` | DIN EN 50530 | MPPT minimum voltage lockout: shutdown below $16.0\,\text{V}$ | | | `CELL-03` | IEC 60904-1 | Landscape orientation advantage on parapet shade: $\Delta P > 10\,\text{W}$ over Portrait | | **6. Inverter** | `INV-01` | DIN EN 50530 | European weighted efficiency: $\eta_{\text{euro}} = 96.55\% \pm 0.15\%$ | | | `INV-02` | VDE-AR-N 4105 | Standby threshold: $P_{\text{DC}} < 3.5\,\text{W} \implies P_{\text{AC}} = 0.0\,\text{W}$ | | | `INV-03` | DIN EN 50530 | Hardware AC clipping at $1500\,\text{W}_{\text{DC}}$: $P_{\text{AC}} = 800.0\,\text{W}$ strict | | | `INV-04` | DIN EN 50530 | Thermal inverter derating at $> 65^\circ\text{C}$: annual clipping increase $\ge 110\,\text{kWh/a}$ | | | `PAR-01` | DIN EN 50530 | Multi-MPPT: independent channel addition ($440\,\text{W} + 150\,\text{W} = 590\,\text{W}$) | | **7. System** | `SYS-01` | VDI 4655 / DIN EN 61724-1 | Dispatch integrity: annual balance error $\Delta < 0.05\,\text{kWh/a}$, autarky $25\dots 45\%$ | | | `SYS-02` | VDI 2067 / DIN EN 17463 | 10-year discounted cashflow (NPV) at $2.0\%$ interest: $847.21\,\text{EUR} \pm 0.05\,\text{EUR}$ | | | `SYS-03` | three-mesh-bvh | BVH bounds tree active and accelerated raycast bound | | | `SYS-04` | Architecture Spec | Buffer integrity: 96 quarter-hour steps, 48 Perez coefficients | | | `SYS-05` | DIN EN 61724-2 | Telemetry duration validation: flags samples below 14 days | | | `SYS-06` | First Law of Thermo | Loss waterfall energy balance: $\sum \text{Losses} + E_{\text{AC}} = E_{\text{STC,ideal}} \pm 0.1\%$ | | | `SYS-07` | RFC 3986 / ECMA-402 | URL hash parser: decoding of `%C3%BC`, NFD umlauts, and DACH cities | | **8. Storage** | `BAT-01` | VDI 4655 | LiFePO4 roundtrip efficiency including BMS: $\eta_{\text{sys}} \in [72\%; 87\%]$ | | | `BAT-02` | Invariant State | Battery state of charge invariant: $0 \le \text{SoC} \le C_{\text{usable}}$ for all time steps | | | `BAT-03` | VDI 4655 | Continuous battery capacity scaling ($2.4\,\text{kWh} \implies C_{\text{usable}} = 2160\,\text{Wh}$) | | | `WRN-01` | TÜV Rheinland | Plausibility warning triggered when storage ratio $> 4.0\,\text{kWh/kWp}$ | | **9. Benchmarks**| `BM-01` | PVGIS 5.3 SARAH-3 | Kassel 25° South open field ($2\times 440\,\text{Wp}$): $951.7\,\text{kWh/a} \pm 5.0\%$ | | | `BM-02` | PVGIS 5.3 SARAH-3 | Norderney 30° South coastal wind ($2\times 440\,\text{Wp}$): $984.3\,\text{kWh/a} \pm 5.0\%$ | | | `BM-03` | PVGIS 5.3 SARAH-3 | Freiburg 30° South Rhine valley ($2\times 440\,\text{Wp}$): $1000.7\,\text{kWh/a} \pm 5.0\%$ | | | `BM-04` | PVGIS 5.3 SARAH-3 | Kassel 90° South facade ($2\times 440\,\text{Wp}$): $731.8\,\text{kWh/a} \pm 5.0\%$ | | | `BM-05` | PVGIS 5.3 SARAH-3 | Kassel 20° East-West split ($2\times 440\,\text{Wp}$): $858.0\,\text{kWh/a} \pm 5.0\%$ | | | `BM-06` | PVGIS 5.3 SARAH-3 | Kassel 25° South quad setup ($4\times 440\,\text{Wp}$ on $800\,\text{W}$): $1654.5\,\text{kWh/a} \pm 5.0\%$ | | | `BM-07` | DWD CDC Normal | Seasonality gradient Kassel (June/December ratio): $8.12 : 1 \pm 5.0\%$ | | | `BM-08` | 3D Raycast Baseline | Kassel 25° South balcony ($0.90\,\text{m}$ parapet, $2.80\,\text{m}$ wall): $926.7\,\text{kWh/a} \pm 5.0\%$ | | | `BM-09` | DWD CDC Decade | Global Brightening verification: decade 2015–2024 yields $1032.8\,\text{kWh/a} \pm 5.0\%$ | --- ## 9. Interface & Integration Specification for LLMs ### 9.1 Semantic URL Parameters `#ai=` (Dual-Key Bilingual Mapping) URI format: `https://skaduz.de/studio/#ai=key:value;key:value;action:calc` * `loc:`: Location within Central Europe. Resolves DWD climate stations and DACH city aliases (e.g., `kassel`, `berlin`, `muenchen`, `wien`, `zuerich`). * `climate:`: Climatological baseline (`norm` = DWD 1991–2020; `recent` = DWD 2015–2024 / +4.6% Global Brightening). * `baz:<0-360>`: Facade azimuth in degrees ($180 = \text{South}$, $90 = \text{East}$, $270 = \text{West}$) [German: *Balkonausrichtung / Fassade*]. * `az:<0-360>`: PV module azimuth in degrees (defaults to `baz`). * `tilt:<0-90>`: Module tilt from horizontal ($0 = \text{flat}$, $25 = \text{optimal}$, $90 = \text{vertical}$). * `panels:<1|2|4>`: Module quantity ($1 = \text{single/table}$, $2 = \text{standard dual}$, $4 = \text{quad pack}$). * `wp:<100-800>`: Rated peak power per module in Watts (default 440 Wp TOPCon). * `inv:<400|600|800>`: Inverter AC power ceiling in Watts (default 800 W). * `orient:`: Module physical orientation. Landscape aligns bypass diodes with horizontal parapet shadows [German: *Querformat* vs. *Hochkant*]. * `wall:`: Balcony front structure. * `solid`: Opaque masonry / concrete parapet [German: *Betonbrüstung / Mauer*]. * `grid`: Open metal railings / bars [German: *Gitterstäbe / Reling*]. * `overhang:`: Upper balcony / roof slab obstruction [German: *Deckenüberstand / Loggia*]. * `therm:`: Thermal dissipation setting (Faiman parameters). * `standard`: Ventilated railing. * `stau`: Heat stagnation behind solid facade (*Hitzestau*). * `free`: Unrestricted ground mount (*Freiaufstellung*). * `bat:<0.0-15.0>`: LiFePO4 battery capacity in kWh. * `bat_mode:`: Battery dispatch strategy. * `prof:`: VDI 4655 household consumption profile. * `kwh:<200-25000>`: Annual household electricity consumption in kWh/a. * `action:`: Direct execution trigger upon 3D scene initialization. ### 9.2 Model Context Protocol (MCP) Tool Definition ```json { "name": "simulate_balcony_solar", "description": "Performs physical 3D balcony solar simulation with raytraced shading, VDI 4655 load profiles, DWD climate data, tilt optimization, and financial yield metrics.", "inputSchema": { "type": "object", "properties": { "location": { "type": "string", "description": "City name or lat,lon in Central Europe" }, "climate_period": { "type": "string", "enum": ["dwd_1991_2020", "dwd_2015_2024"] }, "facade_azimuth": { "type": "number", "description": "Building facade azimuth in degrees (180 = South, 90 = East, 270 = West)" }, "tilt_angle": { "type": "number", "description": "Module tilt from horizontal (0 to 90 degrees)" }, "panel_count": { "type": "integer", "enum": [1, 2, 4], "description": "Number of PV panels" }, "mounting_height": { "type": "number", "description": "Height of bottom edge above balcony floor in meters" }, "module_orientation": { "type": "string", "enum": ["landscape", "portrait"] }, "balcony_wall_type": { "type": "string", "enum": ["solid", "grid", "glass", "none"] }, "roof_overhang": { "type": "string", "enum": ["deep", "small", "none"] }, "annual_kwh": { "type": "integer", "description": "Annual household power consumption in kWh" }, "battery_kwh": { "type": "number", "minimum": 0.0, "maximum": 15.0, "description": "LiFePO4 storage capacity in kWh" }, "load_profile": { "type": "string", "enum": ["homeoffice", "commuter", "family", "couple", "seniors", "smarthome"] }, "action": { "type": "string", "enum": ["calc", "optimize", "print"], "default": "calc" } }, "required": ["facade_azimuth", "panel_count"] } } ``` ### 9.3 TypeScript Type Definitions ```typescript export interface SolarStudioConfig { loc?: string; climatePeriod?: 'dwd_1991_2020' | 'dwd_2015_2024'; preset?: 'balcony_south' | 'balcony_vertical' | 'loggia_south' | 'east_west_split' | 'table_oso' | 'garden_south'; lat?: number; lon?: number; az?: number; baz?: number; tilt?: number; h?: number; split?: boolean; t1?: number; a1?: number; t2?: number; a2?: number; orient?: 'landscape' | 'portrait'; modp?: 'topcon_440' | 'classic_400' | 'table_380' | 'light_330' | 'power_500' | 'custom'; panels?: 1 | 2 | 4; wp?: number; inv?: 400 | 600 | 800; therm?: 'standard' | 'stau' | 'free'; wall?: 'solid' | 'grid' | 'glass' | 'none'; overhang?: 'deep' | 'small' | 'none' | number; bat?: number; bat_max_p?: number; bat_mode?: 'smart' | 'bypass_100' | 'bypass_150'; prof?: 'homeoffice' | 'commuter' | 'seniors' | 'couple' | 'family' | 'smarthome'; kwh?: number; base?: number; price?: number; capex?: number; cost_bat?: number; feed?: number; inflation?: number; degradation?: number; action?: 'calc' | 'optimize' | 'print' | 'telemetry' | 'verify'; } export interface SolarStudioSimulationResult { valid: boolean; version: string; timestamp: string; summary_for_llm: string; metrics: { climate_period: string; annual_prod_kwh: number; self_consumption_kwh: number; grid_feed_kwh: number; battery_discharge_kwh: number; annual_savings_eur: number; autarky_pct: number; self_consumption_pct: number; usable_battery_wh: number; }; monthly: { prod_kwh: number[]; self_kwh: number[]; grid_kwh: number[]; }; waterfall_pct: { geometry_loss: number; shading_loss: number; thermal_iam_loss: number; inverter_loss: number; }; share_url: string; } ``` ### 9.4 Programmatic Headless JavaScript API ```javascript // Headless simulation execution in browser console, Puppeteer, or Playwright: const sim = window.SolarStudio.simulate({ loc: "muenchen", climatePeriod: "dwd_2015_2024", baz: 180, tilt: 25, panels: 2, wp: 440, inv: 800, bat: 1.6, prof: "homeoffice", kwh: 1800 }); console.log(sim.metrics.annual_prod_kwh); // Annual generation (kWh/a) console.log(sim.metrics.self_consumption_kwh); // Self-consumed generation (kWh/a) console.log(sim.metrics.annual_savings_eur); // Financial yield (EUR/a) console.log(sim.waterfall_pct.shading_loss); // 3D obstacle shading reduction (%) // Execute Golden-Section tilt optimizer: const opt = await window.SolarStudio.optimize({ loc: "koeln", panels: 2 }); console.log(opt.best_tilt_deg, opt.payback_years); // Execute internal 41-vector model verification harness: const audit = await window.SolarStudio.verify(); console.log(audit.meta.overallPassed, audit.meta.integrityChecksum); ```