Kurz gesagt
Wenn du nur fünf Minuten hast, lies diesen Abschnitt. Der Rest der Seite ist für alle, die es genau wissen wollen.
Die Frage: Wie sieht es unter einer Wiese, einem Acker oder einer Baustelle aus – ohne dass man ein Loch graben muss?
Unsere Antwort: Elektrische Widerstandstomographie, kurz ERT. Verschiedene Materialien leiten Strom verschieden gut. Feuchter Ton leitet gut, trockener Sand und Fels schlecht, ein Hohlraum praktisch gar nicht. Wenn wir den Widerstand an vielen Stellen messen, können wir daraus ein Bild vom Untergrund rechnen.
Was wir gebaut haben: ein komplettes Messsystem, von der Platine über die Firmware bis zur Auswertung am PC.
- Ein Messgerät. Acht Elektroden werden in den Boden gesteckt. Eine Elektronik schaltet automatisch durch, welche zwei Elektroden Strom einspeisen und welche zwei die Spannung messen.
- Eine Firmware auf einem STM32-Mikrocontroller, die einen 24-Bit-Messwandler steuert, die Verstärkung selbst einstellt und die Messwerte statistisch auswertet.
- Eine PC-Software (Qt/C++), die das Gerät steuert, die Daten in eine Rechnung mit pyGIMLi schickt und acht verschiedene Karten des Untergrunds zeichnet.
- Einen Simulator, der das ganze Gerät samt Boden nachbildet – damit wir Software testen können, ohne dass die Hardware fertig sein muss.
- Eine Web-App und eine Schnittstelle für Benutzerkonten und gespeicherte Messungen.
Die Schaltpläne der Platine sind entworfen, die Firmware läuft auf dem Nucleo-Board mit ADC und wurde am Labornetzteil vermessen, PC-Software und Simulator arbeiten zusammen. Die Ergebnisbilder auf dieser Seite stammen aus simulierten Messdaten, nicht aus einem Feldversuch. Was fertig ist und was nicht, steht in Kapitel 12.
Zum Mitmachen: vierzehn Stationen
Auf dieser Seite kannst du vieles selbst ausprobieren. Alles rechnet direkt in deinem Browser – mit denselben Formeln wie unser Simulator.
- Eigene Messung bauenElektroden zuweisen, Spannung ablesen
- Kombinationen zählenWie viele Messungen bei n Elektroden?
- 24-Bit-WandlerSpannung wird zur Binärzahl
- Warum 60 Volt?Stromquelle und Compliance
- AutogainVerstärkung automatisch wählen
- Störimpuls-TestMaximum gegen Quantil
- Messfenster-Labor50-Hz-Brumm wegmitteln
- Konfigurations-LaborWas dauert wie lange?
- TerminalBefehle ans Gerät senden
- Mini-SimulatorSweep mit Zeitraffer
- Karten-BetrachterEchte Ergebnisse, Werte ablesen
- Inversions-SpielFinde den versteckten Boden
- Archie-RechnerVom Widerstand zum Wasser
- QuizWas hast du mitgenommen?

