Hackerspace Website (Klon wg. Rechte)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
private_mirror/content/projekt/NodeSP/index.md

181 lines
8.9 KiB

---
title: NodeSP Part I (Analog)
author: kaqu
status: Aktiv
difficulty: geht so ...
time: ~4h
date: 2020-02-20
3 years ago
image: NodeSP_Overview.jpg
keywords: NodeMCU,ESP32,FFT,Assembler
---
oder
ein Beitrag zum Thema *'Wieder versuchen./Wieder scheitern./Besser scheitern'* (Samuel Becket)
3 years ago
## 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?
3 years ago
{{< fluid_img alt="Showtime" src="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 ...
3 years ago
## 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?!
3 years ago
Anforderungen:
3 years ago
- Der verwendete Algorithmus sollte hinreichend allgemein einsetzbar sein,
d.h. die Meßwertblöcke sollten als 2er-Potenzen formuliert werden
können.
3 years ago
- Außerdem sollte mit echten Fließkommazahlen gearbeitet werden
(der ESP32 unterstützt 32-Bit IEEE754 mit 16 Registern native).
3 years ago
- Für die Meßwerte sollen keine Vorinformationen vorliegen (d.h. beliebige
Daten sollen verarbeitet werden können).
3 years ago
- Neben der Fourier-Transformation soll auch die Inverse berechnet werden
können.
3 years ago
## 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 ).
Zunächst gilt es, die Parameterübergabe zu klären, d.h. welche Parameter werden in welchen Registern
übergeben. Dann muß man die Dokumentation zur Inline-Assembly des GCC zusammensuchen und last (but not
least) muß natürlich der Assembler-Guide 'Xtensa® Instruction Set Architecture (ISA) Reference Manual'
durchgearbeitet werden ( https://0x04.net/~mwk/doc/xtensa.pdf ).
Im praktischen Teil 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:
3 years ago
- 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, d.h. der Compiler wählt bereits die optimalen Befehle).
3 years ago
- 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 ... (6510 et al.)!
Letztlich kann dadurch der Compiler recht gut optimieren, der Gewinn durch 'Metawissen' seitens
des Programmierers (also was man weglassen darf u.ä.) ist marginal.
3 years ago
- Die speziellen Matrix-Support Operationen (multiply/add w/ storage pointer increment etc.)
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' ...
3 years ago
## 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.
3 years ago
{{< fluid_img alt="Aufbaubild" src="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).
3 years ago
{{< fluid_img alt="Bohrschablone" src="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),
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 der
belegte Core nicht komplett monopolisiert wird ...). 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.
Für die Verifizierung der Funktion habe ich zunächst mit folgender Webseite Testtöne mit definierter
Frequenz erzeugt: http://onlinetonegenerator.com/432Hz.html .
Leider zeigt sich, das die generierten Töne niedriger und vor allem der hohen Frequenzen nicht 'laut'
genug sind.
Es trifft sich glücklich, das wir im Space von hacKNology einen Funktionsgenerator zur Verfügung haben.
Wenn wir den direkt auf den ADC schalten (ohne Mikro), können wir mit der Einstellung 2,2Vpp Testsignale
für den ganzen Bereich sauber generieren (überflüssig, zu sagen, das wir den Funktionsgenerator
seinerseits vorab mittels Oszi überprüft haben ... ;).
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.
3 years ago
## 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"
3 years ago
src="NodeSP_App.png"
/>
3 years ago
## Showtime!
Hier mal ein (kurzes) Beispiel mit Musik:
<video width="640" height="480" controls>
<source src="//media.hacknology.de/images/NodeSP/NodeSP1.webm" type="video/webm">
Your browser does not support the video tag.
</video>
3 years ago
## Schwächen dieser Implementierung
Das Sampling ist nicht 'sustained rate' sondern intermittierend (wenn auch kaum spürbar).
Es gibt lt. 'ESP32 - Technical Reference Manual' eine Betriebsart (LCD-Mode -> ADC/DAC-Mode) die hier Abhilfe schaffen könnte? Mal schaun ... (ein Tipp von Wolfgang).
Eine verbesserte Version werde ich zu einem späteren Zeitpunkt mittels I2S-Mikrofon (ein Tip von Markus) nachreichen
(der ESP32 unterstützt den I2S-Bus mit DMA-Transfer - da sollte was gehen ... sagt auch das Internet :-).