Diplomarbeit 2026/27 · HTL Hollabrunn

Dem Boden unter die Haut schauen – ohne zu graben

Wir schicken ein bisschen Strom durch die Erde, messen winzige Spannungen und rechnen daraus aus, was darunter liegt: Schichten, Wasser, Hohlräume. Hier findest du alles zu unserem Projekt – vom Chip bis zur Heatmap.

Abteilung Elektronik · Projektteam: Fabian Schieder, Paul Eisenbock, Dorian

Projektlogo: eine Pflanze mit Wurzeln, daneben zwei Elektroden im Boden
8Elektroden pro Messung
210Elektroden-Kombinationen, die automatisch durchgeschaltet werden
24 bitAuflösung des Messwandlers – kleinster Schritt 9,3 nV
60 Vmaximale Spannung der Stromquelle
~28.000Zeilen Code (ohne mitgelieferte Bibliotheken)
6Teilprojekte: Platine, Firmware, PC-Software, Simulator, API, Web-App
1

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.

  1. 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.
  2. Eine Firmware auf einem STM32-Mikrocontroller, die einen 24-Bit-Messwandler steuert, die Verstärkung selbst einstellt und die Messwerte statistisch auswertet.
  3. 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.
  4. Einen Simulator, der das ganze Gerät samt Boden nachbildet – damit wir Software testen können, ohne dass die Hardware fertig sein muss.
  5. Eine Web-App und eine Schnittstelle für Benutzerkonten und gespeicherte Messungen.
Ehrlicher Zwischenstand (Oktober 2026)

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.

Balkendiagramm: Codezeilen und Commits pro Teilprojekt. Der Simulator ist mit rund 11.600 Zeilen das größte, die Firmware hat rund 7.800, die Desktop-App rund 6.100.
So viel Arbeit steckt drin. Gezählt ohne mitgelieferte Bibliotheken (HAL, Django …). Die Commits stammen aus dem Zeitraum Juli bis Oktober 2026 – Teile der Schaltpläne liegen in einem eigenen KiCad-Repository.
2

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.

Vier-Punkt-Messung Strom fließt von Elektrode A durch den Boden zu Elektrode B. Zwischen M und N wird die Spannung gemessen. I U A M N B Boden mit unbekanntem Widerstand ρ hier kommtder Strom rein hier wirdnur gemessen
Eine Messung. Orange: Strom (I) von A nach B. Blau: Spannung (U) zwischen M und N. Aus beiden und dem Abstand der Elektroden folgt ein scheinbarer Widerstand.

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.

Probier’s aus: Wie viele Messungen?

Kombinationen210
Dauer (ca., bei 0,18 s je Messung)38 s

Formel: 3 · n·(n−1)·(n−2)·(n−3) / 24. Unsere Firmware erzeugt diese Liste selbst. Bei 8 Elektroden sind es 210, bei 16 schon 5.460. Praktische Geräte messen deshalb nur eine Auswahl davon.

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.

Pseudotiefe Enge Elektrodenabstände ergeben einen flachen Punkt, weite Abstände einen tiefen Punkt im Dreieck der Pseudosektion. enger Abstand: flach weiter Abstand: tief Pseudotiefe jeder Punkt = 1 Messung
Pseudotiefe. Orange: Stromelektroden (A, B), blau: Spannungselektroden (M, N). Der Punkt liegt in der Mitte der vier Elektroden – je weiter sie auseinander stehen, desto weiter unten wird er eingetragen.

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.

3

Das Gesamtsystem

Von der Elektrode im Boden bis zur bunten Karte am Bildschirm sind es mehrere Stationen. So hängen sie zusammen.

Systemübersicht Elektroden im Boden sind mit der Messplatine verbunden, diese mit dem Mikrocontroller. Per USB geht es zur Desktop-App, die mit pyGIMLi rechnet, Karten zeigt und eine Web-Schnittstelle nutzt. Der Simulator kann Platine und Boden ersetzen. Boden8 Elektrodenstecken im Erdreich MessplatineMultiplexer · StromquelleVerstärker · 24-Bit-ADC STM32-Firmwaresteuert alles, misst,wertet statistisch aus USB-KabelUART, 115200 Baud PC-SoftwareQt 6 · C++17 Simulatorersetzt Platine + Boden pyGIMLiInversion in Python 8 KartenWiderstand, Wasser … Web & APIKonten, Messungen HTTPS startet alles andere ist Mathe, Löten und Geduld
Die Kette. Der Simulator kann die Platine samt Boden ersetzen: Für die PC-Software sieht er aus wie ein echtes Gerät am COM-Port.
KiCad · Altium-Bauteile
Messplatine

