Forum: Digitale Signalverarbeitung / DSP / Machine Learning Ergebnisse einer FFT zusammen fassen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Kevin Hinrichs (Gast)


Lesenswert?

Meine ADC Controler ist für die FFT wie folgt eingestellt:
1
// min frequency is 30,5 Hz
2
// max frequency is 15625 Hz
3
// frequency resolution is 30,5 Hz
4
// recording duration is 32.5 ms
5
// 511 frequencys

Mit diesen Frequenzwerten möchte ich einen 16 Band Led Spectrum Analyzer 
darstellen.
Die Programmiersprache ist C.

Ich habe die 16 Frequenzbänder wie folgt zusammen gefasst:
1
// declare frequency bands (inaccurate version)
2
// Tiefbass + Mittlerer Bass
3
fftData->frequencyBarData[0].arrayPositionStart = 1;
4
fftData->frequencyBarData[0].arrayPositionStop = 3;
5
// Oberbass
6
fftData->frequencyBarData[1].arrayPositionStart = 4;
7
fftData->frequencyBarData[1].arrayPositionStop = 4;
8
// Untere Mitten/Grundtonbereich Teil 1
9
fftData->frequencyBarData[2].arrayPositionStart = 5;
10
fftData->frequencyBarData[2].arrayPositionStop = 8;
11
// Untere Mitten/Grundtonbereich Teil 2
12
fftData->frequencyBarData[3].arrayPositionStart = 9;
13
fftData->frequencyBarData[3].arrayPositionStop = 13;
14
// Mittlere Mitten Teil 1
15
fftData->frequencyBarData[4].arrayPositionStart = 14;
16
fftData->frequencyBarData[4].arrayPositionStop = 19;
17
// Mittlere Mitten Teil 2
18
fftData->frequencyBarData[5].arrayPositionStart = 20;
19
fftData->frequencyBarData[5].arrayPositionStop = 26;
20
// Mittlere Mitten Teil 3
21
fftData->frequencyBarData[6].arrayPositionStart = 27;
22
fftData->frequencyBarData[6].arrayPositionStop = 32;
23
// Obere Mitten Teil 1
24
fftData->frequencyBarData[7].arrayPositionStart = 33;
25
fftData->frequencyBarData[7].arrayPositionStop = 49;
26
// Obere Mitten Teil 2
27
fftData->frequencyBarData[8].arrayPositionStart = 50;
28
fftData->frequencyBarData[8].arrayPositionStop = 65;
29
// Untere Höhen Teil 1
30
fftData->frequencyBarData[9].arrayPositionStart = 66;
31
fftData->frequencyBarData[9].arrayPositionStop = 81;
32
// Untere Höhen Teil 2
33
fftData->frequencyBarData[10].arrayPositionStart = 82;
34
fftData->frequencyBarData[10].arrayPositionStop = 114;
35
// Mittlere Höhen Teil 1
36
fftData->frequencyBarData[11].arrayPositionStart = 115;
37
fftData->frequencyBarData[11].arrayPositionStop = 147;
38
// Mittlere Höhen Teil 2
39
fftData->frequencyBarData[12].arrayPositionStart = 148;
40
fftData->frequencyBarData[12].arrayPositionStop = 196;
41
// Obere Höhen
42
fftData->frequencyBarData[13].arrayPositionStart = 197;
43
fftData->frequencyBarData[13].arrayPositionStop = 327;
44
// Hochton
45
fftData->frequencyBarData[14].arrayPositionStart = 328;
46
fftData->frequencyBarData[14].arrayPositionStop = 360;
47
// Superhochton
48
fftData->frequencyBarData[15].arrayPositionStart = 361;
49
fftData->frequencyBarData[15].arrayPositionStop = 450;

Mein Problem ist die verteilung der Energiewerte von den jeweiligen 
Frequenzen.
Bekomme von 511 Frequenzen die Energiewerte.
Die Energiewerte stellen die Lautstärke der jeweiligen Frequenz dar.
Nun hat unsere LED Matrix 16 Balken.
Also können wir einen 16-Band-Equalizer darstellen.
Diese Energiewerte von den 511 Frequenzen muss ich nun auf die 16 Balken 
verteilen.
Und genau das ist mein Problem.
Aktuell habe ich einfach alle Energiewerte von einer Frequenzspanne 
zusammen addiert.
Wenn in diese frequenzspanne nur ein paar frequenzen energiewerte 
liefern, dann geht das.
ABER wenn in dieser frequenzspanne auf einmal viele frequenzen hohe 
energiewerte liefern, dann erhalte ich zu hohe zahlen.

Habe mir die Normalverteilung angeschaut und die 68-95-99,7-Regel.
Aber ich weiß nicht wie ich die darauf anwenden soll.
Habt ihr eine Idee wie ich die Energiewerte der Frequenzen sinnvoll 
zusammenfügen kann zu einem Band?

von c-hater (Gast)


Lesenswert?

Kevin Hinrichs schrieb:

> Ich habe die 16 Frequenzbänder wie folgt zusammen gefasst:
>
1
> // declare frequency bands (inaccurate version)
2
> // Tiefbass + Mittlerer Bass
3
> fftData->frequencyBarData[0].arrayPositionStart = 1;
4
> fftData->frequencyBarData[0].arrayPositionStop = 3;
5
> // Oberbass
6
> fftData->frequencyBarData[1].arrayPositionStart = 4;
7
> fftData->frequencyBarData[1].arrayPositionStop = 4;
8
> // Untere Mitten/Grundtonbereich Teil 1
9
> fftData->frequencyBarData[2].arrayPositionStart = 5;
10
> fftData->frequencyBarData[2].arrayPositionStop = 8;
11
[...]
12
>
>
> Mein Problem ist die verteilung der Energiewerte von den jeweiligen
> Frequenzen.

Jedes frequencyBarData-Element enthält (potentiell) die gleiche 
Maximalenergie. Wenn du unterschiedliche Zahlen solcher Elemente zu 
jeweils einem Frequenzband verbindest, musst du natürlich mit der Zahl 
der jeweils enthaltenen Elemente skalieren, sprich: die Summe der 
Elemente des Bandes durch ihre Anzahl teilen.

Dann hat jedes Band wiederum als Maximum das Maximum eines einzelnen 
Elements, unabhängig von der darin enthaltenen Elementzahl und die 
Msswerte der Bänder werden vergleichbar.

von Alt G. (altgr)


Lesenswert?

Der nachteil einer fixen 1024 ele fft ist dass sie recht langsam ist. 
Für tiefe töne OK, für hohe nicht schnell genug.

Anstatt bin 9 mit bin 10 und bin 11 zusammenzurechnen, mach nur bin10 
aber nur 512 ele länge. FFT länge ist invers proportional zur 
bandbreite.

Mach 16 von den 1-bin FFT, jedes bin mit and der gewünschten bandbreite 
angepasster länge. Z.b. tiefe töne 1024ele, hohe töne 32ele.

Die hohen töne zeigst du auch häufiger an, nicht zusammnwursteln, 
anzeigen! Genaue zahlen selber ausrechnen.

Die klarheit der spektrumanzeige wird dich überraschen. Das was 
consumergeräte machen, und was du auch vorhattest, ist müll.

: Bearbeitet durch User
von Kevin Hinrichs (Gast)


Angehängte Dateien:

Lesenswert?

c-hater schrieb:
> sprich: die Summe der
> Elemente des Bandes durch ihre Anzahl teilen.

Vielen Dank für deine Antwort.
Damit ich das richtig verstanden habe,
möchte ich das nochmal an einem Beispiel wiederholen.
Das Frequenzband 0 fast die Energiewerte der Frequenzen im BIN 1,2 und 3 
zusammen.
1
fftData->frequencyBarData[0].BandValues += ((uint32_t)fftData->fftOutput[1]) / 3;
2
fftData->frequencyBarData[0].BandValues += ((uint32_t)fftData->fftOutput[2]) / 3;
3
fftData->frequencyBarData[0].BandValues += ((uint32_t)fftData->fftOutput[3]) / 3;
Dies Würde bedeuten, das wenn nur eine Frequenz einen hohen Energiewert 
hat, mein LED-Spectrum-Analyzer nur 1/3 Pegel ausschlag anzeigt.

Der LED-Spectrum-Analyzer hat eine LED Matrix von 29 Pixel in der Höhe 
und 16 Pixel in der Breite.

Die Anforderung soll keine Messeinheit werden.
Die LED Matrix und die Balken sollen passend zu Musik ausschlagen.

Für diese Anwendung brauche ich eine geeignete Mechanik,
um die Werte zusammen zu fassen.

Alt G. schrieb:
> Der nachteil einer fixen 1024 ele fft ist dass sie recht langsam ist.
> Für tiefe töne OK, für hohe nicht schnell genug

Vielen Dank für deine Antwort.
Genau ich möchte Tiefe, Mitten und Hohe Töne darstellen.
Aber die hohen Töne haben ich noch nicht vernünftig darstellen können 
mit Musik. Mit einer einzelnen hohen Frequenz schon. (Online Tone 
Generator)

Alt G. schrieb:
> Anstatt bin 9 mit bin 10 und bin 11 zusammenzurechnen, mach nur bin10
> aber nur 512 ele länge. FFT länge ist invers proportional zur
> bandbreite.
Wenn ich zu wenig fft elemente habe, sieht der Effect auf der Matrix 
nicht gut aus. Kaum Pegel ausschlag.

Alt G. schrieb:
> Mach 16 von den 1-bin FFT, jedes bin mit and der gewünschten bandbreite
> angepasster länge. Z.b. tiefe töne 1024ele, hohe töne 32ele.
ich glaube da stoße ich an meine grenzen.
ich habe schon sehr lange gebraucht, bis zu meinem jetztigen projekt 
stand.
Verwende einen EK-TM4C123GXL Mikrocontroler von TI.
Den muss ich nehmen, ist ein Elektrotechniker Abschluss Projekt.
Warum auch immer ist dieser Controler schon an seinen Grenzen gekommen.
Die LED Ansteuerung geschiet mit 4 parallelen datenleitung über Timer 
und uDMA.
und das ADC läuft auch über uDMA.
und gelegentlich setzten die Timer zum led daten signal schon aus.
zusätzlich geht mir langsam auch der sram aus.

Ich möchte aber dennoch dein Vorschlag umsetzen, wenn ich ihn verstehen 
würde.

Alt G. schrieb:
> Die hohen töne zeigst du auch häufiger an, nicht zusammnwursteln,
> anzeigen! Genaue zahlen selber ausrechnen.
Ich bekomme alle 32ms neue audio daten in dieser zeit kann ich ca 7 
bilder auf die matrix schmeißen.
wie meinst du das ?

Alt G. schrieb:
> Die klarheit der spektrumanzeige wird dich überraschen. Das was
> consumergeräte machen, und was du auch vorhattest, ist müll.
ich möchte kein einfaches consumer gerät haben. das soll verdammt gut 
aussehen. die Hardware ist komplett fertig. Bild ist angehängt.

von c-hater (Gast)


Lesenswert?

Kevin Hinrichs schrieb:

> Vielen Dank für deine Antwort.
> Damit ich das richtig verstanden habe,
> möchte ich das nochmal an einem Beispiel wiederholen.
> Das Frequenzband 0 fast die Energiewerte der Frequenzen im BIN 1,2 und 3
> zusammen.
>
1
> fftData->frequencyBarData[0].BandValues += 
2
> ((uint32_t)fftData->fftOutput[1]) / 3;
3
> fftData->frequencyBarData[0].BandValues += 
4
> ((uint32_t)fftData->fftOutput[2]) / 3;
5
> fftData->frequencyBarData[0].BandValues += 
6
> ((uint32_t)fftData->fftOutput[3]) / 3;
7
>
> Dies Würde bedeuten, das wenn nur eine Frequenz einen hohen Energiewert
> hat, mein LED-Spectrum-Analyzer nur 1/3 Pegel ausschlag anzeigt.

Richtig. Das ist die Konsequenz, wenn man sich wirklich für die Energie 
interessiert, die im Band steckt.

Aber nicht zwingend die einzige Möglichkeit. Wenn dich nur der 
"lauteste" Bin des Bandes interessiert, dann musst du halt nicht 
skalieren, sondern statt dessen das lauteste Element rausfischen.

Das eine wie das andere ist absoluter Kinderkram.

von Kevin Hinrichs (Gast)


Lesenswert?

c-hater schrieb:
> Das eine wie das andere ist absoluter Kinderkram.

du meinst damit meine verfahren mit dem addieren oder mit der 
standardverteilung ?

von c-hater (Gast)


Lesenswert?

Kevin Hinrichs schrieb:

> du meinst damit meine verfahren mit dem addieren

Simples Addieren (ohne Skalierung) ist definitiv völliger Schwachsinn.

> oder mit der
> standardverteilung ?

Was ist eine "Standardverteilung" nach deiner Vorstellung? Beschreibe 
doch mal deinen "Standard"...

von Kevin Hinrichs (Gast)


Lesenswert?

c-hater schrieb:
> Was ist eine "Standardverteilung" nach deiner Vorstellung? Beschreibe
> doch mal deinen "Standard"...

Ja du hast recht, sowas wie eine Standardverteilung gibt es nicht.
Meine eine Normalverteilung.
Als Beispiel die 68-95-99,7-Regel die Ähnlich aussieht
wie die Kurven vom Datenblatt der MSGEQ7.

Als Beispiel wie es die MSGEQ7 machen.
https://www.sparkfun.com/datasheets/Components/General/MSGEQ7.pdf

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Kevin Hinrichs schrieb:
> Mein Problem ist die verteilung der Energiewerte von den jeweiligen
> Frequenzen.
Wenn die FFT richtig arbeitet und sinnvoll gefenstert ist, sollten die 
Energiewerte stimmen.

> Bekomme von 511 Frequenzen die Energiewerte.
Sicher, dass das nicht 512 sind?
Sind das die vollen Werte mit Spiegelspektrum oder schon halbiert?
Ich nehme an, du hast 1024, halbierst und lässt die untere wegen des 
Gleichanteils weg?

Dazu ist zu sagen, dass der Gleichanteil sich nicht nur in der tiefsten 
Frequenz abbbildet, sondern nur dort sehr dominant ist. Das ist u.a. 
auch ein Festerartefakt. Kann man leicht ausprobieren.

Zur Problematik an sich:

Das Zusammenfassen muss so erfolgen, dass überlappende Bereiche 
entstehen, d.h. man kann nicht einfach immer 2 zusammenfassen, sondern 
muss mindestens jede 2. zu 50% der linken und zu 50% der rechten Summe 
zuordnen, weil die Aussage einer Frequenz ja auch so eine "Spannweite" 
hat.

Das gleiche gilt, wenn man ungleichmäßig zusammenfasst.

Mit 16 Frequenzen hast du einen halben Terzband-Analyzer, musst also 
logarithmisch von oben herab immer mehr zusammenfassen. Auf Audio 
bezogen, würde ich das hier machen:

1:  2,0 ,
2:  2,6 ,
3:  3,5 ,
4:  4,6 ,
5:  6,0 ,
6:  8,0 ,
7:  10,5 ,
8:  13,8 ,
9:  18,2 ,
10:  24,0 ,
11:  31,6 ,
12:  41,7 ,
13:  55,0 ,
14:  72,4 ,
15:  95,5 ,
16:  125,8 ,

die hinteren Werte sind die theoretischen Spannen, die man entsprechend 
umsetzen muss, d.h. die 11. Frequenz mit 31,6  nutzt 31 Frequenzen und 
von den daneben liegenden jeweils 1/4 -> 31.5

Dann stimmen die 16 Werte perfekt in der Oktave und man muss nur noch 
die Gleichförmigkeit herstellen, weil in der Interpretation des Bündels 
13 auch  ein wenig das von 12 und 14 drinsteckt.

Damit wären die 16 Wertebündel nochmals mit z.B. einer Dreiecksfunktion 
zu bewerten,  also vereinfacht:  "Bündel 15 neu" = "Bündel 15" / 2 + 
"Bündel 14" / 4 + "Bündel 16" / 4.

Das wäre dann eine musikalisch sinnvolle Darstellung und entspricht auch 
dem Ergebnis, wenn man eine nichtlinear geteilte DFT mit nur diesen 16 
Frequenzen und entsprechendem span durchführen würde - oder eben 16 
analoge  Filter baut, die entsprechendes Q haben.

Ich würde aber raten mit der dritten Wurzel von 2 zu steigern und diese 
Werte zu nehmen:

1:  2,0 ,
2:  2,5 ,
3:  3,2 ,
4:  4,0 ,
5:  5,0 ,
6:  6,3 ,
7:  8,0 ,
8:  10,1 ,
9:  12,7 ,
10:  16,0 ,
11:  20,2 ,
12:  25,4 ,
13:  32,0 ,
14:  40,3 ,
15:  50,8 ,
16:  64,0 ,
17:  80,6 ,
18:  101,6 ,

Das sind dann 483 Punkte und man kann Frequenzen noch etwas verschieben, 
sodass man die äußersten 2 weglassen kann, (nicht bei der o.g. 
Berechnung) nur bei der Anzeige! Damit gibt es auch kein 
"Randrechenproblem" beim Verteilen.

Was man aber überdenken sollte:

Braucht man wirklich eine FFT für 16 Werte? Da gibt es z.B. Görtzel. 
Oder man macht eine 8 Punkte FFT mit jeweils iterativ angewandten 
Halbbandfiltern für jede Oktave und nutzt dann die inneren 6 Werte, 
mischt dann die äusseren 2 in die Nachbarn und hat so 7 Werte, die man 
1:2:4 zusammenfassen kann, um innerhalb jeder Oktave 3 Frequenzen zu 
bekommen.

von Kevin Hinrichs (Gast)


Lesenswert?

Vielen Dank für deine ausführliche Antwort.

Jürgen S. schrieb:
> Wenn die FFT richtig arbeitet und sinnvoll gefenstert ist, sollten die
> Energiewerte stimmen.

Als fensterung habe ich HAMMING und HANN:
1
void createWindow(fftDataType* fftData)
2
{
3
    // source: https://de.wikipedia.org/wiki/Fensterfunktion
4
    // this function is symmetric
5
    
6
    float32_t itemSize = (float32_t)ADC_NUMBER_OF_SAMPLES - 1.0F;
7
    
8
    switch (fftData->windowData.fftWindowTyp)
9
    {  
10
        case HAMMING:
11
        for (int i = 0; i < FFT_SIZE; i++)
12
        {
13
            fftData->windowData.fftWindowing[i] = 0.54F - 
14
                (0.46F * cosf(M_PI2 * (float32_t)i / itemSize));
15
        }
16
        break;
17
        
18
        case HANN:
19
        for (int i = 0; i < FFT_SIZE; i++)
20
        {
21
            fftData->windowData.fftWindowing[i] = 0.54F * 
22
                (1.0F - cosf(M_PI2 * (float32_t)i / itemSize));
23
        }
24
        break;
25
        
26
        default:
27
        break;
28
    }
29
    fftData->windowData.windowDataReady = 0x01;
30
}
31
void useWindow(fftDataType* fftData)
32
{
33
    // this function is symmetric
34
    for (int i = 0; i < FFT_SIZE; i++)
35
    {
36
        fftData->fftInput[i] *= fftData->windowData.fftWindowing[i];
37
        fftData->fftInput[ADC_NUMBER_OF_SAMPLES - (i + 1)] *= 
38
            fftData->windowData.fftWindowing[i];
39
    }
40
}

Jürgen S. schrieb:
> Sicher, dass das nicht 512 sind?
> Sind das die vollen Werte mit Spiegelspektrum oder schon halbiert?
> Ich nehme an, du hast 1024, halbierst und lässt die untere wegen des
> Gleichanteils weg?

Du hast recht es sind 512 nur das die erste BIN der Gleichanteil ist.

Jürgen S. schrieb:
> Dazu ist zu sagen, dass der Gleichanteil sich nicht nur in der tiefsten
> Frequenz abbbildet, sondern nur dort sehr dominant ist. Das ist u.a.
> auch ein Festerartefakt. Kann man leicht ausprobieren.

nutze von cmsis die fft arm_rfft_fast_f32.
da erhalte ich im ersten BIN beim
beim realen teil werte von 300 bis 4000 und beim imaginären teil von 30 
bis 4000. sind diese werte zu hoch?

Auf diese 16 Balken soll der gesamte Frequenzbereich abgebildet werden.
Geht das mit deiner oben beschriebenen Verteilung ?

Ich hab ADC neu eingestellt.
Kann ihn nun über einen Timer beliebig einstellen.
Also die Sample Rate ist jetzt bei 40000 Hertz.
mit 1024 Samples.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin Hinrichs schrieb:
> Das Frequenzband 0 fast die Energiewerte der Frequenzen im BIN 1,2 und 3
> zusammen.fftData->frequencyBarData[0].BandValues +=
> ((uint32_t)fftData->fftOutput[1]) / 3;
> fftData->frequencyBarData[0].BandValues +=
> ((uint32_t)fftData->fftOutput[2]) / 3;
> fftData->frequencyBarData[0].BandValues +=
> ((uint32_t)fftData->fftOutput[3]) / 3;
> Dies Würde bedeuten, das wenn nur eine Frequenz einen hohen Energiewert
> hat, mein LED-Spectrum-Analyzer nur 1/3 Pegel ausschlag anzeigt.
>
Jetzt weiss ich nicht, was aus deiner fft da wirklich fuer Werte 
rauskommen. Wenn man aber ein "Spannungs"-Signal ueber die Zeit 
ff-transformiert, kommen eher Spannungsdichten (Volt pro Hertz) raus, 
keine Energiedichten. Dazu muesstest du die Werte in den Bins erstmal 
quadrieren.
Dann solltest du diese quadrierten Werte aller Bins fuer ein 
Frequenzband aufsummieren.

> Der LED-Spectrum-Analyzer hat eine LED Matrix von 29 Pixel in der Höhe
> und 16 Pixel in der Breite.
>
> Die Anforderung soll keine Messeinheit werden.
> Die LED Matrix und die Balken sollen passend zu Musik ausschlagen.
>
> Für diese Anwendung brauche ich eine geeignete Mechanik,
> um die Werte zusammen zu fassen.

Diese Anzeigen haben "aus Gruenden" eine nichtlineare Kennlinie, gerne 
mal was logarithmisches. Also solltest du dann die Summe der Quadratbins 
nochmal geeignet logarithmieren, bevor du anfaengst damit LED-Balken 
anzusteuern.

Und dann kann ich mir natuerlich nicht verkneifen, anzumerken, dass ich 
fuer solche Spielereien die Fouriertransformation fuer ziemlichen 
Overkill und nicht gut geeinget halte und schon vor Jahren ;-) mal was 
alternatives gebastelt hab':
Beitrag ""LED-Spectrumanalyzer"software ohne Fouriertransformation"

Gegen Ende dieses Schretts schrub ich auch noch was Richtung Terzfilter, 
iirc.

Gruss
WK

: Bearbeitet durch User
von Jürgen S. (engineer) Benutzerseite



Lesenswert?

Kevin Hinrichs schrieb:
> beim realen teil werte von 300 bis 4000 und beim imaginären teil von 30
> bis 4000. sind diese werte zu hoch?
Das kommt einzig auf die konkrete Phasenlage der Oberwellen im 
Eingangssignal an, die ja durch die FFT separiert werden. Es kann sein, 
dass im Bezug auf den willkürlichen Messzeitpunkt sich ein Signal fast 
vollständig im I-Kanal befindet. Im Prinzip ist es ja so, dass die 
Wellen durch die FFT hindurchgleiten und man das auch "sehen" kann, wenn 
sie fein genug aufgelöst ist. Die Sin / Cos berücksichtigen indirekt den 
Umstand der unbekannten Phase, weil sie mit 90° verschoben 
draufgerechnet werden und die Summe der Quadrate damit konstant ist.

Was daher in jedem Fall passieren muss, ist eine korrekte Betragsbildung 
gemäß Wurzel (I*I + R*R). Dann hat man den Einzelwert jeder Frequenz.

