# Modus-2-Solver: achsenweise Laengen-Bilanz Status: **ERLEDIGT 2026-10-29.** Gefaltete Laeufe (U-Form) werden gebaut; am selben Pfad gemessen 0.56 mm (9 Grad) und 0.7 mm (12 Grad) quer, beide Regressionsketten weiter OK. Der Abschnitt "Stand 2026-10-29" und der "Nachtrag 2026-10-29" am Ende beschreiben Loesung und Herleitung. Die Datei bleibt BEWUSST liegen, obwohl der Auftrag abgeschlossen ist: vier Kommentare in `Lisp/vf_linienzug.lsp` verweisen auf diesen Pfad (Suche nach `modus2-achsenweise-bilanz`). Sie dokumentiert damit nicht mehr einen Plan, sondern WARUM der Solver so bilanziert, wie er es tut - einschliesslich der fehlgeschlagenen Versuche, damit sie niemand ein zweites Mal unternimmt. Alles unterhalb dieser Zeile ist der urspruengliche Plan von 2026-09-18 und seine Zwischenstaende. Die dort genannten Zeilennummern sind veraltet; Phase B von `vf-linienzug-modus2` findet man per Suche nach `climber-span`. Die damals vorgeschlagene Zwischenloesung (gefaltete Laeufe mit Meldung abweisen) wurde NICHT umgesetzt und ist gegenstandslos - solche Laeufe funktionieren jetzt. ## Kurzfassung Der Modus-2-Solver (`vf-linienzug-modus2`, Phase B, `Lisp/vf_linienzug.lsp` ca. Zeile 9915-10145) modelliert den VarioFoerderer-Lauf als EINE gerade Bruecke. Bei einer gefalteten Kette (U-Form: hoch, quer, runter) zieht er die festen Fussabdruecke aus der falschen Achse ab: **die erste GF wird zu lang, die Kletterstrecke zu kurz, Motor/ES landen falsch bzw. fehlen.** Der Fix: Laengen pro Schenkelrichtung bilanzieren statt als eine skalare Spanne. Das ist ein **dokumentiertes v1-Naeherungs-Limit**, kein Regressionsfehler - die Umbauten SEGS/Alert-Box/Mini-Filter haben Phase B nicht angefasst. ## Symptom (echter Testfall: results/test_modus2.dxf, logs/vfl_modus2.dbg) U-Form-Kette, 6 Segmente, EIN VF-Lauf (Seg 2-6; die zwei Vario-Kurven zaehlen als VF-Mitglieder): ``` ^ Seg2 VF (1500 mm) | Seg1 GF (2500 mm) start Seg4 VF (2257 mm) | +-----------------------+ | Seg3 Kurve Seg5 Kurve | | | Seg6 VF (3800 mm) + v Ziel (3520, 180) ``` Ergebnis: `SOLL-ENDE=(3520, 180, 2000)`, `IST-ENDE=(3333, 2825, 2080)` -> `dY=+2645 mm`, `dZ=+80 mm`. Die erste GF wird zu lang erzeugt; die Kletterstrecke (Seg 6) endet ~2645 mm zu frueh; Motorstation, das VF-Kurven-Zwischenstueck und das ES-Element sitzen falsch bzw. fehlen. ## Ursache, praezise lokalisiert Der Solver waehlt die laengste VF-Gerade (Seg 6, 3800) als Kletterer, der die ganze Hoehe traegt, und rechnet die geneigte Laenge skalar: ```lisp ;; vf_linienzug.lsp:9990 - Solver bekommt die SKALARE Spanne (setq wahl3 (vfl-zsolve-winkel-waehlen climber-span dH-adj feste-vf)) ;; feste-vf = Umlenk + Separator (+ Motor) -- ein fester Fussabdruck ;; vf_linienzug.lsp:10070 - Kletterer bekommt br-lvf proportional (setq this-lvf (max clamp (* br-lvf (/ (caddr seg) climber-span)))) ;; br-lvf = climber-span MINUS feste-vf ;; ABER: Umlenk/GF1/Motor sitzen physisch in ANDEREN Schenkeln ;; (GF1+Umlenk am Eingang entlang hz=90, nicht in Seg6/hz=-90) ``` **Der Modellbruch:** `br-lvf` = `climber-span` minus die festen Fussabdruecke (Umlenk 500 + Separator 300 + GF1 `gf-total` + Motor). Diese Teile liegen aber in den ANDEREN U-Schenkeln - nicht in Seg 6. Der Solver zieht sie trotzdem von Seg 6s 3800er-Spanne ab. Weil GF1 = "alles am Einlauf" gewaehlt war, ist `gf-total` gross -> Seg 6 wird um genau diese Summe (~2645 mm) zu kurz. Bei einer GERADEN Bruecke liegen alle Teile auf derselben Achse - dann stimmt die skalare Rechnung. Bei der U-Form nicht. Zusaetzlich: die flache Zone nimmt GENAU EIN Uebergangspaar an (`hor-pairs = 1`, Zeile 9950), obwohl die U-Form zwei 90-Grad-Kurven plus Kletterstrecke mischt -> daraus die Rest-dZ von +80 mm. ## Beleg: dokumentiertes Limit, kein Regressionsfehler | Kommentar-Fundstelle | Aussage | |---|---| | `vf_linienzug.lsp:9073-9075` | "v1-Naeherung Laenge ... feinere Laengen-Reservierung -> spaeter" | | `vf_linienzug.lsp:9923-9926` | Modell explizit "EIN Vario mit Horizontal-Mitte" - eine gerade Bruecke ist die Design-Annahme | | `vf_linienzug.lsp:9948-9950` | "flache Zone hat GENAU EIN Uebergangspaar ... unabhaengig von der Zahl der Fueller/Kurven" | Verifiziert: SEGS-Umbau, Alert-Box und Mini-Filter haben Phase B (den Solver) nachweislich nicht veraendert. Die Abweichung ist vorbestehend. ## Vorgeschlagener Umbau in sicheren Etappen Nach jeder Etappe eine BricsCAD-Sichtpruefung (Geometrie ist nur interaktiv pruefbar). 1. **Regressionsnetz zuerst.** Eine bekannt-gute GERADE Modus-2-Kette (GF...VF...GF, eine Achse) bauen und mit `lib/dxf_vf_abbild.py --schreibe-referenz` als Referenz einfrieren. Schuetzt den funktionierenden Normalfall, bevor die Bilanz umgebaut wird. 2. **Schenkel erkennen.** Den VF-Lauf (Seg `vf-start`..`vf-ende`) an den Vario-Kurven in Schenkel aufteilen - jeder Schenkel eine Fahrtrichtung (hz). Pro Schenkel: Summe der VF-Geraden-Laengen, welche festen Teile darin liegen. Neue Datenstruktur statt der skalaren `climber-span`. (ersetzt die climber/nonclimber-Schleife 9935-9947) 3. **Fussabdruecke dem richtigen Schenkel zuordnen** (Risiko-Kern). Umlenk/GF1 nur vom Eingangs-Schenkel abziehen, Motor/GF2/ES nur vom Ausgangs-Schenkel - nicht pauschal von der Kletterstrecke. Reicht ein Schenkel nicht, verteilt sich die Restneigung auf weitere Schenkel. (feste-vf/dH-adj 9978-9989, this-lvf 10070, fill-len 10094-10104) 4. **Uebergangspaare pro Kurve** statt pauschal eins. `hor-pairs` aus der tatsaechlichen Schenkel-/Kurvenzahl ableiten - behebt die dZ-Restabweichung. (9950, dH-adj-Bildung 9982-9989) 5. **Verifikation.** Regressionsnetz aus Schritt 1 muss gruen bleiben (gerader Fall unveraendert). U-Form interaktiv: erste GF korrekt kurz, Kletterstrecke trifft den Zielpunkt, Motor + Kurven-Zwischenstueck + ES an der richtigen Stelle. SEGS-Journal bleibt formgleich. ## Risiko-Einschaetzung - Der GERADE Fall funktioniert heute - er ist der Normalfall, fuer den der Solver gebaut ist. Ein Umbau der Kern-Bilanz kann ihn brechen -> Schritt 1 (Referenznetz) ist nicht optional. - Geometrie nur interaktiv in BricsCAD pruefbar -> mehrere Runden noetig. - Gut eingegrenzt: der Umbau bleibt in Phase B von `vf-linienzug-modus2` (~9915-10145). Klassifizierung, SEGS-Journal, Doppelklick-Replay und die anderen Modi bleiben unberuehrt. ## Zwischenloesung (falls der Umbau nicht sofort kommt) Gefaltete VF-Laeufe (mehr als eine Achsenrichtung im VF-Bereich, z.B. U-Form) erkennen und mit klarer Meldung abweisen, statt still falsche Geometrie zu bauen - analog zur bereits vorhandenen "nur EIN VF-Lauf"-Abweisung (`vfl-m3-vf-lauf-alert`). Macht das Limit ehrlich sichtbar, kleiner Eingriff. --- ## Stand 2026-10-27 (nach Commit ce4ad0f) **Teilweise entschaerft, Kern bleibt offen.** Die Budget-Arbeit vom 26./27.10. hat genau das Prinzip eingefuehrt, das dieses Dokument fordert - aber nur fuer DREI Posten. Sie werden jetzt dem Segment zugeschlagen, auf dem sie physisch stehen, statt skalar von der Gesamtspanne abgezogen zu werden: | Posten | wie | Stelle | |---|---|---| | AS-Element | gemessener Fussabdruck, nur `vf-start` | `as-along-fix` | | Abschlussbogen + Motorstation | nur `vf-ende` | `abschluss-fp` | | Eck-Differenz (gezeichneter Bogen gegen Bauteil) | Alist je Segmentindex | `vfl-eck-korrekturen` / `vfl-eck-extra` | `vfl-eck-extra` ist dabei bereits die hier geforderte Form: ein Zuschlag **je Segment**, nicht ein Skalar fuer den ganzen Lauf. Er fliesst in alle vier Budgets (Spannweite, Kletterer, Fueller, Rueckanker). **Skalar geblieben sind genau die zwei Posten, die den U-Form-Fehler verursachen:** - `feste-vf` (Umlenkstation 500 + Separator 300, ggf. + Motor) - wird in `vfl-zsolve-winkel-waehlen` als EIN Wert uebergeben - `gf-total` (GF1) - bei "alles am Einlauf" gross, und genau diese Summe fehlt dem Kletterer im anderen Schenkel Das oben beschriebene Symptom (dY = +2645 mm) bleibt daher bestehen. Der naechste Schritt waere, diese beiden ebenfalls dem Segment zuzuordnen, auf dem sie stehen - also dieselbe Umstellung wie bei AS und Motorstation, nur fuer den Lauf-EINGANG. Hinweis zur Fehlersuche: Seit ce4ad0f meldet die Konsole jeden Zuschlag namentlich (`AS-Fussabdruck ... von Segment N abgezogen`, `Abschluss-Fussabdruck ...`, `Eck-Korrektur ... auf Segment N`). Eine FEHLENDE Zeile ist das Warnsignal - so wurde ein 2,4-mm-Rest gefunden. Fuer die U-Form-Diagnose sind diese Zeilen der schnellste Einstieg. --- ## Stand 2026-10-28: Fueller-Seite geloest, Solver-Seite offen ### Geloest und gemessen `vfl-m2-eingang-fp`: GF1 + Separator + Umlenkstation + Uebergangsbogen stehen auf dem Segment `vf-start`. Ist dieses Segment ein FUELLER (der Kletterer liegt hinter einer Kurve), bekam der Fueller bisher die volle Restlaenge, als staende dort nichts. Jetzt werden sie abgezogen. Ist das Eingangs-Segment selbst der Kletterer - der gerade Normalfall -, gibt die Funktion hart 0.0 zurueck; der funktionierende Fall kann sich also nicht aendern. Gemessen am U-Form-Testfall: **Querabweichung 8005 -> 1424 mm**, Segment 1 danach auf 0,2 mm genau belegt. ### Noch offen: der Solver rechnet GF und Stationen gegen die falsche Achse Rest 1424 mm. Segment 5 (Kletterer) legt 6475,5 mm zurueck, verfuegbar waeren 7899,8 - der Solver reserviert dort Platz fuer Umlenkstation, Separator und den GF1-Anteil, die auf Segment 1 stehen. ### Fehlgeschlagene Versuche (nicht wiederholen) Drei Anlaeufe am 2026-10-27/28, jeder an einer anderen Kopplung gescheitert: 1. **`feste-vf` kleiner uebergeben.** Geht nicht: `feste-hz` fliesst in `vf-winkel-AB` (vf_standard.lsp:241/245) sowohl als `feste*cos3` in die LAENGE als auch als `feste*sin3` in die HOEHE. Die Hoehe ist real - die Teile senken die Kette ab, egal auf welchem Schenkel sie stehen. Nur der Laengenanteil darf verschoben werden. 2. **Spanne vorab korrigieren und iterieren.** Geht nicht direkt: `vfl-zsolve-winkel-waehlen` enthaelt die WINKELFRAGE an den Nutzer - eine Iteration wuerde mehrfach fragen. Und die Korrektur ist pro Winkel verschieden, weil jeder Winkel ein anderes `L_GF` ergibt. 3. **Stiller Nachrechner nach der GF-Verteilungsfrage** (Code vorhanden, per `(setq nachrechnen-k 4)` deaktiviert). Technisch sauber: kein Dialog, Fragenfolge und Journal unveraendert, Konvergenz in 4 Runden (3278 -> 4372 -> 4737 -> 4859 -> 4899 mm). ABER er kollidiert mit **`filler-A-len`**: dieser Fueller belegt im Kletter-Segment genau den Platz, den das halbe GF1 dort frei laesst. Nimmt man GF1 aus der Kletterer-Spanne heraus, wird Fueller-A trotzdem gebaut - zusaetzlich zum echten GF1 auf demselben Segment. Gemessen: Fueller nach der Umlenkstation -369 mm (auf 100 geklemmt), Kette 746 mm daneben. Kleinerer Endfehler, aber entartete Geometrie - deshalb zurueckgenommen. ### Daraus fuer den naechsten Anlauf Der Nachrechner ist vermutlich der richtige Weg, aber **`filler-A-len` muss mitbehandelt werden**: er gehoert zur Annahme "GF1 liegt im Kletter-Segment" und darf bei gefaltetem Lauf nicht mehr entstehen. Wer das angeht, sollte beide Mechanismen zusammen betrachten, nicht nacheinander. Testfall vorhanden: U-Form 5855 / 270 / 7806 mm (Kletterer hinter zwei 90-Grad-Kurven), Soll-Querabweichung ~0, Stand heute 1424 mm. Die beiden geraden Referenzketten in `c:TEST_LINIENZUG_MODUS2` schuetzen den Normalfall. --- ## Stand 2026-10-29: Eingangs-Segment exakt, Kletterer-Segment offen ### Zusaetzlich geloest (gegenueber dem Stand vom 2026-10-28) **Fueller-A entfaellt bei gefaltetem Lauf**, und `vfl-m2-eingang-fp` zieht seitdem `br-gf1` ab statt `gf-total`. Beides gehoert zusammen: `filler-A-len` fuellt den Platz, den ein halbiertes GF1 auf DERSELBEN Achse frei laesst - er gehoert zur Annahme "GF1 und GF2 liegen auf einer Geraden". Bei gefaltetem Lauf wurde er auf dem Eingangs-Segment ZUSAETZLICH zu GF1 gebaut; zusammen mit GF2 im Kletterer-Schenkel entstanden damit 1.5 x gf-total Gefaellestrecke bei einem Budget von gf-total. Ergebnis, am U-Form-Testfall nachgerechnet (9 Grad, Verteilung 1/2+1/2): ``` Segment 1: AS 425,8 + GF1 1370,3 + Sep 299,6 + Umlenk 499,3 + Bogen 199,9 + Fueller 3153,7 = 5948,6 mm Budget: 5855 + 93,8 (Eck-Korrektur) = 5948,8 mm ``` Das Eingangs-Segment ist damit **auf 0,2 mm exakt belegt**, und im Protokoll steht nur noch EIN Fueller statt zwei. ### Was offen bleibt Das KLETTERER-Segment. Gemessen im selben Lauf: Segment 5 belegt 6965,8 mm, verfuegbar waeren 7899,8 - es fehlen **934 mm**, exakt die Endabweichung. Der Solver bekommt als Spanne 7704,16 mm und verplant darin u.a. GF1 (1370,3) sowie Umlenkstation + Separator (798,9) - Teile, die auf Segment 1 stehen. Umgekehrt enthaelt seine Spanne NICHT den Abschluss-Fussabdruck (ab_3 + Motorstation, 695 mm), weil dieser nur von FUELLER-Segmenten abgezogen wird (`fill-len`) und das Kletterer-Segment keines ist. **Der Restfehler skaliert mit `L_GF`** und damit mit dem gewaehlten Winkel - unabhaengig bestaetigt durch zwei Laeufe auf demselben Pfad: | Winkel | L_GF | Querabweichung | |---|---|---| | 6 Grad | 1093 | 90 mm | | 9 Grad | 2744 | 934 mm | Praktische Folge: Mit flachem Winkel ist der gefaltete Lauf heute brauchbar, mit steilem nicht. ### Hinweis zur Methodik fuer den naechsten Anlauf Zwei Laeufe sind nur vergleichbar, wenn **Winkel UND GF-Verteilung gleich** sind. Mehrere Messreihen dieser Sitzung waren nicht deutbar, weil sich zwischendurch der Winkel geaendert hatte und der Restfehler mit `L_GF` skaliert. Vor einer Aenderung also eine feste Kombination festlegen (Vorschlag: 12 Grad, Verteilung 1/2+1/2) und nur die vergleichen. --- ## Nachtrag 2026-10-29: Loesungsansatz vom Nutzer Der Abschnitt darueber beschreibt den Stand VOR dem folgenden Umbau; er bleibt als Herleitung stehen. Nutzer-Vorgabe: *"nach der zweiten VF-Kurve den passenden Winkel neu aus dem KS_AUS der Kurve und dem Zielpunkt rechnen"* und *"da GF2 feststeht, steht auch die fuer Auf/Ab verbleibende Laenge fest - passender Winkel plus eine ausgleichende GF"*. Das ist die Umkehrung der bisherigen Logik und trifft den Kern: bisher wurde ALLES vorab global verplant und der aufgelaufene Fehler landete am Kettenende. Richtig ist, die letzten freien Groessen aus der GEMESSENEN Ist-Lage zu bestimmen. Je nachdem, was das letzte Segment ist, sind das verschiedene Groessen: | Letztes Segment | feste Groesse | freie Groessen | |---|---|---| | flacher Fueller | - | Richtung + Fuellerlaenge | | Auf/Ab-Koerper (U-Form) | Laenge (aus dem Pfad) | Winkel (diskret) + GF-Ausgleich | ### Umgesetzt **1. Flacher Fueller als Schlussstueck** - neue Funktion `vfl-zsolve-schluss-ziel`. Bisher loeste `vfl-zsolve-es-fueller` nur die LAENGE und uebernahm die Richtung aus dem gezeichneten Pfad. Eine Laenge verschiebt die Kette aber nur ENTLANG ihrer Achse - steht der reale Kurvenausgang seitlich NEBEN der gezeichneten Geraden, laeuft die gebaute Achse parallel zur Zielachse und der Querversatz ist unerreichbar. Gibt man die Richtung mit frei, stehen zwei Unbekannte zwei Gleichungen (X und Y) gegenueber, geschlossen loesbar: ``` D = Ziel - KS_AUS(letzte Kurve) A = sqrt(|D|^2 - P^2) ; P = Querversatz des ES-Fussabdrucks fill = A - C hz = Winkel(D) - atan2(P, A) ``` `C` und `P` sind von `hz` unabhaengig, weil `vfl-zsolve-es-vektor` Vektor und Bezugsrahmen um denselben Winkel dreht - deshalb ist keine Iteration noetig. Scheitert der Solve (Ziel naeher als `P`), bleibt der bisherige Weg. Unit-Tests: `tu-tests-vfl-schluss` (file-frei ueber `es-block = nil`). **2. Eingangs-Hardware bei gefaltetem Lauf** - der am 2026-10-28 zurueck- genommene Spannen-Zuschlag ist wieder da. Begruendung fuer die Ruecknahme war die Kollision mit `filler-A-len`; dieser Blocker ist entfallen, seit Fueller-A bei gefaltetem Lauf gar nicht mehr entsteht. Zugeschlagen wird weiterhin NUR der Laengenanteil (`entry-fixed * cos3`), nie `feste-vf` selbst - dessen `sin3`-Hoehenanteil ist real. **3. Abschluss-Hardware auf dem Kletterer** (`kletter-ende-fp`) - endet der Lauf auf einem FUELLER, zieht `vfl-zsolve-es-fueller` Motorstation + Separator + ES beim Loesen der Fuellerlaenge selbst ab. Endet er auf einem KLETTERER, gibt es diesen Fueller nicht: die drei Teile werden dort gebaut, standen aber in keinem Budget. Abgezogen wird dasselbe wie in dessen Konstante `cc`, OHNE den ab_3-Bogen (der steckt in diesem Fall schon in `uebergang-fp`). **4. GF1-Fremdanteil** (Nachrechner wieder aktiv, 8 statt 4 Runden) - `gf-total` ist ein ERGEBNIS des Winkel-Solves, sein auf dem Eingangs-Schenkel stehender Teil laesst sich dort noch nicht abziehen (Henne-Ei). Der Nachrechner loest bei UNVERAENDERTEM Winkel neu und konvergiert mit Faktor ~1/3. ### Der entscheidende Punkt: 3 und 4 wirken nur GEMEINSAM | Posten | im Budget des Solvers | steht real auf dem Kletterer | |---|---|---| | GF1 | ja | nein - liegt im Eingangs-Schenkel | | Motor + Separator + ES | nein | ja | Die beiden Betraege heben sich TEILWEISE auf. Wer nur einen davon korrigiert, verschiebt den Fehler bloss in die andere Richtung - genau das war der 746-mm-Befund vom 2026-10-28, der damals wie eine Verschlechterung aussah. Gemessen am 9-Grad-Lauf: GF1 1636.9 - (Motor+Sep+ES) 1235.1 = 401.8 mm, exakt die damalige Restabweichung von 401.7 mm. ### Messergebnis | Lauf | vorher | nachher | |---|---|---| | U-Form 9 Grad | 1424 -> 934 mm | **0.56 mm** | | U-Form 12 Grad | - | **0.7 mm** | | Variante A (Vario-Kurve) | OK | OK | | Variante B (GF-Bogen) | OK | OK | Zwei verschiedene Winkel auf demselben Pfad - der Restfehler skaliert also nicht mehr mit `L_GF`, die Bilanz selbst stimmt. ### Regression auf dem Weg dorthin (Lehrstueck) `kletter-ende-fp` schlug zunaechst auch in Variante B zu und verkuerzte deren Segment 1 um 798.9 mm. Dort ist `vf-start = vf-ende = 0`: der VF-Lauf besteht aus EINEM Segment, die Segmente 2..5 sind Back-Lauf. Damit ist der Kletterer zugleich Laufende, der Abzug griff - obwohl ohne flache Zone die Motorstation bereits in `feste-vf` steckt und Separator + ES vom Back-Lauf reserviert werden. Die drei Bedingungen am `if` (`hor-pairs > 0`, `vf-ende = n-1`, `es-vorhanden`) sind deshalb keine Vorsichtsmassnahme, sondern benennen genau die Faelle, in denen sonst doppelt gebucht wird. Auffindbar war die Ursache nur, weil Segment 1 von Variante B bei `hz=0` liegt: eine Verkuerzung dieses Segments uebersetzt sich 1:1 in `dX`, und `IST - SOLL = (-799.11 | -104.68)` aus `logs/vfl_modus2.dbg` zeigte die reine X-Verschiebung.