Spannungsversorgung, schaltbare Konstantstromquelle, 32 Halbleiter-Schalter für die Elektroden, Messverstärker.

C / C++17 · STM32F446RE
Firmware

Zustandsautomat für den Messablauf, ADC-Treiber, automatische Verstärkung, Statistik, UART-Protokoll.

C++17 · Qt 6.11 · Python
PC-Software

Gerät verbinden und konfigurieren, Inversion starten, acht Karten anzeigen, Konto anlegen.

C++17 · Qt 6 · 3D-Finite-Volumen
Simulator

Kompiliert die echte Firmware-Logik am PC und simuliert ADC, Port-Expander, Stromquelle und Untergrund.

PHP · MySQL · Django · Docker
API & Web-App

REST-Schnittstelle mit Login-Token und Messungen; Django-App für das Dashboard im Aufbau.

JSON · Python-Generator
Protokoll

Eine einzige JSON-Datei beschreibt die Sprache zwischen Gerät und PC – beide Seiten erzeugen ihren Code daraus.

4

Hardware

Zwei Sachen sind schwierig: sehr kleine Spannungen sauber zu messen – und gleichzeitig bis zu 60 Volt für die Stromquelle bereitzustellen.

Blockschaltbild der Messplatine Oben die Stromversorgung aus USB-C mit vier Schienen, unten die Signalkette von Stromquelle über Multiplexer und Elektroden zu Messverstärker, ADC und Mikrocontroller. Strom: von USB-C zu vier Spannungen USB-C PDCYPD3177 / STUSB4500 LadelogikBQ25798 → VSYS +5 V Logik · Buck TPS62160 +15 V · LT8330 + TPS7A4901 −15 V · LT8330 + TPS7A3001 60 V Compliance · LT8331 Signal: vom Strom zum Messwert StromquelleTL072 · MOSFET · LM40400,1 mA oder 1 mA Multiplexer32 Schalter AQY210EH2 × MCP23017 per I²C 8 Elektrodenjede kann A, B, M oder N sein MessverstärkerINA128 · TL072Schutzdioden BAV199, BAT54S ADS125624 bit · PGA 1 bis 64SPI, 703 kHz STM32F446RENucleo-64 · 180 MHzUART über ST-Link M, N I²C
Blockschaltbild. Nach den Schaltplänen im KiCad-Projekt (Entwurfsstand Oktober 2026). Die Platine ist als Entwurf fertig; die Messungen weiter unten wurden mit Nucleo-Board und ADS1256-Breakout aufgebaut.

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:

SchieneZweckWie erzeugt
+5 V (1 A)Logik; separat gefiltert als +5VA für den ADCAbwärtswandler TPS62160
+15 VAnalogteil (Operationsverstärker, Stromquelle)Aufwärtswandler LT8330 auf 17,6 V, danach rauscharmer Linearregler TPS7A4901
−15 VAnalogteil, negative SeiteInvertierender 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 kannAufwärtswandler LT8331, nur bei Freigabe aktiv (EN_HV)
Schaltwandler erzeugen Störungen. Darum folgt auf die ±17-V-Stufen je ein rauscharmer Linearregler und Ferritperlen. So kommt der Schaltlärm nicht in die Messung.

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).

Balkendiagramm: kleinster Spannungsschritt des ADS1256 von 596 Nanovolt bei Verstärkung 1 bis 9,3 Nanovolt bei Verstärkung 64
Auflösung des ADC. Mit 2,5-V-Referenz ist ein Schritt bei Verstärkung 1 etwa 596 nV groß, bei 64 nur noch 9,3 nV. Dafür schrumpft der Messbereich von ±5 V auf ±78 mV.

Mikrocontroller: Nucleo mit STM32F446RE

Foto des Nucleo-64-Boards von oben
Nucleo-64 (ST). Der obere Teil ist der ST-Link zum Programmieren.
  • 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)