Dergute W. schrieb:
> Wenn man aber ein "Spannungs"-Signal ueber die Zeit
> ff-transformiert, kommen eher Spannungsdichten (Volt pro Hertz) raus,
> keine Energiedichten. Dazu muesstest du die Werte in den Bins erstmal
> quadrieren.
Das ist nochmal eine Frage, die zu klären wäre. Beim Audio operieren wir 
durchaus mit Spannungen.

Das Zusammenbündeln der Frequenzen bleibt unbenommen. Dazu habe ich ein 
altes Beispiel angeheftet, wie man die Einzelfrequenzen verteilen kann. 
Dargesellt ist die grüne Zentralfrequenz des Bündels und die sich daraus 
ergebenden Grenzen (rot und blau) sowie die Berechnungsvorschrift, um 
über die Prozente der Kommastelle die nicht genau zu treffende 
Frequenznummer zu verteilen. Dazu muss angemerkt werden, dass das 
(linear) so eigentlich falsch ist, für diesen Anwendungsfall aber tut.

Ab da bliebe noch die Summierung der Frequenzen, für die man 25%,50%,25% 
rechnen oder aber auch ein Dreieck nehmen kann um dieFrequenzen 
zunehmend / abnehmend einem finalen Bündelzuzuordnen. Ganz korrekt wäre 
ein Hamming / Cosinus mit der Breite von 3 Bündeln - d.h. man beginnt 
bei der Zentralfrequenz (n-1) und geht bis zur f(n+1) um alle Frequenzen 
zu finden, die dem Bündel n zuzuordnen sind. Das ist in der Tabelle 
nicht dargestellt.

Was man aber der Tabelle entnehmen kann, ist, dass es "unten" ein wenig 
ungenau wird. Noch präziser wird es nur mit noch höheren 
FFT-Auflösungen, bei denen auch unten noch 3-4 Frequenzen gebündelt 
werden können.

Auch nicht vergessen werden darf die Division durch die Zahl der 
Frequenzen - in der Tabelle als INT-DIV ausgeführt.


Dergute W. schrieb:
> Diese Anzeigen haben "aus Gruenden" eine nichtlineare Kennlinie, gerne
> mal was logarithmisches
... und das ist nochmal ein weiterer Aspekt.

Dergute W. schrieb:
> fuer solche Spielereien die Fouriertransformation fuer ziemlichen
> Overkill und nicht gut geeinget halte und schon vor Jahren ;-) mal was
> alternatives gebastelt hab':
Für Prozessoren klar zu bevorzugen, wobei ich bei der Methode anmerken 
muss, dass die Filter, die dazu realisiert werden müssen, im Q sehr 
genug stimmen müssen, damit es musikalischen Sinn ergibt.

Bei einem FPGA sieht es anders aus: Da steht in der Tat Bandbreite genug 
zur Verfügung, um begrenzte FFTs genau genug rechnen zu lassen. 
Allerdings wäre bei nur 16 Kanälen auch dann eine angepasste 
Frequenzstruktur sinnvoll.

von Kevin Hinrichs (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank für eure Hilfe und Unterstützung.
Ich selbst muss zugeben, dass ich noch lange nicht euer technisches 
Niveau habe. Habe alleine schon ca. 3 Monate gebraucht, bis ich eine 
Frequenz messen kann mit der fft. Also das der Mikrocontroller korrekt 
die Samples aufzeichnet und die fft mir halbwegs vernünftige 
Frequenzwerte liefert.

Dergute W. schrieb:
> Jetzt weiss ich nicht, was aus deiner fft da wirklich fuer Werte
> rauskommen. Wenn man aber ein "Spannungs"-Signal ueber die Zeit
> ff-transformiert, kommen eher Spannungsdichten (Volt pro Hertz) raus,
> keine Energiedichten. Dazu muesstest du die Werte in den Bins erstmal
> quadrieren.
> Dann solltest du diese quadrierten Werte aller Bins fuer ein
> Frequenzband aufsummieren.
1
Der ADC hat folgende Daten:
2
-ADC resolution = 12BIT
3
-ADC conversion clock frequency = 16Mhz
4
-ADC conversion rate = 1Msps
5
-ADC sample time = 250ns
6
-ADC conversion time = 1us
7
-latency from trigger to start of conversion = 2 ADC clocks

Die conversion rate habe ich halbiert.
Der ADC wird über einen Timer angesteuert.
Den Timer kann ich konfigurieren wie möchte.
Aktuell ist dieser auf 40kHz eingestellt.
Das angeschlossen Mikrofon ist ein MAX4466 Modul.
Dieses Mikrofon kann bis 20kHz aufnehmen.
Und wie du schon vermutet hast kommt da ein Spannungs Signal raus, 
welche ich denn Sample.
Zudem habe ich noch die Möglichkeit ein Hardware Oversampling zu 
konfigurieren.

Ist dies für diese Anwendung sinnvoll?

Ich verstehe noch nicht ganz, wann ich die Werte quadrieren soll.
Damit meine ich:
Vor der fft oder nach der fft oder nach der Betragsbildung.

Anbei mein fft ablauf:
1
void fft(fftDataType* fftData)
2
{
3
    #ifndef DEBUG_OFF
4
    DEBUG_PC5 = GPIO_PIN_5; // FFT
5
    #endif
6
    
7
    // FFT instance
8
    static arm_rfft_fast_instance_f32 rfftInstance;
9
    
10
    // make fft
11
    arm_rfft_fast_init_f32(&rfftInstance, ADC_NUMBER_OF_SAMPLES);
12
    arm_rfft_fast_f32(&rfftInstance, fftData->fftInput, 
13
                      fftData->fftOutput, 0);
14
    
15
    // save dc offset and set it to 0
16
    fftData->dcOffsetReal = fftData->fftOutput[0];
17
    fftData->dcOffsetImag = fftData->fftOutput[1];
18
    fftData->fftOutput[0] = 0;
19
    fftData->fftOutput[1] = 0;
20
    
21
    // calculating the magnitude at each bin
22
    arm_cmplx_mag_f32(fftData->fftOutput, fftData->fftOutput, FFT_SIZE);
23
    
24
    #ifndef DEBUG_OFF
25
    DEBUG_PC5 = 0; // FFT
26
    #endif
27
}

Dergute W. schrieb:
> Diese Anzeigen haben "aus Gruenden" eine nichtlineare Kennlinie, gerne
> mal was logarithmisches. Also solltest du dann die Summe der Quadratbins
> nochmal geeignet logarithmieren, bevor du anfaengst damit LED-Balken
> anzusteuern.

Das ist ein interessanter Ansatz. Dies würde ich gerne umsetzten.
Kannst du mir die Gründe nennen?
Ich wüsste sonst, nicht wie ich einen geeigneten Logarithmus finden 
könnte.

Dergute W. schrieb:
> Und dann kann ich mir natuerlich nicht verkneifen, anzumerken, dass ich
> fuer solche Spielereien die Fouriertransformation fuer ziemlichen
> Overkill und nicht gut geeinget halte und schon vor Jahren ;-) mal was
> alternatives gebastelt hab':
> Beitrag ""LED-Spectrumanalyzer"software ohne Fouriertransformation"
>
> Gegen Ende dieses Schretts schrub ich auch noch was Richtung Terzfilter,
> iirc.

Da gebe ich dir recht. Vielen dank für dein Angebot. Ich möchte aber bei 
der fft bleiben, da ich eine menge Energie reingesteckt habe und dies 
jetzt immer ein kleinen Stückchen besser verstehe. Und ich möchte auch 
verstehen und lernen.

Jürgen S. schrieb:
> Was daher in jedem Fall passieren muss, ist eine korrekte Betragsbildung
> gemäß Wurzel (I*I + R*R). Dann hat man den Einzelwert jeder Frequenz.

Dies wird durch die Funktion arm_cmplx_mag_f32() umgesetzt.

Jürgen S. schrieb:
> Das Zusammenbündeln der Frequenzen bleibt unbenommen. Dazu habe ich ein
> altes Beispiel angeheftet, wie man die Einzelfrequenzen verteilen kann.
> Dargesellt ist die grüne Zentralfrequenz des Bündels und die sich daraus
> ergebenden Grenzen (rot und blau) sowie die Berechnungsvorschrift, um
> über die Prozente der Kommastelle die nicht genau zu treffende
> Frequenznummer zu verteilen. Dazu muss angemerkt werden, dass das
> (linear) so eigentlich falsch ist, für diesen Anwendungsfall aber tut.

Ich muss zugeben, das habe ich schon bei deiner Antwort weiter oben noch 
nicht richtig verstanden.

Aktuell habe ich die Verteilung wie folgt gewählt:
1
Numer  Band  Von  Bis
2
1  Tiefbass  20  40
3
2  Mittlerer Bass  40  100
4
3  Oberbass  100  150
5
4  Untere Mitten/Grundtonbereich Teil 1  150  250
6
5  Untere Mitten/Grundtonbereich Teil 2  250  400
7
6  Mittlere Mitten Teil 1  400  600
8
7  Mittlere Mitten Teil 2  600  800
9
8  Mittlere Mitten Teil 3  800  1000
10
9  Obere Mitten  1000  2000
11
10  Untere Höhen Teil 1  2000  2500
12
11  Untere Höhen Teil 2  2500  3500
13
12  Mittlere Höhen Teil 1  3500  4500
14
13  Mittlere Höhen Teil 2  4500  6000
15
14  Obere Höhen  6000  10000
16
15  Hochton  10000  11000
17
16  Superhochton  11000  20000

Als Vorlage dafür diente meine Recherche im Internet wie in der Musik in 
den Musik Instrumenten die Frequenzen verteilt sind.

Dergute W. schrieb:
> Dann solltest du diese quadrierten Werte aller Bins fuer ein
> Frequenzband aufsummieren.

Ich hatte das jetzt so verstanden, das dies umprofessionell wäre.

Jürgen S. schrieb:
> Ab da bliebe noch die Summierung der Frequenzen, für die man 25%,50%,25%
> rechnen oder aber auch ein Dreieck nehmen kann um dieFrequenzen
> zunehmend / abnehmend einem finalen Bündelzuzuordnen. Ganz korrekt wäre
> ein Hamming / Cosinus mit der Breite von 3 Bündeln - d.h. man beginnt
> bei der Zentralfrequenz (n-1) und geht bis zur f(n+1) um alle Frequenzen
> zu finden, die dem Bündel n zuzuordnen sind. Das ist in der Tabelle
> nicht dargestellt.

Das ist eine Interessante Idee, die ich gerne umsetzten möchte.

Jürgen S. schrieb:
> Was man aber der Tabelle entnehmen kann, ist, dass es "unten" ein wenig
> ungenau wird. Noch präziser wird es nur mit noch höheren
> FFT-Auflösungen, bei denen auch unten noch 3-4 Frequenzen gebündelt
> werden können.

Aktuell ist die Auflösung mit 1024 Samples und 40kHz. Die Aufnahmedauer 
beträgt ca. 25,6ms. Ich muss mal schauen, ob ich noch genug SRAM für 
2048 Samples übrig habe.
Ist dies wichtig?

von c-hater (Gast)


Lesenswert?

Kevin Hinrichs schrieb:

> Dergute W. schrieb:
>> Und dann kann ich mir natuerlich nicht verkneifen, anzumerken, dass ich
>> fuer solche Spielereien die Fouriertransformation fuer ziemlichen
>> Overkill und nicht gut geeinget halte und schon vor Jahren ;-) mal was
>> alternatives gebastelt hab':
>> Beitrag ""LED-Spectrumanalyzer"software ohne Fouriertransformation"

> Da gebe ich dir recht. Vielen dank für dein Angebot. Ich möchte aber bei
> der fft bleiben, da ich eine menge Energie reingesteckt habe

Tja, dann mache dich mit der Tatsache vertraut, dass man auch mal einen 
Haufen Energie in ein Projekt versenken kann, bei dem sich der gewählte 
Ansatz letztlich als wenig geeignet herausstellt. Hart ist das Leben...

Dass das Grundkonzept von "Dergute W." ziemlich zielführend ist, kannst 
du z.B. daran ermessen, dass es eine voll funktionsfähige (wenn auch 
stark modifizierte) Umsetzung des logarithmischen Grundkonzepts für 
einen ATtiny gibt, der mit Rechenleistung wahrlich nicht gesegnet ist. 
Siehe:

Beitrag "Audio Spektrum Analyzer mit ATtiny85"

Insbesondere zu berücksichtigen ist die Tatsache, dass hier bereits 11 
Kanäle in einem für die Anwendung sinnvollem Raster umgesetzt werden. 
Das ist nicht sehr weit weg von deinem Anspruch mit 16 Kanälen. Mit nur 
etwas mehr Rechenleistung wäre diese Lösung recht problemlos auf 23 
Kanäle aufzubohren und mit einer besseren ADC und deutlich mehr 
Rechenleistung auch auf eine wirklich ernsthaft brauchbare 
Anzeigeauflösung von 16Bit (natürlich logarithmisch).

Für einen Classic-Tiny war das zu viel, aber eine neuzeitlicher AVR8 
könnte das bereits schaffen. Und natürlich erst recht Sachen wie eine 
RP2040 oder noch dickere Schiffe.

von Kevin Hinrichs (Gast)


Lesenswert?

c-hater schrieb:
> Tja, dann mache dich mit der Tatsache vertraut, dass man auch mal einen
> Haufen Energie in ein Projekt versenken kann, bei dem sich der gewählte
> Ansatz letztlich als wenig geeignet herausstellt. Hart ist das Leben...

Das habe ich eben gemacht, als ich mich in dein Projekt rein gelesen 
habe.

Ich weiß aber noch nicht mal ansatzweise, was ich dafür machen soll und 
wie das funktioniert. Ich verstehe ja noch nichtmal die fft komplett. 
Wie soll ich denn das umsetzten?

Ich habe oben geschrieben, das ich ein blutiger Anfänger bin im 
Mikrocontroller programmieren. Ich kann in c ein paar Befehle und mein 
Mathe ist glaube ich dafür nicht ausreichend.
Ich verstehe ja noch nichtmal deine Kennlinien :D

Rechenleistung sollte ich genug haben?
80Mhz CPU mit 32bit.

Muss ich denn überhaupt noch mehrere Samples speichern?
Was muss ich den mit den Samples anstellen?

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Kevin Hinrichs schrieb:
> Aktuell habe ich die Verteilung wie folgt gewählt:

Mitten bis 2000 Hz und Superhochton eine ganze Oktave?

Ich habe es bei mir physiologisch linear aufgeteilt, also F = EXP ( k * 
N).
Demgemäß hat jede Oktave genau dieselbe Zahl von Frequenzgruppen.

Kevin Hinrichs schrieb:
> ob ich noch genug SRAM für
> 2048 Samples übrig habe.
> Ist dies wichtig?
Je mehr desto genauer. Gerade bei den unteren ist es ja so, dass man nur 
sehr wenige Werte hat.

Bei Audio braucht man 8, besser 9 oder 10 Oktaven - bekommt also eine 
Dynamik von 2 EXP 10 = 1024. Mit 3-4 Frequenzen unten sind das 4096 z.B.

von c-hater (Gast)


Lesenswert?

Kevin Hinrichs schrieb:

> Ich weiß aber noch nicht mal ansatzweise, was ich dafür machen soll und
> wie das funktioniert. Ich verstehe ja noch nichtmal die fft komplett.
> Wie soll ich denn das umsetzten?

Tja, ohne Lernen wird's nicht klappen. Was du (hoffentlich) bei der FFT 
gelernt hast, ist nicht umsonst.

Was ich verwende, sind sozusagen einzelne Bins einer FFT 
(Goertzel-Filter). Das hat den Vorteil, dass man für jeden einzelnen Bin 
getrennt die Bandbreite einstellen kann. Genau das ist nützlich, um dein 
aktuelles Problem quasi bereits vor seiner Entstehung zu lösen.

Ein weiterer Vorteil der Goertzel-Filter ist, dass viel weniger 
Rechenaufwand anfällt, solange die Zahl der Bins klein im Verhältnis zur 
FFT ist. Und das ist er immer dann, wenn du mit einer FFT einen großen 
Frequenzbereich erfassen willst, aber die Auflösung im unteren 
Frequenzbereich auch noch recht hoch sein muss. Also genau die Sachen, 
die in deiner Anwendung zutreffend sind.

> Ich habe oben geschrieben, das ich ein blutiger Anfänger bin im
> Mikrocontroller programmieren. Ich kann in c ein paar Befehle und mein
> Mathe ist glaube ich dafür nicht ausreichend.

Tja, ohne Lernen wird's nicht klappen. Wie weiter oben schon gesagt.

> Ich verstehe ja noch nichtmal deine Kennlinien :D

Was ist daran so schwer zu verstehen? Das sind einfach der Kennlinien 
aller elf Goertzel Filter in einem Diagramm zusammengefaßt, 
unterschieden durch die Farbe.

> Rechenleistung sollte ich genug haben?
> 80Mhz CPU mit 32bit.

Damit kann man schon ordentlich was anstellen. An der Rechenleistung 
sollte es also nicht scheitern. Was kann denn die ADC?

> Muss ich denn überhaupt noch mehrere Samples speichern?

Also nö, explizit speichern musst du keine Samples. Die werden einfach 
an den Eingang der Filterstruktur verfüttert, so wie sie reinkommen.

Allerdings braucht das Filterwerk aus Goertzels und Halbbandfiltern eine 
Ablaufsteuerung. Auch die muss bei jedem Sample "bewegt" werden.

Die Gestaltung dieser Ablaufsteuerung ist etwas, was ziemlich tricky 
ist. Sie darf einerseits selber nur möglichst wenig Rechenzeit 
verbrauchen und muss andererseits die einzelnen Filter so ansteuern, 
dass deren unvermeidliche Rechenlast möglichst gleichmäßig über die 
verfügbare Zeit verteilt wird.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin Hinrichs schrieb:
> Ich selbst muss zugeben, dass ich noch lange nicht euer technisches
> Niveau habe.
Immer locker durch die Hose atmen, das wird schon noch :-)
Mein Niveau ist auch sehr uebersichtlich.

> Der ADC hat folgende Daten:
Damit kann ich z.b. schonmal garnix anfangen. Aber ich wuerd' mal sagen, 
dass wenn du der Ansicht bist, eben mit den Einstellungen und der fft da 
bestimmte Frequenzen rausfiltern zu koennen, dann wird das erstmal schon 
so passen.

> Ich verstehe noch nicht ganz, wann ich die Werte quadrieren soll.
> Damit meine ich:
> Vor der fft oder nach der fft oder nach der Betragsbildung.
Ich meine da:
> Betragsbildung
> gemäß Wurzel (I*I + R*R).
Einfach nicht die Wurzel ziehen (wenn das der Fkt. Aufruf erlaubt). 
Dann haste das Quadrat des Betrags. Oder wenn das nicht geht, weil du an 
der Funktion nix schrauben kannst/moechtest, danach halt quadrieren. 
Kost' halt bisschen Rechenzeit extra.

> Ich wüsste sonst, nicht wie ich einen geeigneten Logarithmus finden
> könnte.
Ein grund waere z.b. dass menschliche Sinne oft eine logarithmische 
Empfindlichkeit aufweisen. Damit kann man grosse Bereiche abbilden. Das 
ist z.b. beim Gehoer so.
Du musst dir jetzt halt eine Formel basteln, mit der die Werte, die  aus 
der fft purzeln halt "schoen"  auf deinem Display ankommen.
Wenn da z.b. aus einem Bin max. 1023 rauskommen kann, und du z.b. 5 bins 
fuer einen Balken hernehmen willst, und der Balken besteht aus 29 
Segmenten, dann koennte das so gehen:
(1023*1023)*5 = 5232645
Damit sollen dann also 29 Segmente leuchten. Und 's soll logarithmisch 
sein.
Also logarithmiere ich die 5.2 Mio, z.b. mit dem natuerlichen 
Logarithmus. Dann kommt da 15.470 raus.
Schoener waere aber 29 (fuer eben 29) leuchtende Balken.
Also musst du die 15.470 noch mit einem Skalierungsfaktor 
multiplizierern, der waere dann 1.875.
Also waere die "Formel" dann:
1
Seg=1.876*ln(bin(11)*bin(11)+bin(12)*bin(12)+...bin(15)*bin(15))
Dann musste noch eine "Sicherung" einbauen, denn wenn alle Bins 0 sind, 
macht der ln() Faxen.

> Ich hatte das jetzt so verstanden, das dies umprofessionell wäre.
Naja, so schlimm find' ich's jetzt nicht. Klar kannst du auch hergehen 
und die verschiedenen bins auch noch unterschiedlich gewichten.  In 
meiner "Formel" zaehlen die ja alle gleich.
Wuerd' ich aber fuern Anfang erstmal noch nicht machen. Das macht halt 
noch mal ein Riesenfass auf.

> Ich möchte aber bei
> der fft bleiben, da ich eine menge Energie reingesteckt habe und dies
> jetzt immer ein kleinen Stückchen besser verstehe. Und ich möchte auch
> verstehen und lernen.
Da hab' ich ueberhaupt kein Problem damit. Ich haette jetzt nur ein 
Problem gehabt, wenn ich's nicht geschrieben haette, du dir jetzt noch 
wochenlang einen abkasperst und dann sagst: Ja Kacke, warum hat mir 
keiner gesagt, dass das auch ohne fft geht.
Mit fft gehts sicher auch. Hab' ich halt noch nicht selber gemacht.

Gruss
WK

von Audiomann (Gast)


Lesenswert?

Dergute W. schrieb:
>> gemäß Wurzel (I*I + R*R).
> Einfach nicht die Wurzel ziehen (wenn das der Fkt. Aufruf erlaubt).
> Dann haste das Quadrat des Betrags.

Mal abgesehen von dem eleganten Trick durch Nichtwurzelziehen zu 
Quadrieren, stelle ich die Frage, warum man überhaupt quadrieren soll, 
um die Amplitudenwerte zusammenzuführen. Die Amplitudenwerte jeder 
einzelnen Frequenz sind das Ergebnis einer linearen Summation / 
Integration über die Samples multipliziert mit den Koeffizienten, wenn 
man sich die FFT ausgedröselt vorstellt. Darin inbegriffen ist eine 
effektive Bandbreite dieser Operation, die u.a. von der Länge der FFT = 
Zahl der betrachteten Samplewerte abhängt. Bekanntlich ist die 
Schmalbandigkeit einer jeden dieser Operationen um so größer, je länger 
so ein Filter ist. Bei der FFT ist es nach meinem Wissensstand so, dass 
eine jede der letztlich ermittelten Amplituden einen Bereich abdeckt, 
der sich zu 50% mit den Nachbarbereichen überlappt und dabei die 
Energien der Frequenzen LINEAR berücksichtig.

Als Beispiel nehmen wir die 3 Frequenzen 22Hz, 24Hz und 26Hz einer FFT: 
Die 24er sollte die 25Hz zu 50% drin haben und die 25,5% noch mehr, 
wobei die 25Hz auch als Anteil in der 26er auftauchen.

Also nochmal konkret:

Dergute W. schrieb:
> Seg=1.876*ln(bin(11)*bin(11)+bin(12)*bin(12)+...bin(15)*bin(15))
Warum müssen beim manuellen Zusammenführen dieser eigentlich sich linear 
verhaltenden Werte plötzlich Quadrate gerechnet werden?

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Audiomann schrieb:
> Warum müssen beim manuellen Zusammenführen dieser eigentlich sich linear
> verhaltenden Werte plötzlich Quadrate gerechnet werden?

Muessen muss garnix. Ich schlag das halt mal so vor.
Wenn du eine Spannungsquelle mit 3Veff 50Hz hast und eine mit 4Veff 51Hz 
und du schaltest die beiden in Reihe und heizt damit einen 5 Ohm 
Widerstand auf, dann wird der genauso heiss, wie wenn du ihn an eine 
Spannungsquelle mit - na - wieviel Volt haengen wuerdest?
(Kleiner Tipp: 3²+4²=5²)

Bei einer normalen fft sollte das Uebersprechen von Bins in die 
Nachbarbins auch irgendsowas sin(x)/x artiges sein. Aber ich bin kein 
grosser Fouriereggsberdde.