Wie ERT funktioniert
Das Grundprinzip kennst du aus der Schule: Spannung = Widerstand mal Strom. Nur dass der Widerstand hier die Erde selbst ist.
Vier Elektroden, eine Zahl
Für eine einzelne Messung brauchen wir vier Elektroden. Über zwei davon (A und B) schicken wir einen bekannten Strom in den Boden. Der Strom sucht sich seinen Weg – in Bögen, auch in die Tiefe. Zwischen den beiden anderen Elektroden (M und N) messen wir die Spannung, die dabei entsteht. Weil bei der Spannungsmessung fast kein Strom fließt, stören die Übergangswiderstände der Elektroden kaum. Das ist der Trick der Vier-Punkt-Methode.
Aus Strom, Spannung und der Geometrie der vier Elektroden rechnet man den scheinbaren spezifischen Widerstand ρₐ aus. Für einen gleichmäßigen Boden gilt:
U = ρ · I / (2π) · ( 1/AM − 1/BM − 1/AN + 1/BN )
Das ist dieselbe Formel, die auch unser Simulator verwendet, um den „Boden“ zu berechnen.
„Scheinbar“ heißt: Das wäre der Widerstand eines gedachten, überall gleichen Bodens, der genau diese Spannung erzeugt. Echter Boden ist nie überall gleich – und genau deshalb ist er interessant.
Was verschiedene Böden leiten
Der spezifische Widerstand wird in Ω·m (Ohmmeter) angegeben. Die Werte überlappen stark, weil zum Beispiel Feuchtigkeit und Salzgehalt viel ausmachen – deshalb sind das nur grobe Richtwerte.
Viele Messungen ergeben ein Bild
Eine einzige Messung sagt wenig. Deshalb messen wir mit vielen Kombinationen: mal liegen die Elektroden eng beieinander (der Strom bleibt flach), mal weit auseinander (der Strom geht tiefer). Bei acht Elektroden gibt es 70 Möglichkeiten, vier auszuwählen, und je 3 Arten, ihnen die Rollen A/B/M/N zuzuteilen. Das macht 210 Messungen pro Durchlauf.
Pseudotiefe – das Bild vor dem Bild
Jede Messung liefert eine Zahl. Um sie in ein Bild zu zeichnen, braucht sie eine Position: Wir nehmen die Mitte der vier Elektroden als Ort und den Elektrodenabstand als „Tiefe“. Das ist reine Buchhaltung und keine echte Tiefe in Metern. Daher hat dieses Rohdatenbild immer die typische Dreiecksform.
Von den Rohdaten zum Untergrundmodell: die Inversion
Aus dem Dreieck kann man grob etwas ablesen, aber keine echten Tiefen. Dafür braucht es eine Inversion: Der Computer rät ein Bodenmodell, rechnet vorwärts aus, welche Messwerte dieses Modell erzeugen würde, vergleicht mit den echten Werten und verbessert das Modell – so lange, bis beides zusammenpasst. Wir benutzen dafür die Open-Source-Bibliothek pyGIMLi. Ob das Ergebnis zu den Daten passt, sagt der χ²-Wert: um 1 bedeutet, das Modell erklärt die Daten im Rahmen ihrer Messfehler.
Das Gesamtsystem
Von der Elektrode im Boden bis zur bunten Karte am Bildschirm sind es mehrere Stationen. So hängen sie zusammen.
Messplatine
Spannungsversorgung, schaltbare Konstantstromquelle, 32 Halbleiter-Schalter für die Elektroden, Messverstärker.
Firmware
Zustandsautomat für den Messablauf, ADC-Treiber, automatische Verstärkung, Statistik, UART-Protokoll.
PC-Software
Gerät verbinden und konfigurieren, Inversion starten, acht Karten anzeigen, Konto anlegen.
Simulator
Kompiliert die echte Firmware-Logik am PC und simuliert ADC, Port-Expander, Stromquelle und Untergrund.
API & Web-App
REST-Schnittstelle mit Login-Token und Messungen; Django-App für das Dashboard im Aufbau.
Protokoll
Eine einzige JSON-Datei beschreibt die Sprache zwischen Gerät und PC – beide Seiten erzeugen ihren Code daraus.
Hardware
Zwei Sachen sind schwierig: sehr kleine Spannungen sauber zu messen – und gleichzeitig bis zu 60 Volt für die Stromquelle bereitzustellen.
Stromversorgung: aus einem USB-C-Kabel
Das Gerät wird per USB-C Power Delivery versorgt. Ein Controller handelt mit dem Netzteil die Spannung aus, eine Ladelogik (BQ25798) macht daraus die Systemspannung VSYS. Daraus entstehen vier Schienen:
| Schiene | Zweck | Wie erzeugt |
|---|---|---|
| +5 V (1 A) | Logik; separat gefiltert als +5VA für den ADC | Abwärtswandler TPS62160 |
| +15 V | Analogteil (Operationsverstärker, Stromquelle) | Aufwärtswandler LT8330 auf 17,6 V, danach rauscharmer Linearregler TPS7A4901 |
| −15 V | Analogteil, negative Seite | Invertierender Wandler LT8330 auf −17,8 V, danach TPS7A3001 |
| 60 V (bis ca. 30 mA) | „Compliance“: Reserve, damit die Stromquelle auch durch schlechte Kontakte den Strom treiben kann | Aufwärtswandler LT8331, nur bei Freigabe aktiv (EN_HV) |
Konstantstromquelle
Damit der Widerstand aus U / I stimmt, muss der Strom bekannt und konstant sein, egal ob der Boden gut oder schlecht leitet. Eine Regelschaltung aus Operationsverstärker (TL072), Hochspannungs-MOSFET (STP10NK60ZFP, 600 V) und Spannungsreferenz (LM4040) hält den Strom fest. Zwei Halbleiter-Relais (AQY210EH) schalten zwischen 0,1 mA und 1 mA. Wenn der Boden einen hohen Widerstand hat, braucht der Strom dafür Spannung – dafür gibt es die 60-V-Schiene.
Multiplexer: 32 Schalter, 8 Elektroden
Jede der acht Elektroden kann vier Rollen haben: Strom hinein (A), Strom heraus (B), Spannung plus (M), Spannung minus (N). Das macht 8 × 4 = 32 Schalter. Wir verwenden dafür Halbleiter-Relais (PhotoMOS, AQY210EH): kein mechanisches Kontaktprellen, kein Klackern, lange Lebensdauer. Zwei Port-Expander MCP23017 steuern sie über I²C.
Damit beim Umschalten nichts flackert, schreibt die Firmware den gewünschten Zustand zuerst in ein Schattenregister und schickt ihn dann auf einmal: 4 statt rund 84 Schreibzugriffe.
Messverstärker und ADC
Die Spannung zwischen M und N ist klein – oft nur Millivolt. Ein Instrumentenverstärker INA128 misst sie differentiell und unterdrückt Störungen, die auf beiden Leitungen gleich ankommen. Dioden (BAV199, BAT54S) schützen den Eingang vor Überspannung. Danach folgt der ADS1256: ein 24-Bit-Delta-Sigma-Wandler mit eingebautem programmierbarem Verstärker (PGA, Faktor 1 bis 64).