PinFunktionGegenstelle
PA5 / PA6 / PA7SPI1 SCK / MISO / MOSIADS1256
PB0Chip SelectADS1256
PB1DRDY (Eingang!)ADS1256 meldet „neuer Wert fertig“
PB6 / PB7I²C1 SCL / SDA2 × MCP23017
PA2 / PA3USART2 TX / RXST-Link → USB → PC
PC13Stromquelle ein/ausKonstantstromquelle
5

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.

BausteinAufgabe
MeasurementManagerZustandsautomat für eine Messung; läuft kontinuierlich oder als Sweep über alle 210 Kombinationen
ElectrodeManagerErzeugt die Liste aller Vierer-Kombinationen und schaltet sie über den Multiplexer
CurrentSourceStromquelle ein/aus, Bereich 0,1 mA / 1 mA
AutoGainControllerWählt die ADC-Verstärkung automatisch
Statistics / SignalProcessorMittelwert, Standardabweichung, Median, MAD, Min/Max
ADS1256-TreiberSPI, Register, Selbstkalibrierung, DRDY-Protokoll
UartCommandBefehle vom PC annehmen, Antworten schicken (mit DMA-Empfang)
PiezoWarnton vor dem Einschalten des Stroms

Der Messablauf

Zustandsautomat Ablauf einer Messung: Ruhe, Elektroden schalten, Strom ein, Einschwingen, Vorschau, Verstärkung prüfen, Messen, Ausgabe, zurück in Ruhe. Ruhe Elektrodenschalten Warnton,Strom ein Einschwingen100 ms + 4 verworfen Vorschau20 Samples Verstärkungprüfen Messen40 Samples Ausgabe, Stromaus nächste Kombination passt nicht: ändern, neu schauen (höchstens 6 Mal, sonst Fehler) jeder Schritt hatein Zeitlimit von 5 s
Ein Messzyklus. Pro Elektrodenkombination durchläuft die Firmware diesen Automaten. Läuft ein Schritt länger als 5 Sekunden, bricht sie ab, schaltet den Strom aus und meldet einen Fehler.

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.

Gestapelter Balken: 100 Millisekunden Einschwingen, 4 Verwerfen, 20 Vorschau, 40 Messung, 17 UART – zusammen rund 181 Millisekunden
Wohin die Zeit geht. Mehr als die Hälfte eines Zyklus wartet die Firmware nur, bis der Strom und die Elektroden eingeschwungen sind – das war bei der Planung bewusst großzügig geschätzt (ca. 5,5 Messungen pro Sekunde).

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.

Skala der ADC-Aussteuerung: unter 0,30 Verstärkung erhöhen, zwischen 0,30 und 0,85 Totzone, ab 0,85 senken, ab 0,90 Clipping, Ziel bei 0,80
Die Regeln. Zwischen 30 % und 85 % bleibt die Verstärkung wie sie ist. Diese Totzone (Hysterese) verhindert, dass der Regler bei einem Signal an der Schwelle ständig hin- und herspringt.

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.

Autogain zum Ausprobieren

0 %Ziel 80 %100 % (rosa = Clipping ab 90 %)
gewählte Verstärkung×1
Messbereich±5 V
Aussteuerung0 %
kleinster Schritt596 nV

Das Programm hinter dem Schieber ist dieselbe Regel wie in der Firmware, vereinfacht: aus den sieben Stufen wird die gewählt, die das Signal dem Ziel von 80 % am nächsten bringt, ohne über 90 % zu kommen.

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.

Kurve: Rest-Brumm im Mittelwert über der Fensterlänge. Nullstellen bei 20, 40, 60 usw. Samples. 32 Samples liegen auf einem Buckel, 160 Samples auf einer Nullstelle.
Gerechnet, nicht geschätzt: |sin(π·n·f/fₛ)| / (n·sin(π·f/fₛ)) für f = 50 Hz und fₛ = 1000 SPS. Der Brumm verschwindet bei jedem Vielfachen von 20 Samples.

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.

BefehlWirkung
GET_FW_VERSION, GET_HW_INFOFirmware und Hardware identifizieren
GET_CONFIG, SET, APPLYParameter lesen, in einer Arbeitskopie ändern, erst mit APPLY übernehmen
MEASUREMENT_STARTSweep über alle Kombinationen; pro Kombination ein Ergebnis, am Ende SWEEP_DONE
DEBUG_LOOPEine Kombination endlos wiederholen – praktisch zum Messen von Rauschen
ADC_TEST, ADC_SELFTESTADC direkt messen bzw. Selbsttest des Chips, unabhängig von der Verdrahtung
PIEZO_TESTWarnton 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=….