Gruss
WK

von Audiomann (Gast)


Lesenswert?

Dergute W. schrieb:
> Bei einer normalen fft sollte das Uebersprechen von Bins in die
> Nachbarbins auch irgendsowas sin(x)/x artiges sein. Aber ich bin kein
> grosser Fouriereggsberdde.
Das wäre dann wohl zunächst mal zu klären. Es gab dazu glaube ich 
irgendwo eine Diskussion, wie man z.B. 25,7 Hz aus den Werten von 25 und 
26 berechnen kann und die war in der Tat nicht linear.

Ich hänge mich aber an etwas anderem auf:

Wenn ich einen Testtongenerator habe und zwischen 20Hz und 20kHz 
durchfahre, dann werden alle Frequenzen vom Spektrumanalysator irgendwie 
eingeordnet und dabei denke ich nicht, dass das nach der 
"Effektivwertmethode" wie es bei dir durchklingt, geschieht.

Die FFT ist doch am Ende von der Wirkung her nichts anderes, als ein 
Multiplizieren mit den Sinuswellen der jeweiligen Frequenzen. Ich 
dachte, das sei linear.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Audiomann schrieb:
> Die FFT ist doch am Ende von der Wirkung her nichts anderes, als ein
> Multiplizieren mit den Sinuswellen der jeweiligen Frequenzen. Ich
> dachte, das sei linear.

Daher bin ich ein Fan des Quadrierens nach der fft. Weil dann 
verschiedene "Leistungen" verschiedener Bins aufaddiert werden. Eben so, 
wie in meinem Beispiel mit den Spannungsquellen am Widerstand.

Gruss
WK

von Kevin Hinrichs (Gast)


Lesenswert?

c-hater schrieb:
> Was ist daran so schwer zu verstehen? Das sind einfach der Kennlinien
> aller elf Goertzel Filter in einem Diagramm zusammengefaßt,
> unterschieden durch die Farbe.

Damit meine ich den Zusammenhang. Also was diese Kennlinien ausdrücken.
Wie man sie interpretiert.
Ich habe halt fast keinerlei Erfahrung im DSP Bereich.
Ich habe eine Woche gebraucht zu verstehen, was mit einer Fensterung 
gemeint ist und wie ich diese in der Programmiersprache C anwende.

c-hater schrieb:
> Tja, ohne Lernen wird's nicht klappen. Was du (hoffentlich) bei der FFT
> gelernt hast, ist nicht umsonst.

Das ist ja auch okay. Aber halt schwer, wenn man sich die Dinge selber 
beibringen muss. Ich habe mir auch schon 1-2 Bücher zum Thema DSP 
besorgt, aber ich verstehe da noch nicht mal eine Seite von.

c-hater schrieb:
> Damit kann man schon ordentlich was anstellen. An der Rechenleistung
> sollte es also nicht scheitern. Was kann denn die ADC?

Das ist ein fertiges Entwickler Board von Texas Instruments.
EK-TM4C123GXL mit einem ARM® Cortex®-M4F Based MCU TM4C123G.
Der hat 2 ADC's.
Der ADC hat folgende Daten:
1
-ADC resolution = 12BIT
2
-ADC conversion clock frequency = 16Mhz
3
-ADC conversion rate = 1Msps
4
-ADC sample time = 250ns
5
-ADC conversion time = 1us
6
-latency from trigger to start of conversion = 2 ADC clocks
7
-12 shared analog input channels
8
-Single-ended and differential-input configurations
9
-Optional phase shift in sample time programmable from 22.5o to 337.5o
10
-Four programmable sample conversion sequencers from one to eight entries long, with corresponding conversion result FIFOs
11
-Hardware averaging of up to 64 samples
12
-Efficient transfers using Micro Direct Memory Access Controller (μDMA)
habe mal aus der doku heraus kopiert. der kann noch mehr.

c-hater schrieb:
> Also nö, explizit speichern musst du keine Samples.

Okay, das ist nämlich bis jetzt mir schon so. das ich erst 1024 
speichere und diese dann durch die fft bringe.
Das bedeutet ich brauch uint16_t 1024 für die Samples.
float32_t 1024 für den input der fft
und nochmal float32_t 1024 für den fft output.
wenn ich mehr wie 1024 samplen benötige ich mehr sram.

Dergute W. schrieb:
> Wenn da z.b. aus einem Bin max. 1023 rauskommen kann

alle meine bin werte sind float32 werte. Ich weiß leider nicht wie mein 
maximaler wert sein kann, der aus der fft kommt. ich nehme mal an wenn 
ich eine 12 bit adc habe sind meine werte die in die fft rein kommen von 
0 bis 4095. wobei der <2048 die negative werte und >2048 die positiven 
werte sind. wie ich nun aber daraus die maximalen werte heraus rechnen 
kann, weiß ich nicht.

Dergute W. schrieb:
> Wenn da z.b. aus einem Bin max. 1023 rauskommen kann, und du z.b. 5 bins
> fuer einen Balken hernehmen willst, und der Balken besteht aus 29
> Segmenten, dann koennte das so gehen:
> (1023*1023)*5 = 5232645

Warum geht der maximal wert quadratisch rein ?

Dergute W. schrieb:
> Einfach nicht die Wurzel ziehen (wenn das der Fkt. Aufruf erlaubt).
> Dann haste das Quadrat des Betrags. Oder wenn das nicht geht, weil du an
> der Funktion nix schrauben kannst/moechtest, danach halt quadrieren.
> Kost' halt bisschen Rechenzeit extra.

Das ist kein problem. ich muss ja nicht die standard cmsis funktion 
nehmen. Also die werte kommen aus der fft. nun mit jeder bin
dann I * I+R * R rechnen?
Aber was ändere ich damit, ich würde es gerne verstehen.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin Hinrichs schrieb:
> Aber was ändere ich damit, ich würde es gerne verstehen.

Damit kriegst du einen Wert, der die Leistung in dem Bin (also bei einer 
bestimmten Frequenz oder einem sehr kleinen Frequenzband) 
repraesentiert, nicht mehr die Spannung. Und die Leistungen aus mehreren 
Bins aufzuaddieren halte ich fuer sinnvoller als die Spannungen.
Wuerdest du danach aus der Summe wieder die Wurzel ziehen, waere es 
wieder ein Wert, der den Effektivwert aller Spannungen in dem 
Frequenzband repraesentiert.
Dieses (finale) Wurzelziehen kannst du dir aber sparen, wenn/weil du 
danach logarithmierst. Dadurch wird das wurzelziehen nur zu einer 
Halbierung des Ergebnisses - kann also durch Skalierung "gemacht" werden 
(Ein dreifaches Prosit auf die logarithmischen Rechenregeln).
Wenn dir das voellig unklar ist, reite nicht allzulange drauf rum 
(sondern studier' E-Technik, da koennte das so im ca. 2. Semester 
ausgiebig drankommen ;-) ).

Gruss
WK

von Audiomann (Gast)


Lesenswert?

Dergute W. schrieb:
> (sondern studier' E-Technik, da koennte das so im ca. 2. Semester
> ausgiebig drankommen ;-) ).
Im Studium werden die Logarithmus-Rechenregeln durchgenommen? Ist das 
nicht was für die 11. Klasse?

Dergute W. schrieb:
> Daher bin ich ein Fan des Quadrierens nach der fft. Weil dann
> verschiedene "Leistungen" verschiedener Bins aufaddiert werden.
"Fan" klingt so, als sei das eine optionale Form der Auswertung. Kann 
man das  nicht irgendwie verpflichtend herleiten?

Was sagt ein FFT-Wert aus? Energiedichte / Frequenz?

Und wie kommt es zustande?
Der Wert ist der Betrag über die beiden orthogonalen Summen, die 
entstehen, wenn man über N Samples jeweils cos und sin (2*pi(k/N)) 
reinmultipliziert, also alle betrachteten Samples mit einem Sinus und 
parallel einen Cosinus faltet. Soweit stimmig?

Bei einer FFT mit 32 Punkten und 32kHz bekomme ich ganzzahlige kHz, also 
1,2,3, ... 16 und das Spiegelspektrum. Angenommen, ich betrachte die 
Komponente 2kHz in meinem Signal - was sagt die jetzt aus?

Und was passiert mit der 2,5kHz? Die müsste in den Nachbarn gleichmäßig 
drinstecken, oder? Sind das keine 50% : 50%?

Nehmen wir nun ein Rechtecksignal mit 2,5kHz und seine Oberwellen 7,5 
und 12,5. Man sollte Komponenten bei 3,4,7,8,12,13 bekommen. Alle 
Quadrieren?








einem Wert genau 1kHz und die FFT liefert auf

von Audiomann (Gast)


Lesenswert?

"einem Wert genau 1kHz und die FFT liefert auf" ist der Rest von einer 
anderen Frage gewesen, die noch gefehlt hat, nämlich:

Wenn es keine krumme, sondern eine exakt treffende Rechteckwelle ist, 
mit z.B. 1 kHz und den Komponenten 1,3,5 so würde sich ein anderer Wert 
aus der FFT ergeben, weil

100%, 33%, 20% einzeln quadriert was anderes ergeben als

50%+50%,  16%+16%,  10%+10%.

Das kann irgendwie nicht sein. Es muss eigentlich egal sein, welche 
Frequenzen man im Spektrum hat und wie fein aufgelöst die FFt ist - das 
Rechenergbnis bei der Mittelung der Bins muss identisch sein.

von Pukixy (Gast)


Angehängte Dateien:

Lesenswert?

Bei Rechteckfensterung im Zeitbereich hat man eine sinc-Funktion im 
Frequenzbereich. Wenn die Signalfrequenz nicht ins Raster passt, hat man 
im Frequenzbereich entsprechende Werte der verschobenen sinc-Funktion 
über alle Bins.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

iirc, kommen im 2. Semester so Sachen dran, wie Effektivwert, 
Spitzenwert, lin.Mittelwert, etc. von Wechselgroessen auch mit 
"lustigem" Kurvenverlauf.

Und wenn man das dann etwas durchdrungen hat, kann man evtl. auch sagen, 
was man dann gerne fuer Werte haette. Ob einen z.b. der Effektivwert 
oder der Spitzenwert eines Signals mehr interessiert.

So, und wenn ich dann am Anfang sowas hier lese:
Kevin Hinrichs schrieb:
> Aktuell habe ich einfach alle Energiewerte von einer Frequenzspanne
> zusammen addiert.
> Wenn in diese frequenzspanne nur ein paar frequenzen energiewerte
> liefern, dann geht das.
> ABER wenn in dieser frequenzspanne auf einmal viele frequenzen hohe
> energiewerte liefern, dann erhalte ich zu hohe zahlen.

Dann ist das fuer mich ein Anzeichen, dass der Kollege besser mit einem 
Effektivwert ueber ein paar Bins (also Quadrieren, Summieren (und 
ggf.Wurzelziehen )) fahren wuerde als mit dem Spitzenwert(Addieren der 
einzelnen Betraege ohne quadrieren).
Das kann man machen, muss man aber nicht.
Da gibts kein Richtig oder Falsch. Kommt halt drauf an, was ich haben 
will.
Hab' ich z.b. ein Problem mit Lichtboegen durch Spannungsueberschlaege 
im Ausgangsfilter eines COFDM-Senders z.b. fuer DVB-T, dann wuerden mich 
eher die Spitzenspannungen der Summen der Traegerfrequenzen 
interessieren.
Ist hier aber eben nicht der Fall, hab' ich stark den Eindruck...daher 
mein Plaedoyer fuer Effektivwerte.

Gruss
WK

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Das ist schon richtig, was W.K. schreibt und auch was zu der 
SINC-Funktion gepostet wurde.

Das Einsortieren der Frequenzen in "ihr" zugehöriges Bündel erfolgt 
nicht konstant oder linear. Wenn man auf einen Analyzer schaut, dann 
laufen die Amplituden beim Sweep auch in kleinen Wellen. Es muss genauer 
gerechnet werden, wollte man das signalverarbeitungtechnisch auswerten.

Das sprengt aber hier jeglichen Rahmen, denn wir bekommen durch das 
grobe 16er-System eine extreme Reduktion an Information, sodass das 
lineare Verteilen der gebrochenen Frequenzen auf die FFT-Frequenzen 
einerseits- und im weiteren das gruppenweise oder lineare Zuordnen zu 
den Bins andererseits völlig ausreichend ist. Richtig(er) wäre hier z.B. 
ein Cosinus, der die Frequenzen sukzessive gewichtet.

So eine Anzeige ist nur eine grobe Information, bei der man nebenbei 
erwähnt noch einen offenen Punkt hat, nämlich die Reaktions- und 
Integrationsdauer, die bei Bässen ja eine andere sein muss als bei den 
Höhen. Auch dafür müsste man eine genauere Betrachtung anstellen, wie 
man aus den optimalen Zeiten für jede Frequenz einen richtige Summenzeit 
bilden könnte.

von Gerhard Z. (germel)


Lesenswert?

Kevin Hinrichs schrieb:
> Ich habe mir auch schon 1-2 Bücher zum Thema DSP
> besorgt, aber ich verstehe da noch nicht mal eine Seite von.

Ich fand "The Scientist and Engineer's Guide to Digital Signal 
Processing By Steven W. Smith, Ph.D." sehr hilfreich:
http://www.dspguide.com/pdfbook.htm

Man kann sich die einzelnen Kapitel als PDF runter laden und mit etwas 
Mühe alle Kapitel zu einem Buch (PDF) kombinieren.

von Kevin Hinrichs (Gast)


Lesenswert?

Gerhard Z. schrieb:
> Ich fand "The Scientist and Engineer's Guide to Digital Signal
> Processing By Steven W. Smith, Ph.D." sehr hilfreich:
> http://www.dspguide.com/pdfbook.htm

Danke für diesen Tipp. Das schaue ich mir gerne an.

Eine andere Frage:
Wie errechne ich den maximalen möglichen Wert,
der aus einem BIN nach der fft heraus kommen kann?

Jürgen S. schrieb:
> So eine Anzeige ist nur eine grobe Information, bei der man nebenbei
> erwähnt noch einen offenen Punkt hat, nämlich die Reaktions- und
> Integrationsdauer, die bei Bässen ja eine andere sein muss als bei den
> Höhen.

Ich habe beobachtet, dass bei schnellen Bässen manchmal der Pegel oben 
bleibt und manchmal passend zum Bass Beat läuft. Ich glaube das ist auch 
darauf zurück zuführen, dass manche Bässe länger im Raum rum dröhnen.
Und die Höhen habe ich noch gar nicht im Griff. Mit Musik kann ich diese 
nicht vernünftig darstellen. Mit einem Online Tone Gernator auf eine 
einzelne Frequenz geht es aber.

Ich merke immer mehr, wie sensible das Thema ist.
Und frage mich ob ich alle Schritte korrekt umgesetzt habe.
Ich würde euch gerne meinen C Code geben und euch mal rüber schauen 
lassen.

Teil 1 DC Offset entfernen
1
void clearMicBuffer(fftDataType* fftData)
2
{
3
    // reset average
4
    uint32_t micMEAN = 0x00000000;
5
    
6
    // calculate the average of the mic buffer
7
    for (int i = 0; i < ADC_NUMBER_OF_SAMPLES; i++)
8
    {
9
        micMEAN += mic0Buffers[fftData->bufferNumber][i];
10
    }
11
    // divide the average by the number of samples
12
    // use float for more accurate)
13
    float32_t micAVG = (float32_t)micMEAN / (float32_t)ADC_NUMBER_OF_SAMPLES;
14
    
15
    // reset rms
16
    fftData->micData.micRMS = 0.0F;
17
    
18
    //
19
    // an overflow may occur during RMS formation, 
20
    // but this is highly unlikely
21
    // the highest value would be:
22
    // 2048 * 2048 * 1024 = 4.294.967.296
23
    // a uint32_t has a max value of 4.294.967.295
24
    // all 1024 values should have their maximum value
25
    // and this is highly improbable
26
    
27
    // remove DC offset from the mic and 
28
    // calculate the rms of the sound buffer
29
    for (int i = 0; i < ADC_NUMBER_OF_SAMPLES; i++)
30
    {
31
        // remove DC offset from the mic
32
        fftData->fftInput[i] = (float32_t)mic0Buffers[fftData->bufferNumber][i] - 
33
                                micAVG;
34
        
35
        // calculate the rms of the sound buffer
36
        fftData->micData.micRMS += fftData->fftInput[i] * fftData->fftInput[i];
37
    }
38
    // clear the buffer status flag and reset bufferNumber
39
    mic0BuffersStatus[fftData->bufferNumber] = EMPTY;
40
    fftData->bufferNumber = 0xFF;
41
    
42
    // start new transfer
43
    recordMusic_ADC0();
44
    
45
    // divide the rms by the number of samples
46
    fftData->micData.micRMS /= (float32_t)ADC_NUMBER_OF_SAMPLES;
47
    
48
    // square root the rms value to get the rms
49
    fftData->micData.micRMS = sqrt(fftData->micData.micRMS);
50
}

Teil 2 Egal bei welcher Lautstärke, sollen gleiche Werte rauskommen
1
void micVolumeControl(streamDataType* ledData, 
2
                      fftDataType* fftData, setupDataType* setupData)
3
{
4
    static uint8_t saveMaxBrightness;
5
    static uint8_t noMusic;
6
    
7
    static uint16_t micRMSBufferIndex;
8
    static uint32_t thresholdForMusicIsLouder;
9
    static uint32_t thresholdForMusicIsQuieter;
10
    
11
    static float32_t micRMSBuffer[AGC_AVERAGE_SAMPLE_SIZE];
12
    
13
    //
14
    // https://de.wikipedia.org/wiki/Schalldruckpegel
15
    //
16
    // ADC resolution is 12bit -> range from 0 to 4095
17
    // max value from soundBuffer is |-2048|
18
    // max value from log10 is 20*log10(1 / 2048) = -66,22dB
19
    // dB range is from -66,22dB to 0dB
20
    // -66,22dB is silince but the mic has gain +12dB = -54dB
21
    // 0dB is max loudness
22
    //
23
    // i will use this later
24
    //
25
    #ifndef DEZIBEL_OFF
26
    fftData->micData.micVolumeInDezibel = 20.0F * log10(fftData->micData.micRMS / 2048.0F);
27
    #endif
28
    
29
    // set index to zero for the moving average
30
    if (micRMSBufferIndex == AGC_AVERAGE_SAMPLE_SIZE)
31
    {
32
        micRMSBufferIndex = 0;
33
    }
34
    
35
    // add a value to the moving average
36
    micRMSBuffer[micRMSBufferIndex] = fftData->micData.micRMS / (float32_t)AGC_AVERAGE_SAMPLE_SIZE;
37
    micRMSBufferIndex++;
38
    
39
    // reset average
40
    float32_t micRMSBufferAVG = 0.0F;
41
    
42
    // calculate average
43
    for (int i = 0; i < AGC_AVERAGE_SAMPLE_SIZE; i++)
44
    {
45
        micRMSBufferAVG += micRMSBuffer[i];
46
    }
47
    
48
    //
49
    // change micRMSforScaling only after a strong hysteresis
50
    // and a big threshold
51
    //
52
    // switch it off for adjust the filters
53
    #ifndef MIC_SCALING_OFF
54
    if (!fftData->micData.micScaling)
55
    {
56
    #endif
57
        // music is getting louder
58
        if (micRMSBufferAVG > fftData->micData.micRMSforScaling * 1.20F)
59
        {
60
            thresholdForMusicIsLouder++;
61
            
62
            if (thresholdForMusicIsLouder > 500)
63
            {
64
                fftData->micData.micRMSforScaling = micRMSBufferAVG;
65
                thresholdForMusicIsLouder = 0;
66
            }
67
        }
68
        else
69
        {
70
            thresholdForMusicIsLouder = 0;
71
        }
72
        
73
        // music is getting quieter
74
        if (micRMSBufferAVG < fftData->micData.micRMSforScaling * 0.80F)
75
        {
76
            thresholdForMusicIsQuieter++;
77
            
78
            if (thresholdForMusicIsQuieter > 3500)
79
            {
80
                fftData->micData.micRMSforScaling = micRMSBufferAVG;
81
                thresholdForMusicIsQuieter = 0;
82
            }
83
        }
84
        else
85
        {
86
            thresholdForMusicIsQuieter = 0;
87
        }
88
    #ifndef MIC_SCALING_OFF
89
    }
90
    #endif
91
    
92
    // calculate the scale factor with the rms value
93
    //
94
    // after scaling the rms should be near 2048 (the new rms)
95
    //
96
    // the range from micRMSforScaling is 0.0F to 4095.0F
97
    // 1     -->  2048.0F scale factor
98
    // 2     -->  1024.0F scale factor
99
    // 4     -->   512.0F scale factor
100
    // 8     -->   256.0F scale factor
101
    // 16    -->   128.0F scale factor
102
    // 32    -->    64.0F scale factor
103
    // 64    -->    32.0F scale factor
104
    // 128   -->    16.0F scale factor
105
    // 256   -->     8.0F scale factor
106
    // 512   -->     4.0F scale factor
107
    // 1024  -->     2.0F scale factor
108
    // 2048  -->     1.0F scale factor
109
    // 4095  -->     0.5F scale Factor
110
    //
111
    // the formel is: scaleFactor = 2048 / micRMSforScaling
112
    
113
    float32_t scaleFactor = 2048.0F / fftData->micData.micRMSforScaling;
114
    
115
    // the mic signal have to bigger than 30.0F
116
    // because a mic signal < 30.0F is a silence room
117
    if (fftData->micData.micRMSforScaling > 30.0F)
118
    {
119
        // scale volume from the mic signal
120
        if (scaleFactor < 1.0F)
121
        {
122
            // the mic signal is to high
123
            for (int i = 0; i < ADC_NUMBER_OF_SAMPLES; i++)
124
            {
125
                fftData->fftInput[i] -= fftData->fftInput[i] * scaleFactor;
126
            }
127
        }
128
        else
129
        {
130
            // the mic signal is to low
131
            for (int i = 0; i < ADC_NUMBER_OF_SAMPLES; i++)
132
            {
133
                fftData->fftInput[i] += fftData->fftInput[i] * scaleFactor;
134
            }
135
        }
136
        // make this once
137
        if (noMusic)
138
        {
139
            // music is back
140
            setupData->effectSetupData.brightness = saveMaxBrightness;
141
            noMusic = 0x0;
142
        }
143
    }
144
    else
145
    {
146
        // make this once
147
        if (!noMusic)
148
        {
149
            // no music
150
            saveMaxBrightness = ledData->effectData.brightness;
151
            setupData->effectSetupData.brightness = 0;
152
            noMusic = 0x1;
153
        }
154
    }
155
}

Teil 3 fft
1
void fft(fftDataType* fftData)
2
{
3
    // FFT instance
4
    static arm_rfft_fast_instance_f32 rfftInstance;
5
    
6
    // make fft
7
    arm_rfft_fast_init_f32(&rfftInstance, ADC_NUMBER_OF_SAMPLES);
8
    arm_rfft_fast_f32(&rfftInstance, fftData->fftInput, 
9
                      fftData->fftOutput, 0);
10
    
11
    // save dc offset and set it to 0
12
    fftData->dcOffsetReal = fftData->fftOutput[0];
13
    fftData->dcOffsetImag = fftData->fftOutput[1];
14
    fftData->fftOutput[0] = 0;
15
    fftData->fftOutput[1] = 0;
16
    
17
    // computes the magnitude of the elements
18
    // of a complex data vector
19
    // RMS value of all voltages in the frequency band
20
    // 
21
    //arm_cmplx_mag_f32(fftData->fftOutput, fftData->fftOutput, FFT_SIZE);
22
    
23
    // computes the magnitude squared of the elements
24
    // of a complex data vector
25
    // RMS value of all powers in the frequency band
26
    // 
27
    arm_cmplx_mag_squared_f32(fftData->fftOutput, fftData->fftOutput, FFT_SIZE);
28
}