Mikrocontroller: Nucleo mit STM32F446RE

- Kern: Cortex-M4F mit Gleitkommaeinheit, 180 MHz, 512 KB Flash, 128 KB RAM
- Belegt: laut letzter Auswertung nur rund 9 % Flash und 2 % RAM – reichlich Reserve
- Taktquelle: 8 MHz vom ST-Link statt Quarz (HSE-Bypass), per PLL auf 180 MHz
- SPI zum ADC: Modus 1, bewusst nur 703 kHz (erlaubt wären 1,92 MHz) – schnelle Flanken würden Störungen in den analogen Pfad einkoppeln
- UART: USART2 mit 115200 Baud über den ST-Link als virtueller COM-Port
- Außerdem: Piezo-Summer als Warnton, I²C für die Port-Expander, drei Pins für Stromquelle (ein/aus, Bereich)
Pinbelegung (Auszug)
| Pin | Funktion | Gegenstelle |
|---|---|---|
| PA5 / PA6 / PA7 | SPI1 SCK / MISO / MOSI | ADS1256 |
| PB0 | Chip Select | ADS1256 |
| PB1 | DRDY (Eingang!) | ADS1256 meldet „neuer Wert fertig“ |
| PB6 / PB7 | I²C1 SCL / SDA | 2 × MCP23017 |
| PA2 / PA3 | USART2 TX / RX | ST-Link → USB → PC |
| PC13 | Stromquelle ein/aus | Konstantstromquelle |
Firmware
Die Firmware ist das Gehirn des Geräts. Sie schaltet Elektroden, startet den Strom, misst, wertet aus und schickt das Ergebnis per UART an den PC.
Aufbau in Schichten
Die Firmware ist in C++17 geschrieben, der ADC-Treiber in C. Alle Objekte werden statisch angelegt – keine dynamische Speicherverwaltung, wie es bei Embedded-Code üblich ist. Ein kooperativer Ablauf ohne Betriebssystem ruft in der Hauptschleife immer wieder einen Zustandsautomaten auf, der pro Aufruf einen Schritt macht.
| Baustein | Aufgabe |
|---|---|
| MeasurementManager | Zustandsautomat für eine Messung; läuft kontinuierlich oder als Sweep über alle 210 Kombinationen |
| ElectrodeManager | Erzeugt die Liste aller Vierer-Kombinationen und schaltet sie über den Multiplexer |
| CurrentSource | Stromquelle ein/aus, Bereich 0,1 mA / 1 mA |
| AutoGainController | Wählt die ADC-Verstärkung automatisch |
| Statistics / SignalProcessor | Mittelwert, Standardabweichung, Median, MAD, Min/Max |
| ADS1256-Treiber | SPI, Register, Selbstkalibrierung, DRDY-Protokoll |
| UartCommand | Befehle vom PC annehmen, Antworten schicken (mit DMA-Empfang) |
| Piezo | Warnton vor dem Einschalten des Stroms |
Der Messablauf
Dass vor dem Einschalten des Stroms ein Warnton kommt (nicht blockierend über einen Piezo-Summer), hat einen einfachen Grund: Mit bis zu 60 V an den Elektroden soll niemand überrascht werden, der gerade im Boden herumsteckt.