6

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.

Zwei Balkendiagramme: Streuung der Standardabweichung sinkt von 19,3 auf 8,2 Prozent, Streuung der Mittelwerte von 77,8 auf 53,7 LSB
Die Vermutung stimmte. Messreihe 1: 54 Messungen; Messreihe 2: 82 Messungen, jeweils mit Gain 2. Die Streuung der Standardabweichung sank von 19,3 % auf 8,2 % – nahe am theoretischen Minimum von 5,6 %.

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.

Doppelt logarithmische Kurve: relativer Fehler der Messung in Prozent über der Signalspannung in Millivolt. Bei 2 Volt 0,0001 Prozent, bei 1 Millivolt 0,18 Prozent.
Faustregel: Für 0,1 % Genauigkeit braucht das Signal etwa 2 mV. Grundlage ist ein Standardfehler des Mittelwerts von rund 1,8 µV.
SpeisestromKleinste auflösbare Widerstandsänderung
0,1 mAca. 0,018 Ω
1 mAca. 0,0018 Ω
ΔR = ΔU / I mit ΔU = 1,8 µV. Gilt unabhängig von der Größe von R. Bei kleinen Signalen erhöht Autogain zusätzlich die Verstärkung.
Zum Vergleich

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.

Kurve: Unsicherheit der Standardabweichung in Prozent über der Anzahl der Samples. Bei 20 Samples 16,2 Prozent, bei 160 Samples 5,6 Prozent.
Warum nicht einfach mehr Samples? Die Unsicherheit einer Standardabweichung sinkt nur mit 1/√(2(n−1)). Von 40 auf 160 Samples gewinnt man 5,7 Prozentpunkte, kostet aber das Vierfache an Zeit.

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.
7

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.