Teil 4 Frequenzbänder bestimmen. Werte festlegen zum skallieren und zum 
filtern
1
void changeFrequencyBands(fftDataType* fftData)
2
{
3
    if (fftData->FrequencyBandsSwitcher == 0x01)
4
    {
5
        // declare frequency bands (inaccurate version)
6
        // Tiefbass
7
        fftData->frequencyBarData[0].arrayPositionStart = 1;
8
        fftData->frequencyBarData[0].arrayPositionStop = 1;
9
        // Mittlerer Bass
10
        fftData->frequencyBarData[1].arrayPositionStart = 2;
11
        fftData->frequencyBarData[1].arrayPositionStop = 2;
12
        // Oberbass
13
        fftData->frequencyBarData[2].arrayPositionStart = 3;
14
        fftData->frequencyBarData[2].arrayPositionStop = 3;
15
        // Untere Mitten/Grundtonbereich Teil 1
16
        fftData->frequencyBarData[3].arrayPositionStart = 4;
17
        fftData->frequencyBarData[3].arrayPositionStop = 6;
18
        // Untere Mitten/Grundtonbereich Teil 2
19
        fftData->frequencyBarData[4].arrayPositionStart = 7;
20
        fftData->frequencyBarData[4].arrayPositionStop = 10;
21
        // Mittlere Mitten Teil 1
22
        fftData->frequencyBarData[5].arrayPositionStart = 11;
23
        fftData->frequencyBarData[5].arrayPositionStop = 15;
24
        // Mittlere Mitten Teil 2
25
        fftData->frequencyBarData[6].arrayPositionStart = 16;
26
        fftData->frequencyBarData[6].arrayPositionStop = 20;
27
        // Mittlere Mitten Teil 3
28
        fftData->frequencyBarData[7].arrayPositionStart = 21;
29
        fftData->frequencyBarData[7].arrayPositionStop = 25;
30
        // Obere Mitten
31
        fftData->frequencyBarData[8].arrayPositionStart = 26;
32
        fftData->frequencyBarData[8].arrayPositionStop = 51;
33
        // Untere Höhen Teil 1
34
        fftData->frequencyBarData[9].arrayPositionStart = 52;
35
        fftData->frequencyBarData[9].arrayPositionStop = 64;
36
        // Untere Höhen Teil 2
37
        fftData->frequencyBarData[10].arrayPositionStart = 65;
38
        fftData->frequencyBarData[10].arrayPositionStop = 89;
39
        // Mittlere Höhen Teil 1
40
        fftData->frequencyBarData[11].arrayPositionStart = 90;
41
        fftData->frequencyBarData[11].arrayPositionStop = 115;
42
        // Mittlere Höhen Teil 2
43
        fftData->frequencyBarData[12].arrayPositionStart = 116;
44
        fftData->frequencyBarData[12].arrayPositionStop = 153;
45
        // Obere Höhen
46
        fftData->frequencyBarData[13].arrayPositionStart = 154;
47
        fftData->frequencyBarData[13].arrayPositionStop = 256;
48
        // Hochton
49
        fftData->frequencyBarData[14].arrayPositionStart = 257;
50
        fftData->frequencyBarData[14].arrayPositionStop = 281;
51
        // Superhochton
52
        fftData->frequencyBarData[15].arrayPositionStart = 282;
53
        fftData->frequencyBarData[15].arrayPositionStop = 511;
54
        
55
        fftData->FrequencyBandsSwitcher = 0x00;
56
    }
57
    
58
    //very flatt not perfect but looks good
59
    // without windowing
60
    if(fftData->FrequencyFilterSwitcher == 0x01)
61
    {
62
        // bass
63
        fftData->bandFilterData[0].arrayPositionStart = 1;
64
        fftData->bandFilterData[0].arrayPositionStop = 3;
65
        fftData->bandFilterData[0].passFilter = 92000.0F;
66
        fftData->bandFilterData[0].amplitude = 92000;
67
        // middle
68
        fftData->bandFilterData[1].arrayPositionStart = 4;
69
        fftData->bandFilterData[1].arrayPositionStop = 51;
70
        fftData->bandFilterData[1].passFilter = 90000.0F;
71
        fftData->bandFilterData[1].amplitude = 90000;
72
        // high
73
        fftData->bandFilterData[2].arrayPositionStart = 52;
74
        fftData->bandFilterData[2].arrayPositionStop = 256;
75
        fftData->bandFilterData[2].passFilter = 73000.0F;
76
        fftData->bandFilterData[2].amplitude = 73000;
77
        // very high Teil 1
78
        fftData->bandFilterData[3].arrayPositionStart = 257;
79
        fftData->bandFilterData[3].arrayPositionStop = 281;
80
        fftData->bandFilterData[3].passFilter = 10000.0F;
81
        fftData->bandFilterData[3].amplitude = 8000;
82
        // very high Teil 2
83
        fftData->bandFilterData[4].arrayPositionStart = 282;
84
        fftData->bandFilterData[4].arrayPositionStop = 511;
85
        fftData->bandFilterData[4].passFilter = 50000.0F;
86
        fftData->bandFilterData[4].amplitude = 45000;
87
        
88
        fftData->FrequencyFilterSwitcher = 0x00;
89
    }
90
    
91
    //very flatt not perfect but looks good
92
    // with windowing
93
    if(fftData->FrequencyFilterSwitcher == 0x02)
94
    {
95
        // bass
96
        fftData->bandFilterData[0].arrayPositionStart = 1;
97
        fftData->bandFilterData[0].arrayPositionStop = 3;
98
        fftData->bandFilterData[0].passFilter = 50000.0F;
99
        fftData->bandFilterData[0].amplitude = 50000;
100
        // middle
101
        fftData->bandFilterData[1].arrayPositionStart = 4;
102
        fftData->bandFilterData[1].arrayPositionStop = 51;
103
        fftData->bandFilterData[1].passFilter = 65000.0F;
104
        fftData->bandFilterData[1].amplitude = 65000;
105
        // high
106
        fftData->bandFilterData[2].arrayPositionStart = 52;
107
        fftData->bandFilterData[2].arrayPositionStop = 256;
108
        fftData->bandFilterData[2].passFilter = 45000.0F;
109
        fftData->bandFilterData[2].amplitude = 45000;
110
        // very high Teil 1
111
        fftData->bandFilterData[3].arrayPositionStart = 257;
112
        fftData->bandFilterData[3].arrayPositionStop = 281;
113
        fftData->bandFilterData[3].passFilter = 9000.0F;
114
        fftData->bandFilterData[3].amplitude = 8000;
115
        // very high Teil 2
116
        fftData->bandFilterData[4].arrayPositionStart = 282;
117
        fftData->bandFilterData[4].arrayPositionStop = 511;
118
        fftData->bandFilterData[4].passFilter = 21000.0F;
119
        fftData->bandFilterData[4].amplitude = 20000;
120
        
121
        fftData->FrequencyFilterSwitcher = 0x00;
122
    }
123
}

Teil 5 Alle 16 Bänder mit werte füllen und filtern
1
void fillFrequencyBands(fftDataType* fftData)
2
{
3
    // clear band values cache
4
    for (int i = 0; i < 16; i++)
5
    {
6
        fftData->frequencyBarData[i].bandValues = 0;
7
    }
8
    
9
    // catch all frequency data and
10
    // use pass filters for each freq band
11
    // 
12
    //
13
    // i = array index 0-511
14
    // j = band filter index 0-3
15
    // k = frequency bar index 0-16
16
    for (int i = 0; i < FFT_SIZE; i++)
17
    {
18
        for (int j = 0; j < 5; j++)
19
        {
20
            if (i >= fftData->bandFilterData[j].arrayPositionStart && 
21
                i <= fftData->bandFilterData[j].arrayPositionStop)
22
            {
23
                if (fftData->fftOutput[i] > fftData->bandFilterData[j].passFilter)
24
                {
25
                    for (int k = 0; k < 16; k++)
26
                    {
27
                        if (i >= fftData->frequencyBarData[k].arrayPositionStart && 
28
                            i <= fftData->frequencyBarData[k].arrayPositionStop)
29
                        {
30
                            fftData->frequencyBarData[k].bandValues += (uint32_t)fftData->fftOutput[i];
31
                        }
32
                    }
33
                }
34
            }
35
        }
36
    }
37
    
38
    // scale band data for each bar
39
    fftData->frequencyBarData[0].bandValues /= fftData->bandFilterData[0].amplitude;
40
    fftData->frequencyBarData[1].bandValues /= fftData->bandFilterData[0].amplitude;
41
    fftData->frequencyBarData[2].bandValues /= fftData->bandFilterData[0].amplitude;
42
    fftData->frequencyBarData[3].bandValues /= fftData->bandFilterData[1].amplitude;
43
    fftData->frequencyBarData[4].bandValues /= fftData->bandFilterData[1].amplitude;
44
    fftData->frequencyBarData[5].bandValues /= fftData->bandFilterData[1].amplitude;
45
    fftData->frequencyBarData[6].bandValues /= fftData->bandFilterData[1].amplitude;
46
    fftData->frequencyBarData[7].bandValues /= fftData->bandFilterData[1].amplitude;
47
    fftData->frequencyBarData[8].bandValues /= fftData->bandFilterData[1].amplitude;
48
    fftData->frequencyBarData[9].bandValues /= fftData->bandFilterData[2].amplitude;
49
    fftData->frequencyBarData[10].bandValues /= fftData->bandFilterData[2].amplitude;
50
    fftData->frequencyBarData[11].bandValues /= fftData->bandFilterData[2].amplitude;
51
    fftData->frequencyBarData[12].bandValues /= fftData->bandFilterData[2].amplitude;
52
    fftData->frequencyBarData[13].bandValues /= fftData->bandFilterData[2].amplitude;
53
    fftData->frequencyBarData[14].bandValues /= fftData->bandFilterData[3].amplitude;
54
    fftData->frequencyBarData[15].bandValues /= fftData->bandFilterData[4].amplitude;
55
    
56
    fftData->micData.newDataAvailable = 0x01;
57
}

von Audiomann (Gast)


Lesenswert?

Pukixy schrieb:
> Bei Rechteckfensterung im Zeitbereich hat man eine sinc-Funktion
Das würde aber bedeuten, das bei einer Aufteilung eines beliebigen 
Signals, eine Art "Übersprechen" in Nachbarbänder stattfände, welche 
eigentlich die FFT-Analyse im Audiobereich ad absurdum führen würde. 
Schließlich kann niemand wissen, woher ein Signalanteil kommt. Oder wird 
das bei der iFFT wieder kompensiert?

Jürgen S. schrieb:
> Wenn man auf einen Analyzer schaut, dann
> laufen die Amplituden beim Sweep auch in kleinen Wellen.
Bei einem richtigen ordentlichen Audiosignalanalysator sieht man keine 
Wellen. Seit wann das denn?

Kevin Hinrichs schrieb:
> Ich habe beobachtet, dass bei schnellen Bässen manchmal der Pegel oben
> bleibt und manchmal passend zum Bass Beat läuft. Ich glaube das ist auch
> darauf zurück zuführen, dass manche Bässe länger im Raum rum dröhnen.
Das wäre aber richtig gemessen, weil es ja tatsächlich so stattfindet, 
oder?

von Kevin Hinrichs (Gast)


Lesenswert?

Dergute W. schrieb:
> Wenn da z.b. aus einem Bin max. 1023 rauskommen kann, und du z.b. 5 bins
> fuer einen Balken hernehmen willst, und der Balken besteht aus 29
> Segmenten, dann koennte das so gehen:
> (1023*1023)*5 = 5232645
> Damit sollen dann also 29 Segmente leuchten. Und 's soll logarithmisch
> sein.
> Also logarithmiere ich die 5.2 Mio, z.b. mit dem natuerlichen
> Logarithmus. Dann kommt da 15.470 raus.
> Schoener waere aber 29 (fuer eben 29) leuchtende Balken.
> Also musst du die 15.470 noch mit einem Skalierungsfaktor
> multiplizierern, der waere dann 1.875.
> Also waere die "Formel"
> dann:1Seg=1.876*ln(bin(11)*bin(11)+bin(12)*bin(12)+...bin(15)*bin(15))
> Dann musste noch eine "Sicherung" einbauen, denn wenn alle Bins 0 sind,
> macht der ln() Faxen.

Ich möchte mir das gerne mal zusammen bauen.
Meine BIN Werte nach einer fft und nach der Betragsbildung ohne die 
wurzel sind die sehr hoch. Schon bei absoluter stille im raum ca. 30000.

Und wie hast du den Skalierungsfaktor ausgerechnet?

Oder macht es eher sinn in diese Richtung zu gehen?
Habe die Werte mal mit einem Handy und einer App verglichen.
Mit unterschiedlicher Lautstärke. Und das Handy war immer 20dB daneben, 
bei musik. aber wenn der raum leise war, hat es gepasst.
1
// https://de.wikipedia.org/wiki/Schalldruckpegel
2
//
3
// ADC resolution is 12bit -> range from 0 to 4095
4
// max value from soundBuffer is 2048
5
// max value from log10 is 20*log10(1 / 2048) = -66,23dB
6
// dB range is from -66,23dB to 0dB
7
// -66,23dB is silince
8
// 0dB is max loudness
9
//
10
fftData->micData.micVolumeInDezibel = 20.0F * log10(fftData->micData.micRMS / 2048.0F);
11
12
// to get positive values add max dB Value
13
fftData->micData.micVolumeInDezibel += 20.0F * log10(2048.0F);

von Jürgen S. (engineer) Benutzerseite


Angehängte Dateien:

Lesenswert?

Audiomann schrieb:
> Bei einem richtigen ordentlichen Audiosignalanalysator sieht man keine
> Wellen. Seit wann das denn?
Die Wellen sind Folge der "Energiesumme" der Frequenzen, wie das bereits 
erklärt wurde. Als Beispiel die SINC-Funktionen für einige Werte und die 
gewurzelte Summe der Produkte aller Punkte in weiss

Das ist der Verlauf der "Empfindlichkeit" für meinen alten 
5-Band-Analyzer, der u.a. im Equalizer und Kompressor sitzt. Man muss 
sich jetzt noch das shelving hinzudenken / bzw die umgeklappten Verläufe 
am Rand. Im Unterschied zu den Kurven oben ist hier das Vorzeichen noch 
drin, weil es für die Phase wichtig ist. Das fällt bei der FFT weg - 
jedenfalls beim Betrag.

Und ja, die kann man sehen, wenn man sehr hoch aufgelöste Amplituden hat 
und nicht so sehr hochaufgelöste Frequenzen. Geht die FFT in der 
Auflösung ins Unendliche, geht auch die Summe gegen 1.

Die andere Sache mit dem Übersprechen bleibt vom Prinzip her bestehen 
und ist der Grund, warum man ein Signal grundsätzlich nicht mit einer 
FFT endlicher Länge zerlegen und dann fehlerfrei wieder zusammensetzen 
kann.

Audiomann schrieb:
> Oder wird das bei der iFFT wieder kompensiert?
Nein, allgemein nicht. Wie auch?

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Kevin Hinrichs schrieb:
> Und das Handy war immer 20dB daneben,
> bei musik. aber wenn der raum leise war, hat es gepasst.
Das Telefon würde ich mal getrost ignorieren. Das hat ein so massives 
Grundrauschen, dass man unterhalb von 40dBspl nicht vernünftig messen 
kann. Das Thema hatten wir vor einigen Wochen im Musiker-Board. Da habe 
ich und noch jemand Messungen gemacht, um den Ruhepegel im Studio zu 
finden und mit Mikrofonen zu korrelieren.

Kevin Hinrichs schrieb:
> Meine BIN Werte nach einer fft und nach der Betragsbildung ohne die
> wurzel sind die sehr hoch.
Ja, logisch, aber entscheidend ist das was nach der Wurzel rauskommt. 
Die Summe der FFT muss insgesamt 1 sein, sprich: Die Amplitude die 
reinkommt, muss sich 1:1 verteilen. Dazu muss man gedanklich mit 1/Länge 
der FFT "rechnen", wenn es ein weißes Spektrum ist. Durch die 
Formulierung der FFT, die unterschiedlich sein kann, kommt ein 
hochskalierter Wert raus, weil man sonst Bruchteile erhält und unter 
Rundung leider könnte. Sinnvollerweise skaliert man das mit 
durchschnittlich Wurzel(L) - d.h. man verteilt die Auflösung zu gleichen 
Teilen in die Amplitude und in die Frequenz. Das reicht in der Regel, um 
es vernünftig auszuwerten. Das gleiche muss bei dem Bündeln passieren, 
wie ich oben schon schrieb.

von Pukixy (Gast)


Angehängte Dateien:

Lesenswert?

Audiomann schrieb:
> Pukixy schrieb:
>> Bei Rechteckfensterung im Zeitbereich hat man eine sinc-Funktion
> Das würde aber bedeuten, das bei einer Aufteilung eines beliebigen
> Signals, eine Art "Übersprechen" in Nachbarbänder stattfände, welche
> eigentlich die FFT-Analyse im Audiobereich ad absurdum führen würde.
> Schließlich kann niemand wissen, woher ein Signalanteil kommt. Oder wird
> das bei der iFFT wieder kompensiert?

Diesen "Leckeffekt" (Stichwort für entsprechende Literatur) kann durch 
andere Fensterfunktionen verringert werden. Die Mathematik bleibt aber 
die gleiche: Multiplikation der Fensterfunktion im Zeitbereich 
entspricht Faltung mit der Fouriertransformierten der Fensterfunktion im 
Frequenzbereich. Durch andere Fensterfunktionen erhält man im 
wesentlichen weniger starke "Nebenzipfel" im Frequenzbereich, dafür aber 
eine breitere "Hauptkeule".

Die DFT (und die FFT ist die effiziente Berechnung dieser) berechnet ein 
Spektrum eines periodischen Signals über einen endlichen Zeitraum (die 
Fensterlänge). Es wird sozusagen das Spektrum des Signals berechnet, was 
sich ergibt wenn man das Fenster im Zeitbereich periodisch fortsetzt. 
Daher die Verschmierung im Frequenzbereich wenn Frequenz nicht in Raster 
passt.

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Gut erklärt, auch das Bild zeigt das sehr schön (allerdings hat der Auto 
auch dort wieder nur an Fehler abgeschrieben, den die meisten machen, 
nämlich "Hanning").

Wie auch immer: Selbst mit dem besten Fenster ist es nicht zu packen, 
die fehlerhafterweise einbezogenen Frequenzen völlig zu vermeiden. Für 
die Audioanalyse, um zu "Gucken" ist das aber meistens kein Problem, 
weil die anderen Einschränkungen viel mehr "Verschmierung" generieren.

Gleichwohl ist ein gutes Fenster wichtig. Empfehlenswert ist z.B. das 
Blackman-Harris II. Das hat >70dB Seitenbanddämpfung, wenn ich mich 
richtig erinnere.

von Kevin Hinrichs (Gast)


Lesenswert?

Dergute W. schrieb:
> Ein grund waere z.b. dass menschliche Sinne oft eine logarithmische
> Empfindlichkeit aufweisen. Damit kann man grosse Bereiche abbilden. Das
> ist z.b. beim Gehoer so.
> Du musst dir jetzt halt eine Formel basteln, mit der die Werte, die  aus
> der fft purzeln halt "schoen"  auf deinem Display ankommen.
> Wenn da z.b. aus einem Bin max. 1023 rauskommen kann, und du z.b. 5 bins
> fuer einen Balken hernehmen willst, und der Balken besteht aus 29
> Segmenten, dann koennte das so gehen:
> (1023*1023)*5 = 5232645
> Damit sollen dann also 29 Segmente leuchten. Und 's soll logarithmisch
> sein.
> Also logarithmiere ich die 5.2 Mio, z.b. mit dem natuerlichen
> Logarithmus. Dann kommt da 15.470 raus.
> Schoener waere aber 29 (fuer eben 29) leuchtende Balken.
> Also musst du die 15.470 noch mit einem Skalierungsfaktor
> multiplizierern, der waere dann 1.875.
> Also waere die "Formel"
> dann:1Seg=1.876*ln(bin(11)*bin(11)+bin(12)*bin(12)+...bin(15)*bin(15))
> Dann musste noch eine "Sicherung" einbauen, denn wenn alle Bins 0 sind,
> macht der ln() Faxen.

Ich versuche dein Vorschlag umzusetzen.
Nach der FFT mache ich bei der Betragsbildung nur noch Imag * Imag + 
Real * Real. Also keine Wurzel mehr ziehen.
Aus einem BIN kann ein maximaler Wert von 600000000000 als float32_t 
kommen.
Bei absoluter stille im Raum sind die maximalen Werte ca. 600000.
Wenn ich jetzt auf ein Balken nur eine BIN nehmen als Beispiel.
Dann ist für dieser Balken der Maximale Wert = 600000000000.
Wenn ich als logarithmus diesen nehme: 20*log10();

20*log10(600000000000) = 235.56

Für 28 Segmente wäre das denn 28 / 235.56 = 0.118864.
Für meine Berechnung wäre denn:
1
(28 / (20*log10(600000000000))) * 20*log10(BIN_WERT)
Mein Problem dabei ist das schon bei sehr kleinen BIN_WERT sehr viele 
Segmente leuchten. Dies ist aber auch beim dem natuerlichen Logarithmus.
Was kann ich dagegen tun?

Ich dachte dieser logarithmus wäre sinnvoll,
da dieser ja auch für den Schalldruck genommen wird.
Oder ist der natuerlichen Logarithmus besser?

von Kevin Hinrichs (Gast)


Lesenswert?

Jürgen S. schrieb:
> Wie auch immer: Selbst mit dem besten Fenster ist es nicht zu packen,
> die fehlerhafterweise einbezogenen Frequenzen völlig zu vermeiden. Für
> die Audioanalyse, um zu "Gucken" ist das aber meistens kein Problem,
> weil die anderen Einschränkungen viel mehr "Verschmierung" generieren.
>
> Gleichwohl ist ein gutes Fenster wichtig. Empfehlenswert ist z.B. das
> Blackman-Harris II. Das hat >70dB Seitenbanddämpfung, wenn ich mich
> richtig erinnere.

Danke für den Hinweis.
Dies kann ich auch ändern.

Aus allen euren Antworten sind meine Aufgaben:

Meine 16 Balken Ergo 16 Frequenzbänder sinnvoller zusammenfassen.
Ein Beispiel wäre:
Beitrag "Re: Ergebnisse einer FFT zusammen fassen"
Ist auf meiner ToDo Liste.

Blackman-Harris II programmieren und nutzen statt Hamming oder Hann.
Ist auf meiner ToDo Liste.

Die Energiewerte der BINS aus der fft in ein Frequenzband bringen.
Beispiel aufsummieren und logarithmieren.
Bin ich gerade bei.

von Kevin Hinrichs (Gast)


Lesenswert?

Jürgen S. schrieb:
> Gleichwohl ist ein gutes Fenster wichtig. Empfehlenswert ist z.B. das
> Blackman-Harris II. Das hat >70dB Seitenbanddämpfung, wenn ich mich
> richtig erinnere.

Du Meinst den?
https://de.wikipedia.org/wiki/Fensterfunktion#Blackman-Harris-Fenster
1
n = ADC_NUMBER_OF_SAMPLES - 1
2
filterdaten = 0.35875 - 
3
(0.48829 * (cos(Pi2 * n))) + 
4
(0.14128 * (cos(Pi4 * n))) - 
5
(0.01168 * (cos(Pi4 * n)));

von Kevin H. (xerxes777)


Angehängte Dateien:

Lesenswert?

Moin,

ich habe mich mal in diesen Forum angemeldet.

Anbei meine Excel Tabelle für die Ordnung der BINs.
Vielen dank für die vielen Tipps.
Habe mich weiter in die Thematik eingelesen.

Bin am Überlegen mehrere fft's zu machen.
Der Nächste schritt wird sein meine 16 Balken auf die  26 Terzbänder 
geschickt zu verteilen. Habt ihr da vorschläge?
Wenn die Verteilung fix ist,
würde ich mir dann die passenden fft packete zusammen schnüren.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin Hinrichs schrieb:
> Aus einem BIN kann ein maximaler Wert von 600000000000 als float32_t
> kommen.
> Bei absoluter stille im Raum sind die maximalen Werte ca. 600000.