Automatische Verstärkung (Autogain)
Ein ADC misst am besten, wenn sein Messbereich gut ausgenutzt ist: zu klein – er verschenkt Auflösung, zu groß – er „übersteuert“ und schneidet ab. Das Signal ist aber bei jeder Kombination anders. Deshalb nimmt die Firmware zuerst 20 Probewerte, bestimmt daraus die Signalspitze und stellt die Verstärkung so ein, dass etwa 80 % des Bereichs genutzt werden.

Eine Besonderheit: Als „Spitze“ nimmt die Firmware nicht das Maximum, sondern das 95-%-Quantil. Ein einzelner Störimpuls würde das Maximum hochziehen und die Verstärkung unnötig klein machen. Das Quantil ist gegen solche Ausreißer unempfindlich.
Wie lang ist ein Messfenster? Die Sache mit den 50 Hz
Im Raum steckt überall Netzbrummen mit 50 Hz. Bei 1000 Messwerten pro Sekunde ist eine Netzperiode genau 20 Samples lang. Wenn das Messfenster kein ganzes Vielfaches davon ist, bleibt vom Brumm je nach Startzeit ein anderer Rest übrig – der Mittelwert wackelt. Mit 20, 40, 60 … Samples kürzt sich der Brumm heraus.

Statistik, damit man den Messwerten trauen kann
Aus den 40 (oder mehr) Samples einer Messung berechnet die Firmware Mittelwert, Median, Standardabweichung (mit Bessel-Korrektur), robuste Streuung (MAD) und Minimum/Maximum. Ausgegeben werden unter anderem:
- StdDev – Rauschen eines einzelnen Samples
- StdErr = StdDev/√n – wie sehr der Mittelwert von Messung zu Messung streuen sollte
- Span – Spitze-Spitze, zeigt Ausreißer und Brumm sofort
Der Vergleich von vorhergesagter und tatsächlich beobachteter Streuung ist ein Diagnosewerkzeug: Stimmen beide überein, ist das Rauschen weiß und die Messkette am theoretischen Optimum. Liegt die Realität deutlich darüber, dominiert Drift – mehr Mitteln hilft dann nicht.
Eine Sprache für Gerät und PC
Gerät und PC-Software sprechen über eine einfache, lesbare Textschnittstelle. Wichtig: Sie ist nur an einer einzigen Stelle definiert, in der Datei ert_protocol.json. Ein kleiner Python-Generator erzeugt daraus beim Build den C++-Code für die Firmware und für Qt. Neuer Befehl? Eintrag in die JSON, und der Compiler sagt einem, wo man ihn implementieren muss. Beim Verbinden vergleicht die PC-Software die Protokollversionen und meldet Unterschiede.
| Befehl | Wirkung |
|---|---|
GET_FW_VERSION, GET_HW_INFO | Firmware und Hardware identifizieren |
GET_CONFIG, SET, APPLY | Parameter lesen, in einer Arbeitskopie ändern, erst mit APPLY übernehmen |
MEASUREMENT_START | Sweep über alle Kombinationen; pro Kombination ein Ergebnis, am Ende SWEEP_DONE |
DEBUG_LOOP | Eine Kombination endlos wiederholen – praktisch zum Messen von Rauschen |
ADC_TEST, ADC_SELFTEST | ADC direkt messen bzw. Selbsttest des Chips, unabhängig von der Verdrahtung |
PIEZO_TEST | Warnton auslösen |
Auf der Leitung sieht das so aus: BEFEHL arg1 arg2 vom PC, KEY:feld=wert,feld=wert vom Gerät. Fehler kommen immer als ERR:code=…,cmd=….
Wie genau messen wir?
Ein Messgerät ist nur so gut wie sein Nachweis. Deshalb haben wir die Messkette selbst vermessen – nicht den Boden, sondern ein Labornetzteil als ruhige Spannungsquelle.
Messreihe 1 und 2: die Hypothese
Zuerst messten wir mit 32 Samples (1,6 Netzperioden) und sahen, dass die Standardabweichung stärker streute als die Statistik erlaubt. Unsere Vermutung: Netzbrummen. Wir stellten auf 160 Samples (genau 8 Perioden) um und wiederholten die Messung.

Was bleibt: ein Rest von 8 ppm
Eine Schwankung von 53,7 LSB klingt viel. Auf einen Messwert von 6,69 Millionen Codes bezogen sind das aber nur 8 ppm. Das ist keine additive Rauschquelle, sondern eine relative Instabilität. Wahrscheinliche Ursachen: die Referenzspannung oder die Quelle selbst. Und die war ein einfaches lineares Labornetzteil, dessen Anzeige auf 10 mV genau ist. Der Aufbau misst vermutlich genauer, als das Netzteil stabil ist.