Querschnitt des Test-Untergrunds: obere Schicht 100 Ohmmeter bis 3 Meter, darunter 50 Ohmmeter, ein kreisförmiger Block mit 10 Ohmmeter in 6 Meter Tiefe, 25 Elektroden an der Oberfläche
Der Test-Untergrund der Demo-Daten (aus dem Skript 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.

Vier Tiefenschnitte nebeneinander: spezifischer Widerstand, Leitfähigkeit, geschätzter Wassergehalt und Coverage. Die ersten drei zeigen nur den verlässlichen Bereich als Schüssel unter der Messlinie.
Tiefenschnitte aus einem Testlauf der Software (simulierte Messdaten, 140 × 70 Rasterzellen). Die Karten 1–3 zeigen nur Zellen, für die die Messung genug aussagt – der Rest ist ausgeblendet. Die Coverage (4) zeigt, warum: Oben und mittig sehen viele Messungen die Zelle, unten und am Rand kaum eine.
Karte 1 · Tiefenschnitt
Spezifischer Widerstand ρ

Das eigentliche Inversionsergebnis. Hoch = trocken, Sand, Fels, Hohlraum. Niedrig = Ton, feucht, salzig, Grundwasser.

Karte 2 · Tiefenschnitt
Leitfähigkeit σ = 1/ρ

Dieselbe Information, umgedreht: Was gut leitet, leuchtet auf.

Karte 3 · Tiefenschnitt
Wassergehalt θ

Eine Schätzung nach Archie – mit angenommenen Bodenkonstanten. Verlässlich ist nur, wo mehr oder weniger Wasser ist, nicht die genaue Prozentzahl.

Karte 4+5 · Tiefenschnitt
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.

Karte 6+7 · Pseudosektion
ρₐ gemessen und Modell

Rohdaten und die Vorhersage des fertigen Modells. Beide müssen sich ähneln.

Karte 8 · Pseudosektion
Misfit

Differenz in Prozent, mit divergierender Skala: Weiß = passt, Rot/Blau = Modell zu hoch/zu niedrig.

Drei Pseudosektionen als Dreieck: scheinbarer Widerstand gemessen, Modellantwort und Abweichung. Die Abweichung liegt zwischen minus 2,3 und plus 1,7 Prozent.
Die Prüfkarten. Gemessen und Modell sehen praktisch gleich aus, die Abweichung liegt bei etwa ±2 %. Das ist das Zeichen für eine gute Anpassung. Dieselben Karten würden große Flecken zeigen, wenn Messfehler oder ein unglaubwürdiges Modell vorliegen.

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

Kurve: Wassergehalt in Volumenprozent fällt mit steigendem spezifischen Widerstand. Der Bereich 31 bis 115 Ohmmeter unseres Testlaufs ist markiert.
Wichtig: θ ist eine eindeutige Funktion von ρ. Die Karte enthält keine neue räumliche Information, sie deutet den Widerstand nur physikalisch. Ohne Eichung vor Ort ist nur das Muster belastbar.

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.

8

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 FirmwareIm Simulator
STM32-HAL (Takt, GPIO, SPI, UART)Eigene Nachbildung mit simulierter Zeit; UART braucht so lange wie am Board
ads1256.cRegisterabbild; Samples kommen aus dem Analogteil, quantisiert auf 24 bit, mit Clipping wie am echten Chip
mcp23017.cMerkt sich, welche Elektrode welche Rolle hat – daraus kennt der Analogteil die Geometrie
main.cEigene 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:

FallGitter „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 %
Abweichung des numerischen Lösers gegenüber der analytischen Lösung. Elektroden direkt neben starken Kontrasten brauchen das feinere Gitter.
Warum das sinnvoll war

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.

9

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.

MethodePfadZweck
POST/userKonto anlegen
POST/loginAnmelden, Token erhalten
GET/userNutzerliste (mit Token)
…/surveysMesskampagnen 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
10

Was schiefging

Ein Projekt ohne Pannen gibt es nicht. Diese vier haben uns jeweils Stunden gekostet. Wir haben sie aufgeschrieben, damit sie niemand wiederholt.

Messwerte sind Unsinn, Code sieht aber gut aus

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.

Error: Debug adapter doesn't support 'hla_swd' transport

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.

Board startet nicht

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.

Fehlermeldungen kommen nie an

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.

Programm stürzt ab – aber Ergebnisse sind da

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.

11

Quiz

Neun Fragen, keine Note. Wer alles richtig hat, darf uns am Stand die Hand schütteln.

12

Stand & Ausblick

Was funktioniert, was noch fehlt und wie das Projekt entstanden ist.

Wie es entstand

  1. Juli 2026 – Firmware-Anfang21.07.Erster Commit, ADC-Treiber, kontinuierliche Messung. Die DRDY-Panne wird gefunden und behoben.
  2. Juli bis August – PC-Software und Befehlssystem23.07. – 05.08.Qt-App, Inversionspipeline, Ergebnisfenster; UART-Befehle mit DMA; Port-Expander-Treiber.
  3. August – Elektrodenverwaltung, Web-Schnittstelle11. – 28.08.Sweep über alle 210 Kombinationen, ADC-Selbsttest, API.
  4. September bis Oktober – Platine30.09. – 14.10.Schaltpläne in KiCad: Versorgung, Stromquelle, Multiplexer, Messverstärker.
  5. 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

BereichStand
Firmware (Messablauf, Autogain, Statistik, Elektroden, Protokoll)läuft; am Nucleo mit ADC erprobt und im Simulator getestet
PC-Software mit Inversion und 8 Kartenläuft
Simulatorläuft, inklusive 3D-Löser und Szenarien
MessplatineSchaltpläne entworfen; Aufbau und Test am echten Boden stehen noch aus
Feldmessungoffen – die Bilder auf dieser Seite sind simuliert
Web-Appim 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

BereichWomit
MikrocontrollerSTM32F446RE, STM32CubeMX/HAL, CMake, Ninja, arm-none-eabi-gcc, OpenOCD
SchaltungenKiCad; Bauteile von Texas Instruments, Analog Devices, Microchip, Panasonic, Infineon, ST
PC-SoftwareC++17, Qt 6.11 (Widgets, SerialPort, Network), MinGW
InversionPython 3.11, pyGIMLi, NumPy
SimulatorC++17, Qt 6, eigener 3D-Finite-Volumen-Löser mit CG-Verfahren
WebPHP 8.4, MySQL; Django, PostgreSQL 16, Docker; Caddy
ZusammenarbeitGit (eigener Gitea-Server), JetBrains CLion

Das Team

Fabian SchiederFirmware, PC-Software, Simulator, Web
Paul EisenbockSchaltungsentwurf, PC-Software
DorianSchaltungsentwurf, Firmware

Du hast Fragen? Frag uns einfach am Stand – wir erklären gern.

↑ nach oben