OK, also Maximum ca. 6e+11 und Minimum 6e+5 (haelt die Abnutzung der "0" 
Taste geringer). Macht also ein Verhaeltnis von ca. 1e6 - Bezogen auf 
die Leistung. (daraus die Wurzel, damit wir wieder bei Spannungen 
waeren, wuerde also 1e3 machen, also ca. 1000 also ca. 2^10, koennten 
also ca. 10bit Dynamikumfang bei deinen Samples sein. Klingt fuer mich 
erstmal ungefaehr plausibel).

Kevin Hinrichs schrieb:
> Mein Problem dabei ist das schon bei sehr kleinen BIN_WERT sehr viele
> Segmente leuchten. Dies ist aber auch beim dem natuerlichen Logarithmus.
> Was kann ich dagegen tun?
Welche Geschmacksrichtung Logarithmus du verwendest ist ziemlich 
wurscht. Die unterscheiden sich danach nur noch in einem Faktor.Ich nehm 
mal den dekadischen. Wegen leichterem Kopfrechnen ;-)
Kannste so auf deine 29 LEDs mappen:
1
log(MAX_BIN/MIN_BIN) = ist bei dir jetzt ca. 6
waehrend
1
log(MIN_BIN/MIN_BIN) logischerweise 0 ist.

Also solltest du den Bereich von 0..6 auf einen Bereich von 0..29 
bringen.
Das geht z.b. durch Multiplikation mit
1
29/6= 4.833
Also z.b. so:
1
N_LEDS = 4.833*log(BIN/MIN_BIN)
Dann kannste noch deinen Mathelehrer stolz machen und den Quotienten im 
log auseinanderziehen; und konstante Teile einmal berechnen und nicht 
andauernd.
(Eigentlich muesstest du zur Laufzeit nie irgendwelche Logarithmen 
berechnen, weil die Schwellen, ab der dann eine LED mehr leuchten soll 
auch konstant sind, d.h. den BIN-Wert eben gschickt mit 29 
vorberechneten Konstanten vergleichen, um rauszukriegen wieviele LEDs 
dann leuchten muessen).

Wenn du jetzt mehrere Bins auf einen LED-Balken mappen willst, dann 
musst du halt den 4.833 Skalierungsfaktor entsprechend aendern, damit's 
von den Gesamtwerten wieder passt. Also z.b. bei 7 Bins auf einen 
Balken:
1
log(7*MAX_BIN/MIN_BIN) = ist bei dir jetzt ca. 6+log(7) = 6.8451
damit waere dann der Skalierungsfaktor:
1
29/6.8451 = 4.2366
Klarer?

Gruss
WK

: Bearbeitet durch User
von Audiomann (Gast)


Lesenswert?

Pukixy schrieb:
> Diesen "Leckeffekt" (Stichwort für entsprechende Literatur) kann durch
> andere Fensterfunktionen verringert werden.
Ja, die Nutzung von Fenstern ist mir natürlich bekannt, ich hatte nur 
nie genau darüber nachgedacht, wo und wie sich dieser Leckeffekt genau 
abbildet. Das macht aber Sinn so!

Ich habe da aber gerade ein anderes Problem:

Kevin Hinrichs schrieb:
> n = ADC_NUMBER_OF_SAMPLES - 1
> filterdaten = 0.35875 -
> (0.48829 * (cos(Pi2 * n))) +
> (0.14128 * (cos(Pi4 * n))) -
> (0.01168 * (cos(Pi4 * n)));

Ich habe das heute ausprobiert, komme aber mit der Nummerierung nicht 
klar!
Lasse ich n von 0 ... M-1 laufen, kommt eine leicht unsymmetrische Kurve 
heraus.

Ich habe dazu einen neuen thread aufgemacht.
Beitrag "Unklarheit bez. Index und Samplezahl bei Fensterfunktionen"

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Kevin Hinrichs schrieb:
> Du Meinst den?
Ja, wo die kannst du nehmen. Ich hatte nur in einer Publikation eine 
Abwandlung gelesen, die noch etwas andere Koeffs hatte. Man kann für 
Energien auch Kaiser nehmen, nur ist der nicht so einfach direkt zu 
berechnen. SIN/COS geht ja meistens noch. Für deinen Fall ist BH aber 
wohl das Beste. Aufpassen: der dritte Term ist natürlich X6.

Kevin H. schrieb:
> Der Nächste schritt wird sein meine 16 Balken auf die  26 Terzbänder
> geschickt zu verteilen. Habt ihr da vorschläge?
Ja, siehe hier:
Beitrag "Re: Unklarheit bez. Index und Samplezahl bei Fensterfunktionen"
Z.B: 8 Frequenzen pro Oktaven. Das reicht für 24-32 Frequenzen.

Audiomann schrieb:
> Lasse ich n von 0 ... M-1 laufen, kommt eine leicht unsymmetrische Kurve
> heraus.
Vom Original die Punkte 1 bis M-1 nehmen (ungerade Punktezahl). Siehe 
Antwort dort.
Beitrag "Re: Unklarheit bez. Index und Samplezahl bei Fensterfunktionen"

von Kevin H. (xerxes777)


Lesenswert?

Audiomann schrieb:
> Kevin Hinrichs schrieb:
>> n = ADC_NUMBER_OF_SAMPLES - 1
>> filterdaten = 0.35875 -
>> (0.48829 * (cos(Pi2 * n))) +
>> (0.14128 * (cos(Pi4 * n))) -
>> (0.01168 * (cos(Pi4 * n)));

Sorry Tipp fehler! der letzte ist Pi6 !!!!
1
n = ADC_NUMBER_OF_SAMPLES - 1
2
filterdaten = 0.35875 -
3
(0.48829 * (cos(Pi2 * n))) +
4
(0.14128 * (cos(Pi4 * n))) -
5
(0.01168 * (cos(Pi6 * n)));

von Kevin H. (xerxes777)


Lesenswert?

Jürgen S. schrieb:
> Ja, siehe hier:
> Beitrag "Re: Unklarheit bez. Index und Samplezahl bei Fensterfunktionen"
> Z.B: 8 Frequenzen pro Oktaven. Das reicht für 24-32 Frequenzen.

Wenn ich ganz ehrlich bin, verstehe ich da nicht viel.
Ich verstehe, wenn ich den Blackman-Harris anwende,
das ich dies am besten mit einer ungerade zahl an samples tue.
Ist das richtig?

Ich verstehe nicht, wie sich diese Zahl 24-32 Frequenzen zusammen setzt.
Ich habe 10 Oktaven in den Frequenzen von 31.5Hz bis 16kHz.
Hab ich das richtig verstanden?
Du meinst in einer Oktave befinden sich 3 Terze ?
Das bedeutet 8 mal 3 ergibt 24 Frequenzen für 3 Terze ?
Hab ich das richtig verstanden?

von Kevin H. (xerxes777)


Lesenswert?

Dergute W. schrieb:
> also ca. 10bit Dynamikumfang

Ich habe einen 12bit ADC.
Hab ich einen Fehler gemacht?

Dergute W. schrieb:
> Klarer?

Ja vielen Dank für deine ausführliche Beschreibung.

von Dergute W. (derguteweka)


Lesenswert?

Kevin H. schrieb:
> Ich habe einen 12bit ADC.
> Hab ich einen Fehler gemacht?
Nee, ich wuerde sagen, das passt. Von den 12Bit aus deinem ADC sind halt 
die unteren 2 Bit irgendwelcher Quatsch. Noise oder sonstige Stoerungen. 
Das ist halt so. Wenn dich das massiv aergern sollte, muesstest du halt 
forschen, warum die 2 Bit wackeln. Wuerd' ich aber erst machen, wenn mir 
gaaanz arg langweilig waere.

Ich papp hier mal ein Stueckchen C an, mit dem du dir deine Bin-Grenzen 
ausrechnen lassen kannst. Ist aber nicht gross getestet und ueber's 
richtige Runden an den Bandgrenzen kann man sicher noch lange 
diskutieren, etc.
Wenn's du's mal laufen laesst, kommt z.b. sowas dabei raus:
1
2
3
5
7
10
14
19
27
38
54
78
113
165
241
354

Das bedeutet dann, dass du fuer den Anzeigebalken fuer's niedrigste Band 
eben den Bin 1 nehmen sollst, fuer den naechsten den Bin 2, dann Bin 3 
und Bin 4, dann Bin5+6, dann Bin 7,8 und 9, usw. bis zum letzten 
Anzeigebalken fuer's hoechste Band dann die Bins 354, 355, 356,...
Mit dieser Verteilung sind die Frequenzgrenzen nicht linear (Sonst 
waer's ja einfach: 512/16 = 32), sondern so ungefaehr auch 
logarithmisch.
512 = 9 Oktaven = 108 Halbtonschritte, das auf 16 Baender verteilt, 
macht dann also ca. 6.75 Halbtonschritte pro Band.

Gruss
WK
1
#include <stdio.h>
2
#include <math.h>
3
4
#define N_BARS (16)
5
#define N_BINS (512)
6
int main() {
7
    int i;
8
    float hightolow;
9
    float sum = 0.0;
10
    float prod = 1.0;
11
    float bins_per_bar;
12
    int lowerbin = 1;
13
14
    hightolow = exp(log((float)N_BINS) / (float)N_BARS);
15
    for (i = 0; i < N_BARS; i++) {
16
        sum += pow(hightolow, (float)i);
17
    }
18
    for (i = 0; i < N_BARS; i++) {
19
        printf("%d\n", lowerbin);
20
        bins_per_bar = (prod * (float)N_BINS) / sum;
21
        prod *= hightolow;
22
        lowerbin += ceil(bins_per_bar);
23
    }
24
    return 0;
25
}

von c-hater (Gast)


Lesenswert?

Kevin Hinrichs schrieb:

> Der ADC hat folgende Daten:
>
1
> -ADC resolution = 12BIT
2
> -ADC conversion clock frequency = 16Mhz
3
> -ADC conversion rate = 1Msps
4
> -ADC sample time = 250ns
5
> -ADC conversion time = 1us
6
> -latency from trigger to start of conversion = 2 ADC clocks
7
> -12 shared analog input channels
8
> -Single-ended and differential-input configurations
9
> -Optional phase shift in sample time programmable from 22.5o to 337.5o
10
> -Four programmable sample conversion sequencers from one to eight 
11
> entries long, with corresponding conversion result FIFOs
12
> -Hardware averaging of up to 64 samples
13
> -Efficient transfers using Micro Direct Memory Access Controller (μDMA)
14
>

Reicht mehr als aus für eine sehr hochwertige Anzeige im Audio-Bereich.

Also:
- ADC mehr als ausreichend.
- Rechenleistung mehr als ausreichend.

Der Rest ist dein Job.
- Wahl einer wirklich geeigneten Filterkonfiguration
- Deren Implementierung
- "Nachhübschen", also das, was bei meinem Projekt unter 
"behaviour/colors"
  lief

Dein Problem ist im Wesentlichen, dass du auf FFT gesetzt hast, was für 
diese konkrete Anwendung einfach mal deutlich suboptimal ist. Erkenne 
das endlich, revidiere diese Fehlentscheidung und starte von vorn.

"Suboptimal" heißt übrigens natürlich nicht, dass man nicht auch mit dem 
FFT-Ansatz irgendwas halbwegs brauchbares hinpfuschen könnte. Sondern 
eben einfach nur, dass das halt eine deutlich suboptimale Lösung wäre, 
dass es also mit weniger Rechenleistung und obendrein qualitativ 
besser lösbar ist.

von Jürgen S. (engineer) Benutzerseite


Angehängte Dateien:

Lesenswert?

Kevin H. schrieb:
> wenn ich den Blackman-Harris anwende,
... hat man das Ziel, eine (für Audio) passende Analyse zu bekommen. Der 
eliminiert mit am Besten die direkten Seitenbänder. Der Nutall wäre noch 
in Betracht zu ziehen.

> das ich dies am besten mit einer ungerade zahl an samples tue.
Da geht es nur um die Zahl der Samples die man verwenden will. Häufig 
(aber nicht immer) nimmt man ungerade Anzahlen. Das Fenster muss halt 
passen. Die Thematik gerade / ungerade haben wir bei allen Fenstern.

> Ich verstehe nicht, wie sich diese Zahl 24-32 Frequenzen zusammen setzt.
Weil man "unten" kaum noch Stützstellen hat und es ein bisschen 
willkürlich ist, wie man das zusammenfasst. Aus z.B. 8x8 = 64 Frequenzen 
kann man nicht beliebig sinnvoll zusammenfassen, siehe meine Tabelle 
oben. Unten heum gibt es nichts mehr zum zusammenfassen, sondern es gibt 
gerade 2 Frequenzen die man in die Töpfchen verteilen kann.

Kevin H. schrieb:
> u meinst in einer Oktave befinden sich 3 Terze ?
> Das bedeutet 8 mal 3 ergibt 24 Frequenzen für 3 Terze ?
Z.B. ja. Ich schlage mal Folgendes vor, wenn es FFT sein soll.
Das sind 11 Oktaven mit 16 FFT-Frequenzen von denen jeweils 4 genutzt 
werden. Dann hast du 2-3 Frequenzen, die in und um das Bündel liegen, 
das gebildet werde soll, was n.m.E. reichen sollte.

von Kevin H. (xerxes777)



Lesenswert?

Dergute W. schrieb:
> Moin,
>
> Kevin Hinrichs schrieb:
>> Aus einem BIN kann ein maximaler Wert von 600000000000 als float32_t
>> kommen.
>> Bei absoluter stille im Raum sind die maximalen Werte ca. 600000.
>
> OK, also Maximum ca. 6e+11 und Minimum 6e+5 (haelt die Abnutzung der "0"
> Taste geringer). Macht also ein Verhaeltnis von ca. 1e6 - Bezogen auf
> die Leistung. (daraus die Wurzel, damit wir wieder bei Spannungen
> waeren, wuerde also 1e3 machen, also ca. 1000 also ca. 2^10, koennten
> also ca. 10bit Dynamikumfang bei deinen Samples sein. Klingt fuer mich
> erstmal ungefaehr plausibel).
>
> Kevin Hinrichs schrieb:
>> Mein Problem dabei ist das schon bei sehr kleinen BIN_WERT sehr viele
>> Segmente leuchten. Dies ist aber auch beim dem natuerlichen Logarithmus.
>> Was kann ich dagegen tun?
> Welche Geschmacksrichtung Logarithmus du verwendest ist ziemlich
> wurscht. Die unterscheiden sich danach nur noch in einem Faktor.Ich nehm
> mal den dekadischen. Wegen leichterem Kopfrechnen ;-)
> Kannste so auf deine 29 LEDs mappen:
>
1
log(MAX_BIN/MIN_BIN) = ist bei dir jetzt ca. 6
> waehrend
>
1
log(MIN_BIN/MIN_BIN) logischerweise 0 ist.
>
> Also solltest du den Bereich von 0..6 auf einen Bereich von 0..29
> bringen.
> Das geht z.b. durch Multiplikation mit
>
1
29/6= 4.833
> Also z.b. so:
>
1
N_LEDS = 4.833*log(BIN/MIN_BIN)
> Dann kannste noch deinen Mathelehrer stolz machen und den Quotienten im
> log auseinanderziehen; und konstante Teile einmal berechnen und nicht
> andauernd.
> (Eigentlich muesstest du zur Laufzeit nie irgendwelche Logarithmen
> berechnen, weil die Schwellen, ab der dann eine LED mehr leuchten soll
> auch konstant sind, d.h. den BIN-Wert eben gschickt mit 29
> vorberechneten Konstanten vergleichen, um rauszukriegen wieviele LEDs
> dann leuchten muessen).
>
> Wenn du jetzt mehrere Bins auf einen LED-Balken mappen willst, dann
> musst du halt den 4.833 Skalierungsfaktor entsprechend aendern, damit's
> von den Gesamtwerten wieder passt. Also z.b. bei 7 Bins auf einen
> Balken:
>
1
log(7*MAX_BIN/MIN_BIN) = ist bei dir jetzt ca. 6+log(7) = 
2
> 6.8451
> damit waere dann der Skalierungsfaktor:
>
1
29/6.8451 = 4.2366
> Klarer?
>
> Gruss
> WK

Ich habe mich mal daran versucht.
Ich habe mal die Spannungswerte die vom Mikrofon kommen in RMS Werte 
gewandelt.
1
RMS-Wert = Wurzel((Sample * Sample) / N)
2
N = Anzahl der Samples

Zusätzlich habe ich mich dafür entschieden nach der FFT die 
(Spannungswerte) zu nehmen. Also:
1
BIN_VALUE = WURZEL(I * I + R * R)
Der erster Grund, weil die Werte kleiner sind.
Der Zweite Grund, der Dynamikbereich von den Werten nach der FFT ist ja 
der Selbe, oder?
Entweder von 0 bis ca. 750000 Wenn ich die Wurzel ziehe.
Oder von ca. 6e+5 bis ca. 6e+11 Wenn ich die Wurzel nicht ziehe.
Habe bei meiner Musikanlage die Lautstärke in 10% Schritten von 0% bis 
90% aufgedreht.
Und dabei die min und max der RMS Werte vom Mikro in eine Tabelle 
geschrieben.
Und die min und max der FFT Werte in eine Tabelle geschrieben.
Dabei ist mir ein ziemlich konstanter Factor zwischen max RMS-Wert und 
max FFT-Wert aufgefallen. Dieser Beträgt 365.

Weil ich den ganzen möglichen Dynamikumfang von 0 bis ca. 750000 nicht 
als ganzes logarithmisch darstellen möchte.
Dachte ich mir das ich dies in 4 Lautstärken unterteile.
Um mehr Pegelausschlag zu bekommen. Passend zur Lautstärke die gerade 
läuft.
Der Wertebereich der RMS Werte sind von 0 bis 2048.
Jeder RMS-Wert kann mit Faktor von 365 multipliziert werden um den max 
FFT-Wert der raus kommen könnte zu berechnen.

Ich bilde über einen Ringspeicher und eine starke Hysterese einen 
Durchschnittswert von dem RMS Wert.
Und springe dann in 4 Skalierung:
1
WERTE      LEVEL 0    LEVEL 1   LEVEL 2   LEVEL 3
2
min rms    1          512       1024      1536
3
max rms    511        1023      1535      2048

Jetzt möchte ich wie du empfohlen hast alle Werte einmal berechnen 
lassen.
Aber ich kann den Logarithmus nicht anheben auf der y-achse.
Der Logarithmus ist bei LEVEL 0 denke ich mal okay.
Aber bei den anderen ist er so linear.
Was mache ich falsch?

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Vielleicht könnte man für einen einfachen Fall auch auf die 
Wurzelbildung verzichten, wenn es um das Berechnen von I und Q geht und 
stattdessen die MIN-MAX-Formel nehmen.

von Kevin H. (xerxes777)


Lesenswert?

Jürgen S. schrieb:
> Vielleicht könnte man für einen einfachen Fall auch auf die
> Wurzelbildung verzichten, wenn es um das Berechnen von I und Q geht und
> stattdessen die MIN-MAX-Formel nehmen.

Vielen Dank für deine Antwort.
Könntest du das etwas genauer Beschreibung?
Ich weiß nicht so genau was du meinst.

Mein Ziel ist es von einem Startwert zu einem Endwert mit 29 Schritten 
logarithmisch den Endwert zu erreichen. In meinem Beispiel mit dem 
LOG10().

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin H. schrieb:
> Entweder von 0 bis ca. 750000 Wenn ich die Wurzel ziehe.
> Oder von ca. 6e+5 bis ca. 6e+11 Wenn ich die Wurzel nicht ziehe.

Hmmm - das erstaunt mich etwas, vor allem die 0 - da haette ich entweder 
mit ca. 750 gerechnet oder statt der 6e+5 auch mit 0...

Kevin H. schrieb:
> Jetzt möchte ich wie du empfohlen hast alle Werte einmal berechnen
> lassen.
> Aber ich kann den Logarithmus nicht anheben auf der y-achse.
> Der Logarithmus ist bei LEVEL 0 denke ich mal okay.
> Aber bei den anderen ist er so linear.
> Was mache ich falsch?

Leider keine Ahnung, ich check' nicht was du da vorhast. Mach' nochmal 
in langsam fuer alte Oppas ;-)

Gruss
WK

von Jürgen S. (engineer) Benutzerseite


Lesenswert?

Kevin H. schrieb:
> Könntest du das etwas genauer Beschreibung?
Ich erinnere mich leider nicht mehr an die offizielle Bezeichnung, aber 
man kann das überschlägig abschätzen, wenn man den I- und den Q-Anteil 
linear verrechnet. Dazu nimmt man den größeren der beiden Werte als 
"MAX" und den kleineren als "MIN" an und rechnet A * MAX + B * MIN.

Die Werte für A und B habe ich nicht mehr im Kopf aber es war so etwas 
wie 0,95 und 0,35. Es werden glaube ich Sekantenlängen berechnet und der 
Fehler der anderen Koordinate gemittelt. Hatten wir mal im Mathekurs und 
ich habe das am C64 mit den Werten 242 und 100 oder so gemacht. Das 
kommt etwa hin. Fehler etwa 3%.

Das braucht heute natürlich keiner mehr, aber für solche einfachen 
LED-Sachen, könnte das reichen.

Fürs Logarithmieren habe ich auch etwas aus meinen ersten Synth:

Man teilt die Skala in 4 Einheiten je Oktave auf und bekommt als Abfrage 
eine verschachtelte IF-Anweisung, die von oben her immer die 4 oder 5 
höchsten Bits betrachtet. Ausgehend von einem 16 Bit-Vektor und 
Betrachtung von 5 Bits:

Wenn (15 ... 11) >= 23 -> LED N-1 an
Else (15 ... 11) >= 11 -> LED N-2 an
Else (15 ... 11) >=  6 -> LED N-3 an
Else (15 ... 11) >=  2 -> LED N-4 an

Else (14 ... 10) >= 23 -> LED N-5 an
Else (14 ... 10) >= 11 -> LED N-6 an
Else (14 ... 10) >=  6 -> LED N-7 an
Else (14 ... 10) >=  2 -> LED N-8 an

Else (13 ...  9) >= 23 -> LED N-9 an
Else (13 ...  9) >= 11 -> LED N-10 an
Else (13 ...  9) >=  6 -> LED N-11 an
Else (13 ...  9) >=  2 -> LED N-12 an

u.s.w

Man muss sich dazu einfach eine Tabelle machen, die die betrachteten 
Bits enthält und die Bereiche einteilen. Die Zahl der betrachtenden Bits 
muss ausreichend sein, damit die Umschaltabfragen genügend gut an der 
korrekten Stelle sitzen. Die Kombi 4 Bit hat bei 24 Bit Audio gut 
funktioniert.

Dann sind die Abfragewerte halbiert also 12,5,3,1.

: Bearbeitet durch User
von Jürgen S. (engineer) Benutzerseite


Angehängte Dateien:

Lesenswert?

So gerade nachgeguckt:

Meine Pyra 3 benutzt 6/7 bit und die Werte >85 , >39, > 16>, >7, >3, >0 
um 6 dB pro Faktor 2 aufzulösen. Das ist völlig ausreichend, wenn man 
Einzelkanäle in etwa pegeln will und schauen möchte, ob overflow droht.
Benutzt werden die lila Einträge für 1dB Abstände. Man kann natürlich 
schon früher weitere Bits hinzu nehmen.

Die Pyra 4 arbeitet mit dynamischem Vergleich von den jeweils relevanten 
7 Bits. Ich habe nach unten raus die Abfragen sogar so angepasst, dass 
echte 6,00 dB entstehen und nicht die ungefähren LOG (2,10) * 20 = 
6,020599913dB.

Braucht man das nicht, kann man die Tabellenstruktur nach unten linear 
fortsetzen.


Eine sehr einfache Abbildung ist natürlich die Binärdarstellung an sich:
Man nimmt einfach von einem 24 Bit Wert, das jeweils höchste als 
Massstab und macht eine von 24 LEDs an.

Nächster Schritt: Man quadriert den Wert und hat dann 48 Bit. Reicht 
dann für 48 LEDs.