| Speisestrom | Kleinste auflösbare Widerstandsänderung |
|---|---|
| 0,1 mA | ca. 0,018 Ω |
| 1 mA | ca. 0,0018 Ω |
Die Leitfähigkeit eines Elektrolyten ändert sich um etwa 2 % pro Kelvin. 8 ppm entsprechen also einer Temperaturänderung von rund 0,0004 K. Die Elektronik ist damit nicht das Problem. Im echten ERT-Betrieb dominieren Kontaktimpedanz der Elektroden, Polarisation und die Temperatur des Bodens.

Was wir als Nächstes prüfen würden
- Trennungstest: Eingänge kurzschließen. Bleibt die Streuung bei 50 LSB, liegt es an ADC und Referenz, sonst an der Quelle.
- Batterietest: Eine Batterie über einen Spannungsteiler – kein Netzbezug, kein Ripple.
- Masseschleife: Messen mit Notebook im Akkubetrieb.
PC-Software
Die Desktop-App ist unsere Schaltzentrale: Gerät verbinden, Parameter einstellen, Daten holen, rechnen lassen und die Ergebnisse so zeigen, dass man sie lesen kann.
Was sie kann
- Gerät verbinden (seriell, 115200 Baud), Firmware- und Hardware-Info anzeigen, Konfiguration laden und speichern, Piezo testen
- Inversion starten mit pyGIMLi als Python-Unterprozess – die Oberfläche bleibt dabei bedienbar
- Acht Karten als Heatmaps mit Farbskala, echten Achsen und 1:1-Seitenverhältnis
- Benutzerkonto: Registrierung und Login gegen die REST-Schnittstelle
Gebaut ist sie mit Qt 6.11 (C++17, CMake). Ein Hauptfenster im MDI-Stil öffnet Setup-, Konfigurations- und Ergebnisfenster. Als Stil haben wir uns einen bewusst nostalgischen Look ausgesucht – das Stylesheet heißt „Luna Silver“, wie das Windows-XP-Design. Das hat ein bisschen Spaß gemacht, ist aber auch praktisch: Man sieht sofort, wo man klicken kann.
Ein paar Entscheidungen, die uns Ärger erspart haben
- Eine einzige serielle Verbindung. Ein COM-Port gehört immer nur einem. Das Hauptfenster besitzt die Verbindung und reicht sie an alle Fenster weiter, die mit dem Gerät reden.
- Python als Unterprozess. pyGIMLi in C++ einzubetten wäre fragil. Stattdessen schreibt Python seine Ergebnisse als Textdatei, C++ liest sie.
- Erfolg an der Datei erkennen, nicht am Exit-Code. Unter Windows stürzt pyGIMLi gern erst beim Beenden ab, nachdem alles fertig ist. Darum prüft die App, ob die Ergebnisdatei existiert.
- Protokoll nur an einer Stelle. Fenster kennen nur Signale wie
firmwareVersion(…), nie Befehlsstrings.
Der Weg einer Demo-Inversion
Auf Knopfdruck erzeugt ein Skript einen künstlichen Untergrund mit bekannter Wahrheit: eine obere Schicht mit 100 Ω·m, eine untere mit 50 Ω·m und einen leitenden Block mit 10 Ω·m in 6 m Tiefe. 25 Elektroden, Dipol-Dipol-Anordnung, 1 % Rauschen. Wenn die Inversion die Wahrheit ungefähr wiederfindet, funktioniert die Kette.

erzeuge_daten.py). Mit Testdatensätzen von 4 bis 256 Elektroden haben wir außerdem geprüft, wie sich die Rechnung bei verschiedenen Größen verhält.Die acht Karten
Wichtig ist der Unterschied zwischen zwei Familien von Bildern: Tiefenschnitte sind berechnete Bodenmodelle (echte Meter) – zur Interpretation. Pseudosektionen sind Rohdaten, nur angeordnet – zur Kontrolle. Wer beide verwechselt, liest Tiefen ab, die es nicht gibt.

