Projekt NodeSP neu

epvpn
kln 3 years ago
parent bb3fc638cb
commit 7ae9fa32ad
  1. 164
      content/projekt/NodeSP.md
  2. BIN
      static/images/NodeSP/NodeSP1.webm
  3. BIN
      static/images/NodeSP/NodeSP_App.png
  4. BIN
      static/images/NodeSP/NodeSP_Aufbau.jpg
  5. BIN
      static/images/NodeSP/NodeSP_Bohrschablone.png
  6. BIN
      static/images/NodeSP/NodeSP_Overview.jpg

@ -0,0 +1,164 @@
---
title: NodeSP Part I (Analog)
author: kaqu
status: Aktiv
difficulty: geht so ...
time: ~4h
date: 2020-02-20
image: /images/NodeSP/NodeSP_Overview.jpg
keywords: NodeMCU,ESP32,FFT,Assembler
---
## Motivation ##
Phail hat mir - temporär - ein ESP32-Dev-Board überlassen. Auf diesem
ist ein FTDI-Chip zwecks Bereitstellung eines JTAG-Interfaces verbaut.
Seit Sommer 2019 hat PlatformIO seinen Debugger für die Öffentlichkeit
freigegeben. Beim Herumspielen in VSC zeigt sich, daß nicht nur
Source-Level Debugging möglich ist, sondern auch auf die
(Dis-)Assembler-Ebene gewechselt werden kann.
Da ließe sich doch vielleicht etwas mit anfangen?
{{< fluid_img alt="Showtime" src="/images/NodeSP/NodeSP_Overview.jpg" >}}
Wie wäre es mit einer Fingerübung in ESP32-Assembler? Eine FFT hätte
den Charme einer späteren Nutzbarkeit für verschiedenste Projekte und
wäre doch ein überschaubarer Aufwand ...
<br/>
<br/>
## Planung ##
Wichtig ist zunächst einmal, einen brauchbaren Algorithmus zu finden.
Wenn ein Schneller gefunden ist, könnte dieser als Re-Implementierung
in ESP32-Assembler vermutlich alle anderen wegblasen?!
+ Anforderungen:
+ Der verwendete Algorithmus sollte hinreichend allgemein einsetzbar sein,
d.h. die Meßwertblöcke sollten als 2er-Potenzen formuliert werden
können.
+ Außerdem sollte mit echten Fließkommazahlen gearbeitet werden
(der ESP32 unterstützt 32-Bit IEEE754 mit 16 Registern native).
+ Für die Meßwerte sollen keine Vorinformationen vorliegen (d.h. beliebige
Daten sollen verarbeitet werden können).
<br/>
<br/>
## Ausführung Testprogramm FFT ##
Für die Geschwindigkeitsmessung habe ich zunächst ein Testprogramm in C(99)
erstellt. Dies soll zunächst verschiedene Algorithmen bzw. deren Implementierungen vergleichen,
später wird hiermit auch die Effizienz der eigenen Implementierung getestet. Es soll immer der
gleiche Testmeßdatensatz verwendet werden, für den die korrekten Ergebnisse vorab bekannt sind.
So wird die Korrektheit der Implementierung verifiziert.
Nachdem in meinem Vergleichsfeld ein 'schnellster' Algorithmus ermittelt ist (es liegen mehrere
10er-Potenzen - in [µs] gemessen - zwischen den verschiedenen Implementierungen), habe ich diesen
in 'native' ESP32 umgeschrieben (für mathematisch Interessierte: http://www.katjaas.nl/home/home.html).
Es zeigt sich, daß die aktuelle Kombination VSC/PlatformIO/Xtensa-Debugger
noch reichlich 'buggy' ist. Beim Single-Stepping durch den Code kommt es immer wieder zum 'Rausfliegen'
(Rücksprung in die übergeordnete Funktion). Außerdem klappt es mit dem Disassemblieren häufig nicht so
recht, d.h. Opcodes werden falsch gelesen bzw. an 'falschen' Adressen mit der Disassembly begonnen
(erkennbar häufig an der komplett sinnfreien Bedeutung des Codes, gelegentlich auch an eingefügten
.byte-Instruktionen - die hier eigentlich nichts verloren haben ...).
Trotz dieser Widrigkeiten habe ich schließlich eine funktionierende Version realisiert.
Ergebnis:
Der Speedup sinkt sehr schnell von 2.2 (für 8 Meßwerte) auf 1.1 (ab 256 Meßwerte & mehr). Mmmh,
nicht so überzeugend (nur 10%) für den Aufwand (ich hatte mit einem Speedup von 2-5 gerechnet!). Nach einigem
Kopfkratzen bin ich zu folgenden Erkenntnissen gelangt:
+ Der limitierende Faktor ist vermutlich der Speicherzugriff. Der ESP32 hat keinen Cache, d.h. alle
Speicherzugriffe bremsen unmittelbar. Bei größeren Meßwertmengen schlägt das überproportional durch
(Speicherzugriffe von C<->Assembler sind aufgrund der leistungsfähigen Befehle des 'Instruction Sets'
gleich schnell).
+ Moderne Prozessoren (ESP32 gemäß Doku eine 'post-RISC Architecture') haben sehr leistungsfähige
Befehle & vergleichsweise viele Register (hier 16 'universelle' in einem Registerfile von 64 und
16 FP-Register - sowie diverse andere hier nicht so Relevante). Früher war das mal anders ... (6502,
68k etc.)! Letztlich kann dadurch der Compiler recht gut optimieren, der Gewinn durch 'Metawissen' seitens
des Programmierers (also was man weglassen darf u.ä.) ist marginal.
+ Die speziellen Matrix-Support Operationen (multiply/add w/ storage pointer increment et.al.)
passten leider nicht zu dem von mir favorisierten Algorithmus (dumm gelaufen!).
Fazit: Nett, aber (weitgehend) sinnfrei! Eigentlich ist das zwar der Stand der Erkenntnisse (in der
Informatik), aber schön, das wir das noch einmal überprüft haben ...
Jetzt brauchen wir noch etwas 'zum Anfassen' ...
<br/>
<br/>
## Ausführung 'Spectrum Analyzer' (SP) ##
Naheliegend für einen Realitätscheck ist natürlich der Aufbau eines 'Spectrum Analyzers', so eine
Art Equalizer wie man es von Audio-Apps, Hifi-Anlagen (oder dem Autoradio) kennt - nur ohne
Eingriffsmöglichkeit.
{{< fluid_img alt="Aufbaubild" src="/images/NodeSP/NodeSP_Aufbau.jpg" >}}
Aus alten Beständen hatte ich noch die LED-Streifen (WS2812) aus einem Sonderangebot. Hier fällt etwas
Lötarbeit an (& die Heißklebepistole kommt auch zu ihrem Recht).
{{< fluid_img alt="Bohrschablone" src="/images/NodeSP/NodeSP_Bohrschablone.png" >}}
Für das Gehäuse habe ich eine Bohrschablone mit FreeCAD erstellt, die wir auf der neuen 'Großfräse' der
Innovationswerkstatt dann ausgeführt haben.
Neben dem Gehäuse habe ich eine Mikrofonbaugruppe mit eingebauter Verstärkung (40..60dB) sowie
einen Level-Shifter (3,3<->5V) sowie eine kleine Platine zusätzlich beschafft.
Referenzen: Adafruit MAX9814-debo-amp-mic2, DEBO LEV SHIFTER
Da ich alle meine Projekte bis dato auf NodeMCUs (& esp-idf Framework) realisiert habe, muß jetzt
ein passendes Modul ('sampling') in 'C' erstellt werden, die Scriptanbindung Richtung Lua gibt es
gratis dazu (bei sachgerechter Anwendung ... ;-).
Im Ergebnis kann man mit 44.6 kHz Daten sampeln (separate FreeRTOS Task, runtergebremst damit die
CPUs nicht komplett monopolisiert werden ...). Als Blockgröße habe ich
2048 Meßwerte gewählt. Das Mikrofon leistet 50 Hz bis 20kHz lt. Datenblatt, d.h. ein Teil der
Frequenzen kann unten & oben verworfen werden.
Damit das ganze hinreichend zügig abläuft, habe ich eine Verarbeitungspipeline aufgebaut:
Datenerfassung(Blockgröße) -> FFT -> Binning(10 St.). Das Sampeln wird in Lua aktiviert, die Ergebnisse
(aus zwei wechselseitig genutzten Ergebnispuffern à 10 'Bins') werden per Timertask in Lua ausgelesen
und an die LED-Kette ausgegeben.
Ein paar Meßergebnisse:
Die Aufnahme der Meßwerte benötigt ca. 45ms, das Umrechnen per FFT ca. 0,8 ms!
(Umso sinnfreier die Umsetzung in ESP32-Assembler ...).
Da ich gerade keine Schalter zur Hand hatte, habe ich zum Feintuning eine Flutter-App per Multicast
angebunden - die ich auf meinen 'NodeSwarm Devices' standardmäßig vorhalte.
<br/>
<br/>
## NodeSP Android App ##
Die App sendet Konfigurationsdaten an die NodeMCU per Multicast, am wichtigsten natürlich
für das Einstellen der Empfindlichkeit. Wenn die Umgebung sehr laut ist, sollte man runterregeln können ...
Die restlichen Parameter dienen der Konfiguration der LED-Ausgabe.
<img style="max-width: 200px"
alt="App picture"
src="/images/NodeSP/NodeSP_App.png"
style="max-width:100%;"
/>
<br/>
<br/>
## Showtime! ##
Hier mal ein (kurzes) Beispiel mit Musik:
<video width="640" height="480" controls>
<source src="/images/NodeSP/NodeSP1.webm" type="video/webm">
</video>
<br/>
<br/>
## Schwächen dieser Implementierung ##
Das Sampling ist nicht 'sustained rate' sondern intermittierend (wenn auch kaum spürbar). Eine verbesserte
Version werde ich zu einem späteren Zeitpunkt mittels I2S-Mikrofon nachreichen (der ESP32 unterstützt den
I2S-Bus mit DMA-Transfer - da sollte was gehen ... sagt das Internet :-).

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Loading…
Cancel
Save