Für eine audiokompatible Anzeige könnte noch den Wert X hoch 6 nehmen. 
Macht dann 24 * 6 = 144 dB als Einzelbits. Das entspricht ungefähr der 
Dynamik der 24 Bit in Dezibel (Zehnerlogarithmus). Davon die obersten 32 
geschnappt und noch mal quadriert und man hat eine Audioanzeige mit etwa 
0 dB full scale - - 63dB und halber dB-Auflösung.

In einer sehr frühen DSP-APP für meine Chameleon habe ich das so 
gemacht, ist aber nicht so effektiv, was das rechnen angeht. Man muss 
unterwegs auch runden und abschneiden, weil man sonst zu große 
Datentypen bekommt.

von Kevin H. (xerxes777)


Lesenswert?

c-hater schrieb:
> Was ich verwende, sind sozusagen einzelne Bins einer FFT
> (Goertzel-Filter). Das hat den Vorteil, dass man für jeden einzelnen Bin
> getrennt die Bandbreite einstellen kann. Genau das ist nützlich, um dein
> aktuelles Problem quasi bereits vor seiner Entstehung zu lösen.
>
> Ein weiterer Vorteil der Goertzel-Filter ist, dass viel weniger
> Rechenaufwand anfällt, solange die Zahl der Bins klein im Verhältnis zur
> FFT ist. Und das ist er immer dann, wenn du mit einer FFT einen großen
> Frequenzbereich erfassen willst, aber die Auflösung im unteren
> Frequenzbereich auch noch recht hoch sein muss. Also genau die Sachen,
> die in deiner Anwendung zutreffend sind.

Weiß einer wie das geht?
Im Internet habe ich nichts brauchbares für mich gefunden.
Ich brauche ein Beispiel am besten mit C Pseudo Code.
Das ich mir das besser vorstellen kann.

An dieser Stelle möchte ich mich nochmal für all eure Vorschläge 
bedanken. Ich habe soweit es mir möglich war diese mit ins Projekt 
einfließen lassen.

Als nächstes möchte ich mich von der fft trennen und dies mit der oben 
genanten Methode probieren.

Ich habe viel probiert um die Pegel der LED Balken logarithmisch zu 
skallieren.
Optisch gefällt mir diese Skallierung ganz gut. Diese habe ich für jedes 
Band etwas angepasst. Diese kleinen min und max Werte gehen nur, da ich 
die Samples auf einen ca. fixen RMS Wert skalliere, bevor diese durch 
die fft gehen.
1
#include <stdio.h>
2
#include <math.h>
3
4
void main()
5
{
6
    static float min[16];
7
    static float max[16];
8
    const float n_LEDs = 28.0F;
9
    const float n_LEDs_2 = n_LEDs + 1.0F;
10
    const float bend = 100.0F;
11
    
12
    const float minFactor = 1.5F;
13
    const float maxFactor = 2.8F;
14
    
15
    const float minFactor_high1 = 0.6F;
16
    const float maxFactor_high1 = 0.8F;
17
    
18
    const float minFactor_high2 = 0.7F;
19
    const float maxFactor_high2 = 0.6F;
20
    
21
    // BAR 0
22
    min[0] = 40000 * minFactor;
23
    max[0] = 1000000 * maxFactor;
24
    
25
    // BAR 1
26
    min[1] = 40000 * minFactor;
27
    max[1]= 1000000 * maxFactor;
28
    
29
    // BAR 2
30
    min[2] = 40000 * minFactor;
31
    max[2]= 1000000 * maxFactor;
32
    
33
    // BAR 3
34
    min[3] = 50000 * minFactor;
35
    max[3]= 1500000 * maxFactor;
36
    
37
    // BAR 4
38
    min[4] = 50000 * minFactor;
39
    max[4]= 1500000 * maxFactor;
40
    
41
    // BAR 5
42
    min[5] = 90000 * minFactor;
43
    max[5]= 1500000 * maxFactor;
44
    
45
    // BAR 6
46
    min[6] = 280000 * minFactor;
47
    max[6]= 1500000 * maxFactor;
48
    
49
    // BAR 7
50
    min[7] = 280000 * minFactor;
51
    max[7]= 1500000 * maxFactor;
52
    
53
    // BAR 8
54
    min[8] = 250000 * minFactor;
55
    max[8]= 1800000 * maxFactor;
56
    
57
    // BAR 9
58
    min[9] = 250000 * minFactor;
59
    max[9]= 1800000 * maxFactor;
60
    
61
    // BAR 10
62
    min[10] = 200000 * minFactor;
63
    max[10]= 1800000 * maxFactor;
64
    
65
    // BAR 11
66
    min[11] = 200000 * minFactor;
67
    max[11]= 1800000 * maxFactor;
68
    
69
    // BAR 12
70
    min[12] = 200000 * minFactor;
71
    max[12]= 1500000 * maxFactor;
72
    
73
    // BAR 13
74
    min[13] = 200000 * minFactor;
75
    max[13]= 1800000 * maxFactor;
76
    
77
    // BAR 14
78
    min[14] = 400000 * minFactor_high1;
79
    max[14]= 2000000 * maxFactor_high1;
80
    
81
    // BAR 15
82
    min[15] = 400000 * minFactor_high2;
83
    max[15]= 2000000 * maxFactor_high2;
84
    
85
    // create datatype
86
    printf("__root const uint32_t barHeights_bar[16][%.0f] = {", n_LEDs_2);
87
    printf("\n");
88
    //printf("{");
89
    printf("\n");
90
    
91
    for (int i = 0; i < 16; i++)
92
    {
93
        printf("{");
94
        for (int j = 0; j < n_LEDs_2; j++)
95
        {
96
            float potenz = pow((bend + 1.0F), j / n_LEDs);
97
            float data = 1.0F / bend * ((bend + 1.0F) * min[i] - max[i] + (max[i] - min[i]) * potenz);
98
            printf ("%.0f", data);
99
            
100
            if (j == n_LEDs_2 - 1 && i != 15)
101
            {
102
                printf("},");
103
                printf("\n");
104
                printf("\n");
105
            }
106
            
107
            if (j != n_LEDs_2 - 1)
108
            {
109
                printf(", ");
110
            }
111
            
112
            // 4 numbers in one row
113
            if (j % 8 == 7)
114
            {
115
                printf ("\n");
116
            }
117
        }
118
    }
119
    printf("}");
120
    printf("\n");
121
    printf("};");
122
}

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin H. schrieb:
> Weiß einer wie das geht?
> Im Internet habe ich nichts brauchbares für mich gefunden.
> Ich brauche ein Beispiel am besten mit C Pseudo Code.
> Das ich mir das besser vorstellen kann.

Hier
https://en.wikipedia.org/wiki/Goertzel_algorithm
gibt's doch ("weiter unten") Pseudocode.

Sonst musst du halt c-haters "grosses Gemaecht"
Beitrag "Re: Audio Spektrum Analyzer mit ATtiny85"
ausgiebig bewundern, vielleicht rueckt er dir dann was sourcecodeartiges 
'raus ;-)

Gruss
WK

von c-hater (Gast)


Lesenswert?

Dergute W. schrieb:

> Sonst musst du halt c-haters "grosses Gemaecht"
> Beitrag "Re: Audio Spektrum Analyzer mit ATtiny85"
> ausgiebig bewundern, vielleicht rueckt er dir dann was sourcecodeartiges
> 'raus ;-)

Wie bereits in dem damaligen Thread angemerkt: Der Designer ist in 
VB.net geschrieben. Und er enthält u.A. eine nahezu vollständige 
Simulation des µC-Codes (umgesetzt natürlich mit den Mitteln von VB.net 
und bezüglich der grafischen Ausgabe angepaßt auf das Target, d.h.: 
WS28xx-Ansteuerung ist durch Ausgabe auf das verfügbare GUI ersetzt und 
die UART-Ausgabe gibt's garnicht).

Und es ist kein Problem, so ein .net-Binary in sehr gut lesbaren 
Quelltext zu verwandeln (wenn man das nicht künstlich durch 
Code-Obfuscation verhindert, was ich nicht getan habe).
Man hat sogar die Wahl, ob man es in VB oder C# haben will, ganz 
unabhängig davon, in welcher der beiden Sprachen es geschrieben wurde. 
Also sind selbst die C-only-Hirnies nicht völlig hilflos, mit dem 
C#-Code sollten selbst diese Schmalspur-Idioten schon durchaus was 
anfangen können.

Aber mal ganz unabhängig vom Quelltext: die meisten wesentlichen Tricks 
stehen eigentlich sogar schon in der damaligen textuellen Beschreibung 
der Architektur. Das ist halt alles so hingetrimmt, dass es die gegebene 
Aufgabe mit möglichst wenig Rechenzeitaufwand erfüllen kann. Die 
verwendeten Filter sind beschrieben, wenn man weiss, wie die 
funktionieren, weiss man auch, warum ich sie gewählt habe und durch 
Verwendung welcher Besonderheiten der gegenüber der allgemeinen Form 
relativ geringe Rechenzeitaufwand möglich wird.

von Kevin H. (xerxes777)


Lesenswert?

> Wie bereits in dem damaligen Thread angemerkt: Der Designer ist in
> VB.net geschrieben. Und er enthält u.A. eine nahezu vollständige
> Simulation des µC-Codes (umgesetzt natürlich mit den Mitteln von VB.net
> und bezüglich der grafischen Ausgabe angepaßt auf das Target, d.h.:
> WS28xx-Ansteuerung ist durch Ausgabe auf das verfügbare GUI ersetzt und
> die UART-Ausgabe gibt's garnicht).
>
Der Designer ist eine fertige ausführbare Datei.
Ich wüsste jetzt nicht, wie ich die debuggen könnte.
Ist aber nicht schlimm.

> Und es ist kein Problem, so ein .net-Binary in sehr gut lesbaren
> Quelltext zu verwandeln (wenn man das nicht künstlich durch
> Code-Obfuscation verhindert, was ich nicht getan habe).
> Man hat sogar die Wahl, ob man es in VB oder C# haben will, ganz
> unabhängig davon, in welcher der beiden Sprachen es geschrieben wurde.
> Also sind selbst die C-only-Hirnies nicht völlig hilflos, mit dem
> C#-Code sollten selbst diese Schmalspur-Idioten schon durchaus was
> anfangen können.

Das ganze muss auf einen ARM Cortex M4 umgesetzt werden.
Und da habe ich schon herausgefunden, das es ASM MAC Instructions gibt.
Diese sollen sehr hilfreich sein für DSP Anwendungen.
Ich arbeite mich immer weiter in ASM ein.
Bin aber noch ganz weit weg davon ein Programm zu schreiben.
Habe ja erst Anfang des Jahres mit C und diesem Projekt angefangen.

>
> Aber mal ganz unabhängig vom Quelltext: die meisten wesentlichen Tricks
> stehen eigentlich sogar schon in der damaligen textuellen Beschreibung
> der Architektur. Das ist halt alles so hingetrimmt, dass es die gegebene
> Aufgabe mit möglichst wenig Rechenzeitaufwand erfüllen kann. Die
> verwendeten Filter sind beschrieben, wenn man weiss, wie die
> funktionieren, weiss man auch, warum ich sie gewählt habe und durch
> Verwendung welcher Besonderheiten der gegenüber der allgemeinen Form
> relativ geringe Rechenzeitaufwand möglich wird.

Die habe ich mehrmals gelesen und mir dazu meine Gedanken gemacht.
Bin gerade dabei mich in die DSP Themen FIR und IIR Filter einzulesen 
und wie diese "Rechenwerke" so funktionieren.
Bei meiner weiterem Recherche ist mir auch aufgefallen, das der goertzel 
Algo auch eine Art IIR Filter sein soll.

Zum goertzel Algo habe ich eine Frage:
Ich lese das ich wissen muss wie viele Samples ich durch bringen möchte.
Dies bedeutet, ich muss eine N Anzahl an Samples Sammeln z.B 1024?
Wenn das der Fall ist, wie hast du denn die schnelle reaktionszeit 
hinbekommen?
1
Als Beispiel:
2
Fs (SampleRate) = 40kHz (das Mikrofon kann 20Hz - 20kHz)
3
N = 1024
4
BIN_SIZE = Fs / N = 39 Hz
5
Dauer bis alle 1024 Samples aufgenommen wurden sind = 25,6ms

Ich muss also für niedrige Frequenzen viele Samples aufnehmen?
Oder kann ich einfach die Fs kleiner machen und somit die Anzahl N 
reduzieren?
Aber dann ist Fs < 40kHz und dann halte ich mich nicht mehr an das 
Nyquist Theorem.

Ich habe noch viel mehr Fragen, aber das solls erstmal gewesen sein.
Ich habe auch die weiter Entwicklung dieses Projekt mit der fft 
abgebrochen.
Ich möchte das Projekt neu erstellen mit der hilfe des goertzel Algo.

von c-hater (Gast)


Lesenswert?

Kevin H. schrieb:

> Und da habe ich schon herausgefunden, das es ASM MAC Instructions gibt.

Das ist für Signalverarbeitung oft ein sehr hilfreiches Feature, wird 
aber für diese konkrete Anwendung nicht gebraucht. Die Filter und ihre 
Parameter sind so gewählt, dass schon kaum was zu Multiplizieren ist, 
denn schon das konnte das damalige Target nicht in Hardware (geschweige 
den MAC-Operationen).

> Bei meiner weiterem Recherche ist mir auch aufgefallen, das der goertzel
> Algo auch eine Art IIR Filter sein soll.

Nur die verwendeten Halbbandfilter sind echte IIRs.

Die Goertzels hingegen arbeiten zwar auch ein wenig wie IIRs, sind aber 
nicht wirklich welche, denn eine ganz wesentliche Eigenschaft fehlt 
ihnen dazu: sie sind eben nicht "infinite", ihre Laufzeit ist begrenzt. 
Das ist gut, denn es macht sie deutlich einfacher handhabbar. Man 
braucht sich um einige Probleme echter IIRs nicht zu kümmern...

> Oder kann ich einfach die Fs kleiner machen und somit die Anzahl N
> reduzieren?

Genau das ist einer der wesentlichen konzeptionellen Tricks: Statt den 
Kram mit einer FFT in kleine Einzelbänder gleicher Bandbreite zu 
zerlegen und dann wieder aufwendig zusammenzu"addieren", um einige 
wenige Bänder unterschiedlicher Bandbreite zu bekommen, werden die 
Goertzels halt gleich auf die passende Bandbreite und Mittenfrequenz für 
die Anwendung ausgelegt. In dem Zusammenhang kommt dann auch gleich der 
zweite Trick zur Anwendung: die logarithmische Stufung der 
Mittenfrequenz in Oktaven und die konstante Bandbreite relativ zur 
jeweiligen Mittenfrequenz.
Dadurch ist dann die Implementierung für (fast) alle Goertzels 
identisch. Nur der eine für die höchste Mittenfrequenz weicht etwas ab 
vom Rest.

von Kevin H. (xerxes777)


Lesenswert?

Vielen Dank für die Infos.

Ich habe mir mal als Lektüre
https://npr.hs-schmalkalden.de/files/CategoryKommunikationstechnik/Realisierung_Digitaler_Filter_in_C.pdf
dieses Buch zugelegt. Das PDF alleine finde ich schon interessant.

Hätte jemand noch eine Empfehlung, wo ich weiter Wissen zu diesem Thema 
aufnehmen kann?

Meine 1. Internet suche über den Goertzel Algo ergab, das es wohl 
verschiedene Versionen von diesem gibt?
Hab auch welche in Büchern gefunden, diese sind dann statt dem sin(w) 
mit einer exp funktion. ich denke das dies nicht falsch ist und das 
dafür eine mathematische Begründung gibt.
Oft wird auch für k ein faktor < 1.00 mit eingebunden.
Skalliert man damit etwas?
1
======================= Version 1 =======================
2
INFO:
3
https://www.youtube.com/watch?v=37N0ra1CnnI&list=PL75kaTo_bJqmw0wJYw3Jw5_4MWBd-32IG&index=6
4
5
ASM:
6
http://stevenmerrifield.com/papers/hons_thesis.pdf
7
8
======================= Version 1 =======================
9
10
======================= Version 2 =======================
11
https://www.embedded.com/the-goertzel-algorithm/
12
13
k = (int) (N * (TARGET_FREQUENCY / SAMPLING_RATE) + 0.5);
14
15
w = (2*π/N)*k
16
cosine = cos w
17
sine = sin w
18
coeff = 2 * cosine
19
20
For the per-sample processing youre going to need three variables. Lets call them Q0 , Q1 , and Q2 .
21
22
Q1 is just the value of Q0 last time. Q2 is just the value of Q0 two times ago (or Q1 last time).
23
24
Q1 and Q2 must be initialized to zero at the beginning of each block of samples. For every sample, you need to run the following three equations:
25
26
Q0 = coeff * Q1  Q2 + sample
27
Q2 = Q1
28
Q1 = Q0
29
30
real = (Q1  Q2 * cosine)-
31
imag = (Q2 * sine)
32
magnitude2 = real2 + imag2
33
34
////// An Optimized Goertzel
35
magnitude2 = Q1 2 + Q2 2 -Q1 *Q2 *coeff
36
37
When to Use the Goertzel Algorithm Instead of the FFT?
38
Where M is the number of frequency coefficients of the DFT to be obtained.
39
M < 5 * N_2 * log2(N_2) / (6 * N)
40
41
======================= Version 2 =======================
42
43
======================= Version 3 =======================
44
https://github.com/Harvie/Programs/blob/master/c/goertzel/goertzel.c
45
46
float goertzel_mag(int numSamples,float TARGET_FREQUENCY,int SAMPLING_RATE, float* data)
47
{
48
    int     k,i;
49
    float   floatnumSamples;
50
    float   omega,sine,cosine,coeff,q0,q1,q2,magnitude,real,imag;
51
52
    float   scalingFactor = numSamples / 2.0;
53
54
    floatnumSamples = (float) numSamples;
55
    k = (int) (0.5 + ((floatnumSamples * TARGET_FREQUENCY) / (float)SAMPLING_RATE));
56
    omega = (2.0 * M_PI * k) / floatnumSamples;
57
    sine = sin(omega);
58
    cosine = cos(omega);
59
    coeff = 2.0 * cosine;
60
    q0=0;
61
    q1=0;
62
    q2=0;
63
64
    for(i=0; i<numSamples; i++)
65
    {
66
        q0 = coeff * q1 - q2 + data[i];
67
        q2 = q1;
68
        q1 = q0;
69
    }
70
71
    // calculate the real and imaginary results
72
    // scaling appropriately
73
    real = (q1 * cosine - q2) / scalingFactor;
74
    imag = (q1 * sine) / scalingFactor;
75
76
    magnitude = sqrtf(real*real + imag*imag);
77
    //phase = atan(imag/real)
78
    return magnitude;
79
}
80
======================= Version 3 =======================
81
82
======================= Version 4 =======================
83
https://medium.com/geekculture/the-great-unknown-the-goertzel-algorithm-492681f30866
84
//////MATLAB
85
86
function [I, Q] = goertzel(x, k, N)
87
w = 2*pi*k/N;
88
cw = cos(w); c = 2*cw;
89
sw = sin(w);
90
z1=0; z2=0; % init
91
for n = 1 : N
92
   z0 = x(n) + c*z1 - z2;
93
   z2 = z1;
94
   z1 = z0;
95
end
96
% real part (in-phase)
97
I = cw*z1 - z2;
98
% imaginary part (quadrature-phase)
99
Q = sw*z1;
100
======================= Version 4 =======================
101
102
======================= Version 5 =======================
103
https://medium.com/reverse-engineering/audio-player-with-voice-control-using-arduino-a-frequency-analyzer-based-on-the-goertzel-algorithm-6f79766e37ad
104
105
Goertzel(float TARGET_FREQUENCY,float BLOCK,float SAMPLING_FREQ){
106
  SAMPLING_RATE=SAMPLING_FREQ;  //9KHz for a 16MHz Arduino
107
  TARGET=TARGET_FREQUENCY; //must be an integer of SAMPLING_RATE/N
108
  N=BLOCK;  //Block size
109
  int k;
110
  float omega;
111
112
  //math
113
  k = (int) (N * (TARGET_FREQUENCY / SAMPLING_RATE) + 0.93);
114
  omega = (2.0 * PI * k) / N;
115
  sine = sin(omega);
116
  cosine = cos(omega);
117
  coeff = 2.0 * cosine;
118
119
  ResetGoertzel();
120
}
121
======================= Version 5 =======================
122
123
======================= Version 6 =======================
124
https://hackaday.com/2020/11/13/dsp-spreadsheet-the-goertzel-algorithm-is-fouriers-simpler-cousin/
125
126
omega_r = cos(2.0*pi*k/N);
127
omega_r2=2*omega_r;
128
omega_i = sin(2.0*pi*k/N);
129
 
130
P = 0.0;
131
S = 0.0;
132
for (n=0; n<N; ++n)
133
{
134
   y = x(n) + omega_r2*P -S;
135
   S = P;
136
   P = y;
137
}
138
realy = omega_r*P - S; // note that hear P=last result and S is the one before
139
imagy=omega_i*P;
140
magy=abs(complex(realy,imagy));  // mag=sqrt(r^2+i^2);
141
142
143
//EXCEL:
144
https://docs.google.com/spreadsheets/d/1ETvhZM02maPIAx94Wli8fcmI0l7yq_-8cUt3atNslhc/edit?usp=sharing
145
146
======================= Version 6 =======================
147
148
======================= Version 7 =======================
149
buch
150
matlab
151
152
function y = goertzel 2 (x,k)
153
§ Goertzel-Algorithmus (based on 2nd order system)
154
% function y = goertzel 2 (x, k)
155
% x : time signal of length N
156
% k: index of dft coefficient
157
% y: kth dft coefficient
158
159
N = length (x) ;
160
w = 2*pi*k/N;
161
v1 = 0; v2 = 0; a1 = - 2*cos (w) ;
162
for n = 1:N
163
v0 = x (n) - al*v1 - v2;
164
v2 = v1;
165
v1 = v0;
166
end
167
Y = -al*v1 - v2 -exp (-1i*w)*v1;
168
return
169
170
======================= Version 7 =======================

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin H. schrieb:
> Hätte jemand noch eine Empfehlung, wo ich weiter Wissen zu diesem Thema
> aufnehmen kann?

Ich les' ganz gerne Zeugs von Rick Lyons.

Gruss
WK

von c-hater (Gast)


Lesenswert?

Kevin H. schrieb:

> Meine 1. Internet suche über den Goertzel Algo ergab, das es wohl
> verschiedene Versionen von diesem gibt?

Nunja, grundsätzlich gibt es zwei "Versionen". Die unterscheiden sich im 
Wesentlichen dadurch, ob dich nur die Magnitude interessiert oder auch 
die Phase.

In der konkreten Anwendung ist nur die Magnitude von Interesse. Dadurch 
ergibt sich gegenüber der "full blown"-Variante einiges an 
Einsparpotential. Deswegen habe ich natürlich diese gewählt.

von Kevin H. (xerxes777)


Lesenswert?

c-hater schrieb:
> Kevin H. schrieb:
>
>> Meine 1. Internet suche über den Goertzel Algo ergab, das es wohl
>> verschiedene Versionen von diesem gibt?
>
> Nunja, grundsätzlich gibt es zwei "Versionen". Die unterscheiden sich im
> Wesentlichen dadurch, ob dich nur die Magnitude interessiert oder auch
> die Phase.
>
> In der konkreten Anwendung ist nur die Magnitude von Interesse. Dadurch
> ergibt sich gegenüber der "full blown"-Variante einiges an
> Einsparpotential. Deswegen habe ich natürlich diese gewählt.

Mit deiner Info hast du meine Vermutung bestätigt.
Danke.

Mein Ziel ist es mit dieser Hardware das best mögliche Ergebnis zu 
erreichen.
Ich möchte einmal eine kleine Zusammenfassung machen.
Dieses Projekt muss weiterhin auf das Entwicklungsboard von TI 
entwickelt werden:
1
Hardware:
2
- EK-TM4C123GXL mit einem Arm Cortex-M4F (TM4C123GH6PM)
3
- 80 Mhz
4
- 256kB Flash
5
- 32kB SRAM
6
- 2 x ADC 12bit
7
- ADC conversion clock frequency = 16Mhz
8
- ADC conversion rate = 1Msps
9
- ADC Hardwareoversampling
10
- DMA
11
- Als Mikrofon wird ein MAX4466 (20Hz bis 20kHz) eingesetzt.
12
- WS2812b LED Stripe
13
14
ADC Konfig:
15
- Samplerate = 40Khz über Timer fix ???
16
- Anzahl der Samples die über DMA vom ADC in ein Array geschoben werden: 1 - ?? Als eine Art Puffer. Damit die MCU zeit bekommt die LED Effekte zu machen und das LEDSignal vorbereitet werden kann.
17
- Hardwareoversampling = 2, 4, 8, 16, 32, 64 ??
18
- Conversations Rate mit Hardwareoversampling = 500Mhz, 250Mhz, 125Mhz, 62,5kHz, 31,25Khz, 15,625kHz
19
(Aus der Doku:
20
Enabling hardware averaging increases the precision of the ADC at the cost of throughput. For example, enabling 4x oversampling reduces the throughput of a 250 k samples/second ADC to 62.5 k samples/second.)
21
22
DSP Konfig:
23
- Alle 26 Terzbänder + 10. Octave mit der jeweiligen Mittenfrequenz.
24
- Bandbreite zwischen den Mittenfrequenzen: ???
25
- Durch die FPU sind Fließkommazahlen zu bevorzugen
26
- einen geeigneten Filter finden für die jeweiligen Mittenfreqenzen der 26 Terzbänder.
27
- Das Mic hat einen DC-Offset von Vin/2. Dies wird durch Mittelwertbildung abgezogen.
28
- Lösung finden: Wenn die Musiklautstärke erhöht / verringert wird, muss dies auf die Balkenauschläge skalliert werden.
29
- goertzel algo für die spectral analyse

Wenn ich dies mit dem oben genannten Mikrofon umsetzte.
Dann wäre meine Grundfreqzenz des Analogen Signals 20Hz.
Und alle weiteren Frequenzen bis 20kHz,
wären die Oberschwingungen.
Bedeutet dies ich müsste exakt einen Theoretischen Trigger dort haben,
wann die Grundfrequenz von Ihrer Amplitude = 0 ist und solange Sample 
werte aufnehmen bis eine Periode dieser abgeschlossen ist.
Dies wäre denn doch eine perfekte Aufnahme, um ohne eine Fernsterung die 
Samples weiter zu verwenden?
Kann mein ADC dies mit diesem Comperator Mode?
Welche MCU Techniken werden für sowas benutzt?

Wenn ich mich für dieses Hardwareoversampling entscheide, kann ich 
dadurch die Auflösung etwas steigern, richtig?
Kann ich dadurch auch das Signal / Raus Verhältnis optimieren?
Wenn ich das richtig sehe, ist der maximale möglicher Wert 16, damit ich 
noch eine Samplerate von 40kHz schaffen kann.

Habe 16 LED Balken. Oben wurde schonmal erwählt dies wäre denn ein 
Halber Terzband Analyzer. Wie genau ist das gemeint.
Es gibt doch nur 26 Terzbänder?
Und welche Terzbänder ich auf die 16 Balken verteile, muss ich noch 
heraus finden. Wenn ich jedes 2te nehme bekomme ich ja nur 13. Brauche 
aber 16. Und dann komme ich nur bis 10Khz. Möchte aber die die vollen 
20kHz abdecken.
Aber unabhängig davon, würde ich gerne alle Terzbänder als 
MittenFrequenz nutzen wollen. Da oben erwähnt wurden ist, dass das 
Prozedere ähnlich ist. Und evtl. ist es möglich aus den 16 Balken 32 
Balken zu machen.

Mit der Skalierung der Balkenausschläge, wenn die Musik Lautstärke sich 
ändert ist folgendes gemeint.
Mit der 12BIT Auflösung ist Dynamikumfang von:
20*LOG10(2^11) = ca. 66 Dezibel vorhanden. richtig?
Ein BIT weniger weil ich durch 2 Teilen muss, da ich Werte im positiven 
und negativen Bereich habe. Richtig ?
Was ich aber nicht möchte das ein Balken erst bei dieser Lautstärke voll 
ausschlägt.

In der Regel dreht man nicht ständig an der Lautstärke. Wenn die Musik 
läuft stellt sich ein durchschnitts und max Wert ein. Und auf diesen Max 
Wert würde ich gerne Skallieren.

Wenn ich die parameter für goertzel algo festlegen und errechnen möchte. 
Kann ich mit der N anzahl an Samples und mit der Samplefrequenz spielen. 
Wenn ich allerdings mein Signal unter abtaste, muss ich aufpassen und 
eine antialaising filter benutzen?

Kann ich einfach, wenn ich mit 40kHz das Signal abtaste und meine 
Samplefrequenz halbieren möchte, nur jeden 2ten Samples nehmen?
Oder ist das Kinderkacke?

Zusätzlich habe ich 2 ADC und diese können mit unterschiedlichen 
SampleRate vom timer parametriert werden. Kann ich mir das irgendwie zu 
nutzen machen? Bekomme dann allerdings die doppelte menge an Samples die 
ja verarbeitet werden müssen.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Uiuiui, so fiele Vragen ;-)
Kevin H. schrieb:
> - Alle 26 Terzbänder + 10. Octave mit der jeweiligen Mittenfrequenz.
Also wieviele Filter/LED-Bars willst du haben?
26Terzen=8.667 Oktaven und dann noch eine 10. dazu?
Ich bin verwirrt.

> - Bandbreite zwischen den Mittenfrequenzen: ???
Ergibt sich aus der Anzahl der Filter/LED-Bars und der von dir 
gewuenschten Frequenzgrenzen(vermutlich vielleicht sowas wie 20Hz..20kHz 
oder sowas).

> - Durch die FPU sind Fließkommazahlen zu bevorzugen
Ist erstmal ziemlich wurscht, ob du jetzt double,float oder int in 
deinem C hast.

> - einen geeigneten Filter finden für die jeweiligen Mittenfreqenzen der
> 26 Terzbänder.
Ja, das solltest du tun.

> - Das Mic hat einen DC-Offset von Vin/2. Dies wird durch
> Mittelwertbildung abgezogen.
Geheimtip: Der Mittelwert ist sowas wie das Signal, nur ganz heftig 
tiefpassgefiltert, mit einer Grenzfrequenz deutlich unterhalb deines 
tiefsten Analysefilters.

> - Lösung finden: Wenn die Musiklautstärke erhöht / verringert wird, muss
> dies auf die Balkenauschläge skalliert werden.
Mach das erst ganz zum Schluss, wenn alles andere perfekt funktioniert.

> - goertzel algo für die spectral analyse
>
> Wenn ich dies mit dem oben genannten Mikrofon umsetzte.
> Dann wäre meine Grundfreqzenz des Analogen Signals 20Hz.
> Und alle weiteren Frequenzen bis 20kHz,
> wären die Oberschwingungen.
Versteh' ich nicht. Oder meinst du einfach, du kriegst ein 
Eingangssignal mit Frequenzen drinnen von 20Hz bis 20kHz?

> Bedeutet dies ich müsste exakt einen Theoretischen Trigger dort haben,
> wann die Grundfrequenz von Ihrer Amplitude = 0 ist und solange Sample
> werte aufnehmen bis eine Periode dieser abgeschlossen ist.
> Dies wäre denn doch eine perfekte Aufnahme, um ohne eine Fernsterung die
> Samples weiter zu verwenden?
> Kann mein ADC dies mit diesem Comperator Mode?
> Welche MCU Techniken werden für sowas benutzt?
Keine Ahnung von was du sprichst, ich glaube nicht, dass sowas relevant 
fuer dein Vorhaben ist. Bin mir aber nicht sicher, weil ich's nicht 
verstehe.

> Wenn ich mich für dieses Hardwareoversampling entscheide, kann ich
> dadurch die Auflösung etwas steigern, richtig?
> Kann ich dadurch auch das Signal / Raus Verhältnis optimieren?
> Wenn ich das richtig sehe, ist der maximale möglicher Wert 16, damit ich
> noch eine Samplerate von 40kHz schaffen kann.
Wuerde ich alles erstmal nicht machen, fruehestens kurz bevor du die 
"Autorange"-Funktion reinbaust.

> Habe 16 LED Balken. Oben wurde schonmal erwählt dies wäre denn ein
> Halber Terzband Analyzer. Wie genau ist das gemeint.
> Es gibt doch nur 26 Terzbänder?
Es gibt soviele Terzbänder, wie du lustig bist. Wieviele du noch hoeren 
kannst, haengt davon ab, wie alt du bist, und wie oft du in die Disco 
gehst oder mit Presslufthaemmern oder Duesenjets spielst.

> Und welche Terzbänder ich auf die 16 Balken verteile, muss ich noch
> heraus finden. Wenn ich jedes 2te nehme bekomme ich ja nur 13. Brauche
> aber 16. Und dann komme ich nur bis 10Khz. Möchte aber die die vollen
> 20kHz abdecken.
Tja, ein Teufelskreis. Du musst halt mal irgendwas festnageln. Entweder 
Anzahl der LED-Bars oder Frequenzintervalle.

> Aber unabhängig davon, würde ich gerne alle Terzbänder als
> MittenFrequenz nutzen wollen. Da oben erwähnt wurden ist, dass das
> Prozedere ähnlich ist. Und evtl. ist es möglich aus den 16 Balken 32
> Balken zu machen.
Wenn du evtl. mit 32 Bars arbeiten willst, muessen deine Filter halt 
auch schmalbandiger sein, sonst bringt das ja wenig, wenn z.b. bei 
Anregung mit einem Sinus dann 3..4 LED-Bars verschieden hoch leuchten. 
Es sollte idealerweise dann immer nur einer "ausschlagen".

>
> Mit der Skalierung der Balkenausschläge, wenn die Musik Lautstärke sich
> ändert ist folgendes gemeint.
> Mit der 12BIT Auflösung ist Dynamikumfang von:
> 20*LOG10(2^11) = ca. 66 Dezibel vorhanden. richtig?
Eher theoretische 72 dB.
> Ein BIT weniger weil ich durch 2 Teilen muss, da ich Werte im positiven
> und negativen Bereich habe. Richtig ?
Nein, du musst nicht durch 2 teilen.

> Was ich aber nicht möchte das ein Balken erst bei dieser Lautstärke voll
> ausschlägt.
>
> In der Regel dreht man nicht ständig an der Lautstärke. Wenn die Musik
> läuft stellt sich ein durchschnitts und max Wert ein. Und auf diesen Max
> Wert würde ich gerne Skallieren.
Wie ich schon oben schrub: Ich empfehle stark, das ganz zum Schluss zu 
machen.

> Wenn ich die parameter für goertzel algo festlegen und errechnen möchte.
> Kann ich mit der N anzahl an Samples und mit der Samplefrequenz spielen.
> Wenn ich allerdings mein Signal unter abtaste, muss ich aufpassen und
> eine antialaising filter benutzen?
Unterabtastung ohne Filter ist nur was fuer die Mutigen, die wissen, was 
sie tun.

> Kann ich einfach, wenn ich mit 40kHz das Signal abtaste und meine
> Samplefrequenz halbieren möchte, nur jeden 2ten Samples nehmen?
> Oder ist das Kinderkacke?
Nur wenn du weisst, dass in deinem mit 40kHz abgetasteten Signal keine 
Anteile mehr im Bereich zwischen 10...20kHz sind, die dich stoeren 
wuerden.
Haettest du z.b. am Eingang ein Signal mit 16kHz, was du mit 40kHz 
abtastest und von diesem schmeisst du einfach nur jedes 2. Sample weg, 
dann sieht das was du dann kriegst, genauso aus, wie wenn du ein 4kHz 
Signal am Eingang gehabt haettest. Das kannst du dann nicht mehr 
unterscheiden. Das ist dann der/die/das Alias(m/w/d).

> Zusätzlich habe ich 2 ADC und diese können mit unterschiedlichen
> SampleRate vom timer parametriert werden. Kann ich mir das irgendwie zu
> nutzen machen? Bekomme dann allerdings die doppelte menge an Samples die
> ja verarbeitet werden müssen.
Komm erstmal mit der normalen Menge an Samples klar, dann kannste 
weitergucken.

Gruss
WK

von Kevin H. (xerxes777)


Lesenswert?

Vielen Dank für die Antworten.

Dergute W. schrieb:
> Moin,
>
> Uiuiui, so fiele Vragen ;-)
> Kevin H. schrieb:
>> - Alle 26 Terzbänder + 10. Octave mit der jeweiligen Mittenfrequenz.
> Also wieviele Filter/LED-Bars willst du haben?
> 26Terzen=8.667 Oktaven und dann noch eine 10. dazu?
> Ich bin verwirrt.
Ich habe im Internet eine Tabelle gefunden.
In dieser Tabelle sind alle Frequenzen den jeweiligen Terzbänder 
zugeordnet.
Und da stehen die Terzbänder von 1 bis 26 drin.
Mit deinen Info weiß ich nun das es halt noch mehr gibt.
Nun weiß ich aber auch, dass man sich die Bänder ausrechnen kann.