Spezifischer Widerstand ρ
Das eigentliche Inversionsergebnis. Hoch = trocken, Sand, Fels, Hohlraum. Niedrig = Ton, feucht, salzig, Grundwasser.
Leitfähigkeit σ = 1/ρ
Dieselbe Information, umgedreht: Was gut leitet, leuchtet auf.
Wassergehalt θ
Eine Schätzung nach Archie – mit angenommenen Bodenkonstanten. Verlässlich ist nur, wo mehr oder weniger Wasser ist, nicht die genaue Prozentzahl.
Coverage
Kein Bodenwert, sondern Qualitätsmaß: Wie stark hat eine Zelle die Messung beeinflusst? Die 0/1-Version ist die „Ampel“ für die Maske.
ρₐ gemessen und Modell
Rohdaten und die Vorhersage des fertigen Modells. Beide müssen sich ähneln.
Misfit
Differenz in Prozent, mit divergierender Skala: Weiß = passt, Rot/Blau = Modell zu hoch/zu niedrig.

Probier die Karten selbst aus
Inversion zum Selberspielen
Die Inversion klingt nach Zauberei. Im Kern ist sie Raten mit System: Modell vorschlagen, vorwärts rechnen, vergleichen, verbessern. Probier’s mit einem Boden aus nur drei Zahlen – der Rechenkern ist derselbe wie im Simulator.
Zwei Details, die uns wichtig waren
Farbskalen. Der klassische Regenbogen sieht schön aus, ist aber nicht wahrnehmungsgleichmäßig und kann Strukturen vortäuschen. Wir bieten deshalb auch Viridis an. Der Misfit nutzt immer eine divergierende Skala mit symmetrischem Bereich um 0, damit Weiß wirklich „kein Fehler“ bedeutet.
Ehrlichkeit bei der Auflösung. Man kann das Bild feiner rastern, aber das erzeugt keine neue Information. Die echte Auflösung begrenzen Elektrodenabstand, die Physik (Sensitivität nimmt mit der Tiefe ab) und die Glättung der Inversion. Die Coverage-Karten zeigen offen, wo diese Grenze liegt.
Vom Widerstand zum Wasser: Archie
Für Karte 3 rechnen wir den Widerstand mit der Archie-Formel um – für einen voll wassergesättigten Boden:
θ = ( a · ρw / ρ )^(1/m)
mit ρw = 10 Ω·m (Porenwasser), a = 1, m = 1,8