>> - Bandbreite zwischen den Mittenfrequenzen: ???
> Ergibt sich aus der Anzahl der Filter/LED-Bars und der von dir
> gewuenschten Frequenzgrenzen(vermutlich vielleicht sowas wie 20Hz..20kHz
> oder sowas).
Okay, also muss ich mich jetzt festlegen.
Filter/LED-Bars = 16
Frequenzgrenzen = 20Hz bis 20kHz

>> - Durch die FPU sind Fließkommazahlen zu bevorzugen
> Ist erstmal ziemlich wurscht, ob du jetzt double,float oder int in
> deinem C hast.
Okay.

>> - einen geeigneten Filter finden für die jeweiligen Mittenfreqenzen der
>> 26 Terzbänder.
> Ja, das solltest du tun.
Bin dabei und versuche zu verstehen, wie das so funktioniert.

>> - Das Mic hat einen DC-Offset von Vin/2. Dies wird durch
>> Mittelwertbildung abgezogen.
> Geheimtip: Der Mittelwert ist sowas wie das Signal, nur ganz heftig
> tiefpassgefiltert, mit einer Grenzfrequenz deutlich unterhalb deines
> tiefsten Analysefilters.
Danke für die Anregung. Ich werde darüber nachdenken. Mir macht das 
Thema tatsächlich Spaß.

>> - Lösung finden: Wenn die Musiklautstärke erhöht / verringert wird, muss
>> dies auf die Balkenauschläge skalliert werden.
> Mach das erst ganz zum Schluss, wenn alles andere perfekt funktioniert.
Okay.

>> - goertzel algo für die spectral analyse
>>
>> Wenn ich dies mit dem oben genannten Mikrofon umsetzte.
>> Dann wäre meine Grundfreqzenz des Analogen Signals 20Hz.
>> Und alle weiteren Frequenzen bis 20kHz,
>> wären die Oberschwingungen.
> Versteh' ich nicht. Oder meinst du einfach, du kriegst ein
> Eingangssignal mit Frequenzen drinnen von 20Hz bis 20kHz?
Ja genau. Wenn ich das Mikrofonsignal mit 40Khz abtaste.
Und das Mikrofon hat eine Bandbreite von 20Hz bis 20Khz.
Dann wäre in dem Mikrofonsignal doch die 20 Hz die Grundschwingung.
Und alle Frequenzen >20Hz die Oberschwingungen. Oder ?

>> Bedeutet dies ich müsste exakt einen Theoretischen Trigger dort haben,
>> wann die Grundfrequenz von Ihrer Amplitude = 0 ist und solange Sample
>> werte aufnehmen bis eine Periode dieser abgeschlossen ist.
>> Dies wäre denn doch eine perfekte Aufnahme, um ohne eine Fernsterung die
>> Samples weiter zu verwenden?
>> Kann mein ADC dies mit diesem Comperator Mode?
>> Welche MCU Techniken werden für sowas benutzt?
> Keine Ahnung von was du sprichst, ich glaube nicht, dass sowas relevant
> fuer dein Vorhaben ist. Bin mir aber nicht sicher, weil ich's nicht
> verstehe.
Ich dachte daran, wenn das Mikrofonsignal exakt zum zeitpunkt abgetastet 
wird, das ich die gesamte Grundschwingung als Digitale Werte in dem 
Mikrocontroller hab. Dann kann ich mir doch eine anschließende 
Fensterung sparen oder?
Das ist nur so eine Theorie von mir.
Und ob es für sowas Techniken gibt.

>> Wenn ich mich für dieses Hardwareoversampling entscheide, kann ich
>> dadurch die Auflösung etwas steigern, richtig?
>> Kann ich dadurch auch das Signal / Raus Verhältnis optimieren?
>> Wenn ich das richtig sehe, ist der maximale möglicher Wert 16, damit ich
>> noch eine Samplerate von 40kHz schaffen kann.
> Wuerde ich alles erstmal nicht machen, fruehestens kurz bevor du die
> "Autorange"-Funktion reinbaust.
Okay.

>> Habe 16 LED Balken. Oben wurde schonmal erwählt dies wäre denn ein
>> Halber Terzband Analyzer. Wie genau ist das gemeint.
>> Es gibt doch nur 26 Terzbänder?
> Es gibt soviele Terzbänder, wie du lustig bist. Wieviele du noch hoeren
> kannst, haengt davon ab, wie alt du bist, und wie oft du in die Disco
> gehst oder mit Presslufthaemmern oder Duesenjets spielst.
Danke für die Info.

>> Und welche Terzbänder ich auf die 16 Balken verteile, muss ich noch
>> heraus finden. Wenn ich jedes 2te nehme bekomme ich ja nur 13. Brauche
>> aber 16. Und dann komme ich nur bis 10Khz. Möchte aber die die vollen
>> 20kHz abdecken.
> Tja, ein Teufelskreis. Du musst halt mal irgendwas festnageln. Entweder
> Anzahl der LED-Bars oder Frequenzintervalle.
Es sollen 16 Balken sein.

>> Aber unabhängig davon, würde ich gerne alle Terzbänder als
>> MittenFrequenz nutzen wollen. Da oben erwähnt wurden ist, dass das
>> Prozedere ähnlich ist. Und evtl. ist es möglich aus den 16 Balken 32
>> Balken zu machen.
> Wenn du evtl. mit 32 Bars arbeiten willst, muessen deine Filter halt
> auch schmalbandiger sein, sonst bringt das ja wenig, wenn z.b. bei
> Anregung mit einem Sinus dann 3..4 LED-Bars verschieden hoch leuchten.
> Es sollte idealerweise dann immer nur einer "ausschlagen".
Okay habe ich verstanden.

>>
>> Mit der Skalierung der Balkenausschläge, wenn die Musik Lautstärke sich
>> ändert ist folgendes gemeint.
>> Mit der 12BIT Auflösung ist Dynamikumfang von:
>> 20*LOG10(2^11) = ca. 66 Dezibel vorhanden. richtig?
> Eher theoretische 72 dB.
>> Ein BIT weniger weil ich durch 2 Teilen muss, da ich Werte im positiven
>> und negativen Bereich habe. Richtig ?
> Nein, du musst nicht durch 2 teilen.
Danke. Das habe ich denn falsch verstanden.

>> Was ich aber nicht möchte das ein Balken erst bei dieser Lautstärke voll
>> ausschlägt.
>>
>> In der Regel dreht man nicht ständig an der Lautstärke. Wenn die Musik
>> läuft stellt sich ein durchschnitts und max Wert ein. Und auf diesen Max
>> Wert würde ich gerne Skallieren.
> Wie ich schon oben schrub: Ich empfehle stark, das ganz zum Schluss zu
> machen.
Okay.

>> Wenn ich die parameter für goertzel algo festlegen und errechnen möchte.
>> Kann ich mit der N anzahl an Samples und mit der Samplefrequenz spielen.
>> Wenn ich allerdings mein Signal unter abtaste, muss ich aufpassen und
>> eine antialaising filter benutzen?
> Unterabtastung ohne Filter ist nur was fuer die Mutigen, die wissen, was
> sie tun.
Ich weiß noch nicht, was ich tue. Also halte ich noch brav das nyquist 
theorem ein.

>> Kann ich einfach, wenn ich mit 40kHz das Signal abtaste und meine
>> Samplefrequenz halbieren möchte, nur jeden 2ten Samples nehmen?
>> Oder ist das Kinderkacke?
> Nur wenn du weisst, dass in deinem mit 40kHz abgetasteten Signal keine
> Anteile mehr im Bereich zwischen 10...20kHz sind, die dich stoeren
> wuerden.
> Haettest du z.b. am Eingang ein Signal mit 16kHz, was du mit 40kHz
> abtastest und von diesem schmeisst du einfach nur jedes 2. Sample weg,
> dann sieht das was du dann kriegst, genauso aus, wie wenn du ein 4kHz
> Signal am Eingang gehabt haettest. Das kannst du dann nicht mehr
> unterscheiden. Das ist dann der/die/das Alias(m/w/d).
Das war eine dumme Überlegung von mir. Wenn ich jeden 2ten Wert löschen 
taste ich ja auch nur noch halb so viel ab.
Danke für die Erklärung.

>> Zusätzlich habe ich 2 ADC und diese können mit unterschiedlichen
>> SampleRate vom timer parametriert werden. Kann ich mir das irgendwie zu
>> nutzen machen? Bekomme dann allerdings die doppelte menge an Samples die
>> ja verarbeitet werden müssen.
> Komm erstmal mit der normalen Menge an Samples klar, dann kannste
> weitergucken.
>
> Gruss
> WK
Okay.

Also muss ich für jede LED-BAR ein Frequenzbereich festlegen.
Die Abtastwerte durch einen Bandpassfiltern der in diesem 
Frequenzbereich liegt schieben. Dann anschließend den Goertzel Algo 
anwenden auf die Werte?
Und dadurch ich die coefs für den Goertzel Algo exakt auf die 
mittenfrequenz gesetzt habe, bekomme ich da als Output einen sehr hohen 
wert. wenn diese mittenfrequenz in den Signal enthalten ist. ich muss 
allerdings N Samples warten bevor ich den Output nutzen darf.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kevin H. schrieb:
> Ich habe im Internet eine Tabelle gefunden.
> In dieser Tabelle sind alle Frequenzen den jeweiligen Terzbänder
> zugeordnet.
> Und da stehen die Terzbänder von 1 bis 26 drin.

Das wird dann wohl eine eher musikalische Auslegung der Terzbaender 
sein. Ich hab' das jetzt eher unter der Annahme gemeint, dass eine Terz 
einfach nur ein Verhaeltnis zwischen 2 Frequenzen ist. Ich koennte z.B. 
an Opas Küchenradio, was noch auf Mittelwelle 801kHz steht, obwohl da 
Bayern1 schon lange nicht mehr sendet, locker hergehen und die 
Empfangsfrequenz um eine Terz nach oben auf 1009.2kHz stellen oder nach 
unten auf 635.8kHz.
Daher bin ich der Ansicht, dass es mehr als 26 Terzbaender gibt. Was 
aber der musikalischen Ansicht nicht entspricht.

Kevin H. schrieb:
> Dann wäre in dem Mikrofonsignal doch die 20 Hz die Grundschwingung.
> Und alle Frequenzen >20Hz die Oberschwingungen. Oder ?
Axo hast du das gemeint. Hab' ich in der Form jetzt noch nicht gehoert.

Kevin H. schrieb:
> Ich dachte daran, wenn das Mikrofonsignal exakt zum zeitpunkt abgetastet
> wird, das ich die gesamte Grundschwingung als Digitale Werte in dem
> Mikrocontroller hab. Dann kann ich mir doch eine anschließende
> Fensterung sparen oder?
Also, du wolltest also 20x pro Sekunde eine komplette Analyse anstossen. 
Ja, kannste so machen. Kommt dann evtl. aber auch drauf an, wie du dein 
Display ansteuern willst. Also ob dem dann 20x pro Sekunde neue Werte 
fuer eine "schoene" Anzeige reichen.
Ob du beim Goertzel noch fenstern musst, weiss ich nicht.

Kevin H. schrieb:
> Das war eine dumme Überlegung von mir. Wenn ich jeden 2ten Wert löschen
> taste ich ja auch nur noch halb so viel ab.
Nee, das war eine "kaufmaennische Ueberlegung" ;-)
Vorher filtern kann echt nicht schaden.
Ich weiss aber nicht, was c-hater da an Gimmicks bei sich noch neben den 
Goertzels eingebaut hat.

Kevin H. schrieb:
> Also muss ich für jede LED-BAR ein Frequenzbereich festlegen.
> Die Abtastwerte durch einen Bandpassfiltern der in diesem
> Frequenzbereich liegt schieben. Dann anschließend den Goertzel Algo
> anwenden auf die Werte?
> Und dadurch ich die coefs für den Goertzel Algo exakt auf die
> mittenfrequenz gesetzt habe, bekomme ich da als Output einen sehr hohen
> wert. wenn diese mittenfrequenz in den Signal enthalten ist. ich muss
> allerdings N Samples warten bevor ich den Output nutzen darf.
Ja, so wuerde ich blauaeugig auch an die Sache rangehen. Sieht aber so 
aus, als wuerde er eben fuer bestimmte Frequenzen noch irgendwas machen. 
Wahrscheinlich nicht ohne Grund.
Beim Goertzel ist es iirc auch so, dass er immer schmalbandiger wird, 
wenn du ihn ueber mehr Samples laufen laesst. Vielleicht ist das ein 
Grund fuer seine Extrafaxen.
Hier bissl C, um deine Frequenzeinteilung zu berechnen. Wenn du 
20Hz..20kHz auf 16 logarithmisch geteilte Frequenzen ausrechnest, sind 
das halt keine Terzen (4 Halbtonschritte) mehr, sondern so ungefaehr 8 
Halbtonschritte pro Filter.
1
#include <stdio.h>
2
#include <math.h>
3
4
#define N_BARS (16)
5
#define F_LO (20.0)
6
#define F_HI (20000.0)
7
int main() {
8
    int i;
9
    float log_f_lo = log(F_LO);
10
    float log_f_hi = log(F_HI);
11
    float log_f_step;
12
13
    log_f_step = (log_f_hi - log_f_lo)/(float)(N_BARS - 1);
14
    for (i=0; i < N_BARS; i++) {
15
        printf("Mittenfreqenz Band %3d : %f\n", i+1, exp(log_f_lo));
16
        log_f_lo += log_f_step;
17
    }
18
}

Gruss
WK

von c-hater (Gast)


Lesenswert?

Dergute W. schrieb:

> Das wird dann wohl eine eher musikalische Auslegung der Terzbaender
> sein.

Ich bin kein Musiker und musste erstmal nachschlagen, was eine Terz 
eigentlich ist. Hat sich rausgestellt: das wissen nichtmal die Musiker 
so genau, denn es gibt verschiedene. Bevor man über irgendwelche Terze 
redet, sollte man also wohl erstmal klarstellen, über welche genau.

> Ich hab' das jetzt eher unter der Annahme gemeint, dass eine Terz
> einfach nur ein Verhaeltnis zwischen 2 Frequenzen ist.

Ja, aber welches genau, da sind selbst die Musiker uneins...

> Ob du beim Goertzel noch fenstern musst, weiss ich nicht.

Ja, muss man. Das ist genau wie bei einer FFT. Bloß dass für eine FFT 
ein Fenster genügt, die Goertzels aber jeweils ein eigenes benötigen.

> Ich weiss aber nicht, was c-hater da an Gimmicks bei sich noch neben den
> Goertzels eingebaut hat.

Steht alles in der Beschreibung: Halbbandfilter, Hammingfenster, 
Goertzel. Mehr ist da wirklich nicht drin an Filtern.

> Sieht aber so
> aus, als wuerde er eben fuer bestimmte Frequenzen noch irgendwas machen.

Nö, das lief andersrum. Die Frequenzen sind (ausgehend von der 
Samplefrequenz, die durch die Fähigkeiten der Hardware vorgegeben waren) 
ganz bewußt genau so gewählt, dass sich für die Goertzels "günstige" 
Koeffizenten ergaben. Recht günstig sind z.B.: 1 und -1, denn 1 ist 
Addition und -1 ist Subtraktion. Beides wesentlich billiger als 
Multiplikation, speziell auf einem ATtiny.

> Beim Goertzel ist es iirc auch so, dass er immer schmalbandiger wird,
> wenn du ihn ueber mehr Samples laufen laesst.

Das ist so, ja. Ist übrigens auch bei einer FFT so. Sind halt 
mathematisch nahe Verwandte.

von Kevin H. (xerxes777)


Lesenswert?

c-hater schrieb:
> Nö, das lief andersrum. Die Frequenzen sind (ausgehend von der
> Samplefrequenz, die durch die Fähigkeiten der Hardware vorgegeben waren)
> ganz bewußt genau so gewählt

Okay dann muss ich herausfinden, wie ich die Samplefrequenz reduzieren 
kann, ohne eine alias zu erzeugen.

@c-hater
Tastet du das Signal mit deiner maximalen abtastrate ab und reduziert 
diese dann digital? oder konfiguriert du den adc um und tastet dann mit 
einer reduzierten abtastrate das signal ab?

Das Mikrofonsignal wird fmax * 2 nach dem nyquist theorem abgetastet.
Also 40kHz. Ich könnte mit der Abtastrate noch locker höher gehen, wenn 
ich das muss.
Dieses Digitale Signal kann ich dann reduzieren in der Abtastrate, wenn 
ich jeden 2ten oder jeden 4ten ... Sample lösche.
Das löschen würde dann aber zu einer unter abtastung führen. und ich 
habe alaising. um das zu umgehen muss ich einen alaising filter nutzen.
vielen dank für die infos. ich lese mal weiter durch meine bücher.
evtl ist das löschen des samples nicht unbedingt clever. evtl kann ich 
diese nutzen um das signal ohne alaising in der samplerate reduzieren.

von c-hater (Gast)


Lesenswert?

Kevin H. schrieb:

> Tastet du das Signal mit deiner maximalen abtastrate ab und reduziert
> diese dann digital?

Ja.

> Dieses Digitale Signal kann ich dann reduzieren in der Abtastrate, wenn
> ich jeden 2ten oder jeden 4ten ... Sample lösche.
> Das löschen würde dann aber zu einer unter abtastung führen. und ich
> habe alaising.

Dagegen sind die Halbbandfilter. Das Schema ist so:

       fs                  fs/2                fs/4
Quelle----->Halfband-->1:2----->Halfband-->1:2----->usw.

An fs hängen zwei Gortzels, einer für fs/3 und einer für fs/6, an den 
restlichen Samplefrequenz-Domänen hängt jeweils ein Gortzel (für 1/6 der 
jeweiligen Samplefrequenz).

von Kevin H. (xerxes777)


Lesenswert?

c-hater schrieb:
> Kevin H. schrieb:
>
>> Tastet du das Signal mit deiner maximalen abtastrate ab und reduziert
>> diese dann digital?
>
> Ja.
>
>> Dieses Digitale Signal kann ich dann reduzieren in der Abtastrate, wenn
>> ich jeden 2ten oder jeden 4ten ... Sample lösche.
>> Das löschen würde dann aber zu einer unter abtastung führen. und ich
>> habe alaising.
>
> Dagegen sind die Halbbandfilter. Das Schema ist so:
>
>        fs                  fs/2                fs/4
> Quelle----->Halfband-->1:2----->Halfband-->1:2----->usw.
>
> An fs hängen zwei Gortzels, einer für fs/3 und einer für fs/6, an den
> restlichen Samplefrequenz-Domänen hängt jeweils ein Gortzel (für 1/6 der
> jeweiligen Samplefrequenz).

Vielen Dank für die Info.

Bedeutet dies ich kann z.B. 32 Samples mit einer Fs von 40kHz Puffern.
Diese Schiebe ich dann durch ein Halbbandfilter und bekomme 16 Samples 
mit einer neuen Fs2 von 10kHz?
Fs = 40kHz -> FsNyquist 20Khz dies durch ein Halband bedeutet 10kHz. 
Aber habe nur noch 16 Samples?

von c-hater (Gast)


Lesenswert?

Kevin H. schrieb:

> Bedeutet dies ich kann z.B. 32 Samples mit einer Fs von 40kHz Puffern.

Das hat mit irgendwelchen Puffern nix zu tun. Ich nehme mal an, das war 
als Beispiel gemeint und der springende Punkt sollen die 32 Samples 
sein.

> Diese Schiebe ich dann durch ein Halbbandfilter und bekomme 16 Samples
> mit einer neuen Fs2 von 10kHz?

Nö. Hinter dem Halbbandfilter hast du nach wie vor 32 Samples. Nur 
enthalten die halt ein tiefpassgefiltertes Signal. Was man (wenn der 
Filter ideal wäre, was er allerdings nicht ist, kein realer Filter ist 
ideal) ohne Alias-Effekte mit der Hälfte der ursprünglichen 
Samplefrequenz erneut "abtasten" kann. Sprich: In der Realität hole ich 
einfach nur jedes zweite Ergebnis-Sample aus dem Filter. Wäre ja 
rechenzeitverschwendender Unfug, ein Sample aus dem Filter zu holen, um 
es dann gleich wegzuwerfen.

Erst durch das "Wegwerfen" jedes zweiten Samples komm man dann auf 16 
Samples.

Die logische (und praktisch sehr nützliche) Trennung zwischen Filter und 
Reduktion hatte ich eigentlich auch ziemlich deutlich dargestellt durch: 
"Halfband-->1:2". Dachte ich jedenfalls...

> Aber habe nur noch 16 Samples?

Natürlich. Die Zeit bleibt gleich, die Samplefrequenz soll sich 
halbieren, das geht nur dadurch, indem man die Zahl der Samples 
halbiert. Das ist ja nun wirklich Klippschul-Mathematik.

von Mitleser (Gast)


Lesenswert?

... und die Qualität des HBF ist auch wirklich so, dass man es sich 
erlauben kann, stets die Frequenz zu halbieren?

Oder muss man jeweils denselben headroom einhalten, also z.B.

Abtaste = 48kHz, gf = 16kHz (Stoppband ab 24)
Abtaste = 24kHz, gf = 08kHz (Stoppband ab 12)
Abtaste = 12kHz, gf = 04kHz (Stoppband ab 06)

weil ein HBF auf Nyquist lappt stets in das Stoppband rein und die 
Halbierung der Rate wirt Oberwellen rein ...

von c-hater (Gast)


Lesenswert?

Mitleser schrieb:

> ... und die Qualität des HBF ist auch wirklich so, dass man es sich
> erlauben kann, stets die Frequenz zu halbieren?

Gut genug für die konkrete Anwendung. Auch das geht aus dem damals im 
Thread geposteten Zeug problemlos hervor, wenn man es denn "lesen" kann.

Natürlich sind die verwendeten Halbbandfilter vor allem 
rechenzeitsparend und nicht besonders gut. Aber eben doch gut genug für 
die konkrete Anwendung.

Wenn man mehr Rechenzeit verfügbar hat, spricht natürlich auch absolut 
nichts dagegen, das Konzept beizubehalten und einfach bessere Filter zu 
verwenden.

Mit mehr Resourcen wird's immer einfacher, das ist nunmal so.

Aber ich denke mal, der TO ist schon völlig überfordert damit, das 
selbst auf kleinster Hardware nachweislich funktionierende Konzept 
nachzubauen, obwohl er massiv mehr Rechenpower verfügbar hat. Das muss 
er erstmal schaffen. Das dann unter Nutzung des Mehr an Rechenleistung 
zu verbessern, ist dann eher trivial.

von Mitleser (Gast)


Lesenswert?

Wie würdest du denn einen guten HBF bauen?

von c-hater (Gast)


Lesenswert?

Mitleser schrieb:

> Wie würdest du denn einen guten HBF bauen?

Kommt drauf an. Was habe ich denn an Hardware zur Verfügung?

von Kevin H. (xerxes777)


Lesenswert?

c-hater schrieb:
> Aber ich denke mal, der TO ist schon völlig überfordert

Ja das stimmt und dies gebe ich auch gerne zu.
Dieses Thema ist komplettes neu für mich und lese mich dazu noch ein.
Ich freue mich über die Hilfe die ich von euch bekomme.

c-hater schrieb:
> das selbst auf kleinster Hardware nachweislich funktionierende Konzept 
nachzubauen

Dies ist gar nicht mein Ziel. Ich möchte über das Thema DSP so viel es 
geht lernen und verstehen. Es macht mir irgendwie Spaß.

c-hater schrieb:
> obwohl er massiv mehr Rechenpower verfügbar hat

Dies ist nicht relevant für mich. Ich möchte ein gutes Konzept 
entwickeln und die Entscheidung begründen können. Warum ich was gemacht.

c-hater schrieb:
> Das muss er erstmal schaffen

Mein erstes Ziel wird werden meine Testumgebung aufzubauen.
Damit meine ich, ich möchte Signale über Klinke(LineIn) oder Mikrofon 
auf nehmen als Quelle PC oder Signalgenerator.
Ausgeben über ein Oszilloskop oder Lautsprechen.

Ich würde dann anfangen einen Halbbandfilter in seinen Parameter zu 
bestimmen und in C schreiben und die Filterung messtechnisch mit dem 
Signalgenerator und Oszilloskop aufzeichen und bewerten. Und gegebenfals 
optimieren und spielen.

c-hater schrieb:
> Das hat mit irgendwelchen Puffern nix zu tun. Ich nehme mal an, das war
> als Beispiel gemeint und der springende Punkt sollen die 32 Samples
> sein.

Genau dies sollte nur ein Beispiel sein, wegen der Anzahl der Samples.

c-hater schrieb:
> Hinter dem Halbbandfilter hast du nach wie vor 32 Samples. Nur
> enthalten die halt ein tiefpassgefiltertes Signal. Was man (wenn der
> Filter ideal wäre, was er allerdings nicht ist, kein realer Filter ist
> ideal) ohne Alias-Effekte mit der Hälfte der ursprünglichen
> Samplefrequenz erneut "abtasten" kann

Danke für die Info. Das habe ich jetzt verstanden

c-hater schrieb:
> Die logische (und praktisch sehr nützliche) Trennung zwischen Filter und
> Reduktion hatte ich eigentlich auch ziemlich deutlich dargestellt durch:
> "Halfband-->1:2". Dachte ich jedenfalls...

Wenn eine Kleinigkeit für mich nicht logisch oder verständlich 
erscheint, bin ich schnell verunsichert und muss mit meinen eigenen 
Worten noch mal nach fragen.

Mitleser schrieb:
> weil ein HBF auf Nyquist lappt stets in das Stoppband rein und die
> Halbierung der Rate wirt Oberwellen rein ...

Okay. Diese müsste ich denn ja sehen, wenn ich mir das Signal genau 
anschaue. Ich bin gespannt.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

A propos 1:2 Dezimation - Hier
Beitrag ""LED-Spectrumanalyzer"software ohne Fouriertransformation"
gibts ja im ersten Post ein tar Archiv mit dem alten Kram von mir.
Und wenn man da mal in dem File hb.c die Zeilen 59ff anguckt, da wird 
genausowas gemacht:
Also ein FIR Filter, was mit den samples gefuettert wird und dann bei 
jedem 2. Aufruf (f->state toggelt immer zwischen 0 und 1) ein Sample 
weitergibt (in Zeile 78 wird dann das naechste Filter aufgerufen, das 
ist also der "Ausgang" der Dezimation). Das reduziert die Samplerate um 
den Faktor 2.

Gruss
WK

von Raspi Fan (Gast)


Lesenswert?

Kevin Hinrichs schrieb:
> Habt ihr eine Idee wie ich die Energiewerte der Frequenzen sinnvoll
> zusammenfügen kann zu einem Band?

Um die Energiewerte auf die 16 Balken des LED Spectrum Analyzers zu 
verteilen, kannst du die Energiewerte der Frequenzbänder addieren und 
dann durch die Anzahl der Frequenzen in jedem Band teilen, um den 
durchschnittlichen Energiepegel pro Band zu erhalten. Du kannst dann 
diesen Wert verwenden, um die Höhe des Balkens für jeden Band auf dem 
LED-Spectrum-Analyzer darzustellen. Es gibt auch andere Methoden wie 
z.B. die Verwendung von Filterbanken, um die Energiewerte auf die Bänder 
zu verteilen, aber diese Methode ist eine einfache und effektive 
Möglichkeit.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Raspi Fan schrieb:
> Um die Energiewerte auf die 16 Balken des LED Spectrum Analyzers zu
> verteilen, kannst du die Energiewerte der Frequenzbänder addieren und
> dann durch die Anzahl der Frequenzen in jedem Band teilen, um den
> durchschnittlichen Energiepegel pro Band zu erhalten. Du kannst dann
> diesen Wert verwenden, um die Höhe des Balkens für jeden Band auf dem
> LED-Spectrum-Analyzer darzustellen. Es gibt auch andere Methoden wie
> z.B. die Verwendung von Filterbanken, um die Energiewerte auf die Bänder
> zu verteilen, aber diese Methode ist eine einfache und effektive
> Möglichkeit.

Krasser shice!!1!eins!1ELF!!
Das sind ja mal ganz neue Konzepte, die hier in diesem Thread noch 
ueberhaupt nicht zur Sprache kamen. Ich bin tief impraegniert.
Jetzt musst du es nur noch schaffen, die KI auch wirklich vernuenftig 
mit den schon vorhandenen Infos/Problemen zu fuettern, vielleicht kommt 
dann auch mal was spannendes dabei raus.
Aber auch bei KI gilt: A fool with a tool is still a fool.

scnr,
WK

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Kevin H. schrieb:

> Okay. Diese müsste ich denn ja sehen, wenn ich mir das Signal genau
> anschaue. Ich bin gespannt.

Ich habe mal im ursprünglichen Thread Details zum tatsächlich benutzten 
Halbbandfilter veröffentlich.

Beitrag "Re: Audio Spektrum Analyzer mit ATtiny85"

von KI Fan (Gast)


Lesenswert?

Dergute W. schrieb:

> Krasser shice!!1!eins!1ELF!!
> Das sind ja mal ganz neue Konzepte, die hier in diesem Thread noch
> ueberhaupt nicht zur Sprache kamen. Ich bin tief impraegniert.
> Jetzt musst du es nur noch schaffen, die KI auch wirklich vernuenftig
> mit den schon vorhandenen Infos/Problemen zu fuettern, vielleicht kommt
> dann auch mal was spannendes dabei raus.
> Aber auch bei KI gilt: A fool with a tool is still a fool.
>
> scnr,
> WK

Du hast immerhin erst auf den zweiten Blick erkannt, dass hier eine KI 
am Werk ist :)

von Kevin H. (xerxes777)


Lesenswert?

Ich hab mal ein wenig mit dem ChatGPT zu diesem Thema "gechattet"
Und nach ca. 30 Minuten hin und her kam das dabei raus:

1
#include <stdio.h>
2
#include <math.h>
3
4
// Anzahl der Frequenzbänder
5
#define NUM_BANDS 16
6
7
// Anzahl der Pixels in der höhe
8
#define NUM_PIXELS_HEIGHT 29
9
10
// Anzahl der Abtastwerte pro Durchlauf
11
#define NUM_SAMPLES 128
12
13
// Frequenzgrenzen vom Mikrofon
14
#define MIN_FREQUENCY 20.0
15
#define MAX_FREQUENCY 20000.0
16
17
// ADC Sample Rate
18
#define ADC_SAMPLERATE 40000.0
19
20
void calculate_band_frequencies(float *bands, int num_bands, float min_frequency, float max_frequency) {
21
    /*
22
    Die Funktion calculate_band_frequencies berechnet die Frequenzbänder
23
    im logarithmischen Mitteltonbereich und speichert sie im bands-Array.
24
    */
25
    
26
    float octave_ratio = pow(2.0, 1.0/12.0); // 12 steps per octave
27
    bands[0] = min_frequency;
28
    for (int i = 1; i < num_bands; i++) {
29
        bands[i] = bands[i-1] * octave_ratio;
30
    }
31
}
32
33
void calculate_coefficients(int order, float fc, float *b, float *a) {
34
    /*
35
    Berechnet die Koeffizienten für einen IIR-Butterworth-Halbbandfilter
36
    */
37
    
38
    float wc = 2 * M_PI * fc;
39
    float alpha = sin(wc) / (2 * order);
40
    float c = cos(wc);
41
    for (int i = 0; i < order; i++) {
42
        float theta = M_PI * (i + 0.5) / order;
43
        b[i] = (1 - c) / 2;
44
        a[i] = 1 + alpha * cos(theta);
45
    }
46
}
47
48
void goertzel_filter(float *signal, float f, int N, float *result) {
49
    /*
50
    Führt den Goertzel-Algorithmus auf
51
    das Signal an und speichert das Ergebnis in result
52
    */
53
    
54
    float omega = 2 * M_PI * f / N;
55
    float cos_omega = cos(omega);
56
    float sin_omega = sin(omega);
57
    float coeff = 2 * cos_omega;
58
    float q0, q1, q2;
59
    for (int i = 0; i < N; i++) {
60
        q0 = coeff * q1 - q2 + signal[i];
61
        q2 = q1;
62
        q1 = q0;
63
    }
64
    *result = sqrt(q1 * q1 + q2 * q2 - q1 * q2 * coeff);
65
}
66
67
void filter_signal(float *signal, float *bands, int num_bands, float *filtered_signal) {
68
    /*
69
    Wendet den IIR-Butterworth-Halbbandfilter auf
70
    das Signal an und speichert das Ergebnis in filtered_signal
71
    */
72
    
73
    for (int i = 0; i < num_bands; i++) {
74
        float fc = bands[i];
75
        float *coeff_b = (float *)malloc(sizeof(float) * order);
76
        float *coeff_a = (float *)malloc(sizeof(float) * order);
77
        calculate_coefficients(order, fc, coeff_b, coeff_a);
78
        filtered_signal[i] = filter(signal,coeff_b,coeff_a, NUM_SAMPLES);
79
        free(coeff_b);
80
        free(coeff_a);
81
    }
82
}
83
84
void scale_amplitude_logarithmic(float *amplitudes, int num_bands, int *pixel_height) {
85
    for (int i = 0; i < num_bands; i++) {
86
        float amplitude_dB = 20 * log10(amplitudes[i] / (4095.0 / (2^12-1)));
87
        amplitudes[i] = amplitude_dB;
88
        pixel_height[i] = log10(amplitude_dB + max_dB) * (29.0 / log10(max_dB));
89
    }
90
}
91
92
int main() {
93
    // Array für die Höhe der LED-Pixel
94
    int pixel_height[NUM_BANDS];
95
    
96
    // Array für die Frequenzbänder
97
    float bands[NUM_BANDS];
98
    
99
    // Array für die Amplituden der Frequenzbänder
100
    float amplitudes[NUM_BANDS];
101
    
102
    // Read microphone input into signal array
103
    float signal[NUM_SAMPLES];
104
    float filtered_signal[NUM_BANDS];
105
    
106
    calculate_band_frequencies(&bands, NUM_BANDS, MIN_FREQUENCY, MAX_FREQUENCY);
107
    filter_signal(&signal, &bands, NUM_BANDS, &filtered_signal);
108
    
109
    for (int i = 0; i < NUM_BANDS; i++) {
110
        goertzel_filter(&filtered_signal[i], &bands[i], NUM_SAMPLES, &amplitudes[i]);
111
        printf("Amplitude of frequency %f: %f\n", bands[i], amplitudes[i]);
112
        
113
        scale_amplitude_logarithmic(&amplitudes[i], NUM_SAMPLES, &pixel_height[i]);
114
        printf("Amplitude of frequency %f: %f dB\n", bands[i], amplitudes[i]);
115
        printf("Pixel height of frequency %f: %f\n", bands[i], pixel_height[i]);
116
    }
117
    return 0;
118
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.