Was ERT nicht kann
Aus einem Gleichstrom-Datensatz kann man nicht ableiten: Aufladbarkeit (IP), Veränderungen über die Zeit (nur eine Messung), 3D-Strukturen (wir messen ein 2D-Profil) oder Porosität und Salzgehalt als eigene Karten – dafür bräuchte es zusätzliche Daten vor Ort.
Der Simulator
Ein Messgerät zu entwickeln, bevor die Platine da ist: Das geht nur, wenn man die Platine spielt.
Unser Simulator nimmt den Pfad zum Firmware-Projekt, kompiliert dessen echte Logik als Windows-Programm und ersetzt alles, was normalerweise Hardware wäre: den ADC, die Port-Expander, die Stromquelle, die Elektroden und den Boden. Die Firmware selbst wird dabei nicht verändert. Die PC-Software öffnet einen virtuellen COM-Port (Nullmodem-Paar) und merkt keinen Unterschied zu einem echten Nucleo.
Was der Simulator kann
- Untergrund: homogen, zwei Schichten, senkrechter Kontakt – oder beliebige quaderförmige Körper mit einem 3D-Finite-Volumen-Löser. Körper kann man im Schnittbild verschieben und skalieren; Vorlagen für Erzkörper, Hohlraum, Graben, Rohr …
- Hardware-Effekte: Übergangswiderstand je Elektrode, Compliance der Stromquelle, Einschwingen, Eigenpotential, Rauschen, 50-Hz-Einstreuung, UART mit echter Baudrate, abklemmbare Elektroden
- Fehlerbilder: ADC hängt (DRDY kommt nie) oder SPI tot (liest nur 0xFF) – live zuschaltbar
- Eigene Zeit: Zeitraffer von 0,1× bis 500×. Ein kompletter Sweep mit 210 Kombinationen (≈ 35 s simuliert) dauert bei 100× unter einer Sekunde.
- Logikanalysator: Zeitleiste mit Szenario, UART in beide Richtungen, Relais, Strom, Warnton und ADC-Einstellung, zoombar bis 20 µs
- Szenarien: zeitgenaue Abläufe wie „nach 15 s fällt Elektrode 3 aus“, acht Vorlagen
- Ergebnisse: Pseudosektion gemessen/Modell/Abweichung, Export als pyGIMLi-Datei oder CSV
Probier den Mini-Simulator
Hier läuft eine stark vereinfachte Version direkt auf dieser Seite: ein Boden mit zwei Schichten, acht Elektroden und derselbe Sweep wie in der Firmware.
Wie er die Firmware täuscht
| Echte Firmware | Im Simulator |
|---|---|
| STM32-HAL (Takt, GPIO, SPI, UART) | Eigene Nachbildung mit simulierter Zeit; UART braucht so lange wie am Board |
ads1256.c | Registerabbild; Samples kommen aus dem Analogteil, quantisiert auf 24 bit, mit Clipping wie am echten Chip |
mcp23017.c | Merkt sich, welche Elektrode welche Rolle hat – daraus kennt der Analogteil die Geometrie |
main.c | Eigene Hauptschleife mit denselben Aufrufen |
Alle anderen Dateien in Core/Src übersetzt der Simulator unverändert – neue Quelldateien werden automatisch mitgebaut. | |
Stimmt die Simulation? Wir haben nachgerechnet
Für einfache Böden gibt es exakte Formeln (Bildquellenreihe, Spiegelquelle). Damit prüfen wir den 3D-Löser:
| Fall | Gitter „schnell“ | Gitter „genau“ |
|---|---|---|
| Zwei Schichten 100/20 Ω·m | Ø 0,14 %, max. 1,0 % | Ø 0,07 %, max. 0,7 % |
| Zwei Schichten 100/1000 Ω·m | Ø 0,31 %, max. 3,8 % | Ø 0,22 %, max. 4,1 % |
| Kontakt 50/500 Ω·m, Elektroden dicht daneben | Ø 2,0 %, max. 29 % | Ø 0,55 %, max. 6,8 % |
Durch den Simulator konnten wir Firmware, Protokoll und PC-Software gemeinsam entwickeln, ohne auf die Platine zu warten. Außerdem kennen wir im Simulator die richtige Antwort: Wir wissen, wie der Boden aussieht, und können prüfen, ob die Software ihn wiederfindet.
Web & Schnittstellen
Messungen sollen nicht auf einem Laptop verloren gehen. Darum gibt es Benutzerkonten und eine Schnittstelle im Netz.
REST-Schnittstelle
Die erste Schnittstelle ist in PHP geschrieben, mit MySQL dahinter. Die Desktop-App nutzt sie für Registrierung und Login. Dabei gibt es ein Token, das bei geschützten Aufrufen im Header mitgeschickt wird. Die Passwörter liegen nur als Hash in der Datenbank. Die Datenbank-Zugangsdaten liegen nicht im Quellcode und nicht im öffentlich erreichbaren Ordner.
| Methode | Pfad | Zweck |
|---|---|---|
| POST | /user | Konto anlegen |
| POST | /login | Anmelden, Token erhalten |
| GET | /user | Nutzerliste (mit Token) |
| … | /surveys | Messkampagnen und ihre Messwerte, nur für den jeweiligen Besitzer sichtbar |
Die vollständige Dokumentation der Schnittstelle liegt unter gnd-analyses.com/wiki.
Web-App (im Aufbau)
Als zweiten Schritt haben wir eine Web-Oberfläche mit Django begonnen. Sie läuft in Docker (Gunicorn und PostgreSQL 16) und hat getrennte Bereiche für Konten, Geräte, Messkampagnen und Inversionen. Derzeit sind ein Dashboard und eine Seite „Messplatz“ umgesetzt. Die App ist erreichbar unter app.gnd-analyses.com.
Wie das alles im Netz steht
- Caddy als Webserver und Reverse-Proxy, mit automatischen Zertifikaten (Let’s Encrypt)
- Automatisches Deployment: Ein Push auf den Hauptzweig im Git-Server löst über einen Webhook das Neubauen des Docker-Stacks aus
- Die Seite, die du gerade liest, ist reines HTML und CSS – ohne Cookies, ohne Tracker, mit selbst gehosteten Schriften
Was schiefging
Ein Projekt ohne Pannen gibt es nicht. Diese vier haben uns jeweils Stunden gekostet. Wir haben sie aufgeschrieben, damit sie niemand wiederholt.
Der Pin, der plötzlich ein Ausgang war
Nach dem Neugenerieren des CubeMX-Projekts lieferte der ADC wirres Zeug, obwohl „nichts geändert“ war. Ursache: In der Projektdatei stand der DRDY-Pin als Ausgang. DRDY ist aber ein Ausgang des ADC – der Mikrocontroller hielt dagegen. Alle Wartschleifen sahen dauerhaft „Low“ und lasen ohne Synchronisation.
Lehre: Nach jedem Regenerieren die Differenz im main.c ansehen. Die Projektdatei ist die Wahrheit, nicht der Code.
Flashen geht nicht
In neuen OpenOCD-Versionen heißt der Treiber anders. Die Lösung war eine einzige Zeile in der Konfiguration: transport select swd.
Der Quarz, der nicht da ist
Auf dem Nucleo-Board sitzt kein Quarz für den Hochgeschwindigkeitstakt. Den liefert der ST-Link-Chip als Rechtecksignal. Wer „Quarz“ statt „Bypass“ einstellt, bekommt einen Timeout und eine hängende Firmware. Und wer den ST-Link-Teil abtrennt, hat keinen Takt mehr.
printf schreibt ins Leere
Die Fehlerpfade benutzten printf, aber die dahinterliegende Funktion war nur als Platzhalter vorhanden. Im Disassembly war der Aufruf zu einem NOP zusammengeschrumpft. Es stürzte nichts ab – man sah nur nie eine Fehlermeldung. Eine Fehlerausgabe, die man nicht sieht, ist schlimmer als gar keine.
pyGIMLi beendet sich nicht sauber
Unter Windows stürzt die Bibliothek manchmal beim Beenden ab, nachdem sie fertig gerechnet hat. Unsere Lösung: Das Skript schreibt die Ergebnisse zuerst, die App prüft anschließend, ob die Datei existiert, statt auf den Exit-Code zu schauen.
Quiz
Neun Fragen, keine Note. Wer alles richtig hat, darf uns am Stand die Hand schütteln.
Stand & Ausblick
Was funktioniert, was noch fehlt und wie das Projekt entstanden ist.
Wie es entstand
- Juli 2026 – Firmware-Anfang21.07.Erster Commit, ADC-Treiber, kontinuierliche Messung. Die DRDY-Panne wird gefunden und behoben.
- Juli bis August – PC-Software und Befehlssystem23.07. – 05.08.Qt-App, Inversionspipeline, Ergebnisfenster; UART-Befehle mit DMA; Port-Expander-Treiber.
- August – Elektrodenverwaltung, Web-Schnittstelle11. – 28.08.Sweep über alle 210 Kombinationen, ADC-Selbsttest, API.
- September bis Oktober – Platine30.09. – 14.10.Schaltpläne in KiCad: Versorgung, Stromquelle, Multiplexer, Messverstärker.
- Oktober – Protokoll, Simulator, Web-App01. – 23.10.JSON-Protokoll als einzige Quelle, Simulator mit 3D-Löser, Docker-Stack und automatisches Deployment.
Was fertig ist, was nicht
| Bereich | Stand |
|---|---|
| Firmware (Messablauf, Autogain, Statistik, Elektroden, Protokoll) | läuft; am Nucleo mit ADC erprobt und im Simulator getestet |
| PC-Software mit Inversion und 8 Karten | läuft |
| Simulator | läuft, inklusive 3D-Löser und Szenarien |
| Messplatine | Schaltpläne entworfen; Aufbau und Test am echten Boden stehen noch aus |
| Feldmessung | offen – die Bilder auf dieser Seite sind simuliert |
| Web-App | im Aufbau |
Was wir uns als Nächstes vornehmen würden
- Absicherung: Die Warteschleifen auf das ADC-Signal haben bisher kein Zeitlimit. Ein abgezogenes Kabel würde die Firmware hängen lassen. Ein Watchdog oder ein Zähler als Abbruch schafft Abhilfe.
- Messen im Feld mit der fertigen Platine – am liebsten auf einer Fläche, wo wir wissen, was drunter liegt.
- Mehr Elektroden durch ein zweites Multiplexer-Modul.
- Schneller werden: Dauerlesemodus des ADC (RDATAC) und UART per DMA statt blockierend.
Werkzeuge
| Bereich | Womit |
|---|---|
| Mikrocontroller | STM32F446RE, STM32CubeMX/HAL, CMake, Ninja, arm-none-eabi-gcc, OpenOCD |
| Schaltungen | KiCad; Bauteile von Texas Instruments, Analog Devices, Microchip, Panasonic, Infineon, ST |
| PC-Software | C++17, Qt 6.11 (Widgets, SerialPort, Network), MinGW |
| Inversion | Python 3.11, pyGIMLi, NumPy |
| Simulator | C++17, Qt 6, eigener 3D-Finite-Volumen-Löser mit CG-Verfahren |
| Web | PHP 8.4, MySQL; Django, PostgreSQL 16, Docker; Caddy |
| Zusammenarbeit | Git (eigener Gitea-Server), JetBrains CLion |
Das Team
Du hast Fragen? Frag uns einfach am Stand – wir erklären gern.