Hallo Gemeinde.
Ich taste auf einem mega644P ein Audiosignal ab und schicke es durch die
ElmChan-FFT. Ausgewählte Frequenzen zeige ich über LEDs an. Nun möchte
ich ein Peak-Hold realisieren, damit die Anzeige nicht so "zuckt".
Ich habe dazu folgenden Algorithmus geschrieben, der als Parameter den
aktuell berechneten Frequenzwert bekommt. Alle alten Werte werden um 3dB
abgesenkt (halbiert). Den größten Wert in meinem Buffer gebe ich dann
zurück und zeige ihn an.
1
#define PEAKHOLD_N 5
2
uint16_tpeaks[PEAKHOLD_N];
3
4
/*
5
Wird alle 10ms mit einem neuen FFT-Wert für
6
die entsprechende Frequenz aufgerufen.
7
8
Return-Wert wird über LEDs angezeigt
9
*/
10
uint16_tgetNextPeak(uint16_tnew_value)
11
{
12
// shift old samples and fade them away
13
for(uint8_tn=PEAKHOLD_N-1;n>0;n--)
14
{
15
peaks[n]=(peaks[n-1]>>2);
16
}
17
18
// insert the new value
19
peaks[0]=new_value;
20
21
// search for max to display
22
uint16_tmax=0;
23
for(uint8_tn=PEAKHOLD_N-1;n>=0;n--)
24
{
25
if(peaks[n]>max)
26
max=peaks[n];
27
}
28
29
returnmax;
30
}
Mir geht's darum, ob der Algorithmus so funktionieren kann oder ob ich
völlig auf dem Holzweg bin?
Syntaxfehler im Code interessieren mich jetzt erstmal nicht.
Grüße
Daniel R. schrieb:
> uint16_t getNextPeak(uint16_t new_value)> {> // shift old samples and fade them away> for(uint8_t n=PEAKHOLD_N-1; n>0; n--)> {> peaks[n] = (peaks[n-1] >> 2);
Das ist eine Division durch 4 und nicht durch 2
Wenn du durch 2 dividieren willst, dann schreib auch Division durch 2!
Dein Compiler weiß schon, wann er das mit Schieben erledigen kann und
wann er tatsächlich dividieren muss.
Ich würds so machen:
Wenn der neue Werte größer ist als der alte, dann übernimm ihn direkt.
Ist er kleiner, dann wird der alte Wert einfach nur um 1 verringert.
Wenn das je nach Wertebereich zu langsam wieder runter fällt, dann eben
2 abziehen (oder halbieren oder ...)
1
staticuint16_toldPeak;
2
3
uint16_tgetNextPeak(uint16_tnew_value)
4
{
5
if(new_value>oldPeak)
6
oldPeak=new_value;
7
8
elseif(oldPeak>0)
9
oldPeak--;
10
11
returnoldPeak;
12
}
Ziel: ansteigende Werte werden sofort übernommen. Fällt der Wert, dann
tut er das langsam.
Daniel R. schrieb:
> // search for max to display> uint16_t max = 0;> for(uint8_t n=PEAKHOLD_N-1; n>=0; n--)> {> if(peaks[n] > max)> max = peaks[n];> }>> return max;> }> [/c]>> Mir geht's darum, ob der Algorithmus so funktionieren kann oder ob ich> völlig auf dem Holzweg bin?
Probiers aus.
Schreib ein Programm, welches eine repräsentatives Samplemenge durch die
Funktion durchjagt und sieh dir die Ergebnisse an. Letztendlich hängt es
vom Effekt ab, den du erzielen willst, ob der Code das macht, was du dir
vorstellst.
Karl heinz Buchegger schrieb:
> Das ist eine Division durch 4 und nicht durch 2>> Wenn du durch 2 dividieren willst, dann schreib auch Division durch 2!
Ich meinte eine Division durch 2, also >>1.
>> Ich würds so machen:> Wenn der neue Werte größer ist als der alte, dann übernimm ihn direkt.> Ist er kleiner, dann wird der alte Wert einfch nur um 1 verringert. Wenn> das je nach Wertebereich zu langsam wieder runter fällt, dann eben 2> abziehen
Das ist natürlich die einfachere Methode, da hab ich wieder zu
kompliziert gedacht ^^.
Ich kanns leider erst morgen testen, weil ich die HW nicht hier hab.
Hatte mir das nur theoretisch überlegt und wollte mal Meinungen dazu
hören.
Danke
Daniel R. schrieb:
> Karl heinz Buchegger schrieb:>> Das ist eine Division durch 4 und nicht durch 2>>>> Wenn du durch 2 dividieren willst, dann schreib auch Division durch 2!>> Ich meinte eine Division durch 2, also >>1.
Dann schreibs auch als Division durch 2
peaks[n] = peaks[n-1] / 2;
und alle sind glücklich. Da gibt es kein Vertun und man sieht was Sache
ist.
Daniel R. schrieb:
> Das ist natürlich die einfachere Methode, da hab ich wieder zu> kompliziert gedacht ^^.
Muss nicht sein.
Das ergibt einen anderen Effekt. Vielleicht willst du den ja gar nicht
haben.
Hier gibt es kein richtig und kein falsch. Was funktioniert und was dir
optisch gefällt ist per Definition richtig :-)
Dieses Shiften im Quellcode kannst du dir sparen, ob du >> 2 oder / 4
schreibst ist das gleiche. Vertraue deinem Compiler, das er intelligent
genug ist, das effektivste daraus zu machen.
Besserwisser schrieb:
> Dieses Shiften im Quellcode kannst du dir sparen, ob du >> 2 oder / 4> schreibst ist das gleiche. Vertraue deinem Compiler, das er intelligent> genug ist, das effektivste daraus zu machen.
Wahrscheinlich werden gleich alle über mich herfallen, aber ich hatte
das vor ein paar Wochen mit der neuesten Kombination WinAVR / AVR-Studio
getestet. Und da wurde meines Erachtens nicht vom Compiler optimiert.
Als ich da ne Division durch z.B. 64 durch shiften ersetzt hatte, habe
ich deutlich schnelleren Code erhalten. Steht ja auch so in diversen
Optimierungs-Guides. Ich war auch der Meinung, dass der Compiler sowas
machen müsste. Vielleicht liegts ja auch an Einstellungen, ich
compiliere immer mit -Os.
Daniel R. schrieb:
> Als ich da ne Division durch z.B. 64 durch shiften ersetzt hatte, habe> ich deutlich schnelleren Code erhalten. Steht ja auch so in diversen> Optimierungs-Guides. Ich war auch der Meinung, dass der Compiler sowas> machen müsste. Vielleicht liegts ja auch an Einstellungen, ich> compiliere immer mit -Os.
Das kann dann nur ein Fehler im Optimizer des Compilers gewesen sein.
Diese Optimierung ist eine der leichtesten Übungen für einen Compiler
die sie seit mehr als 40 Jahren anstandslos beherrschen.
Wenn dem tatsächlich so war, dann ist das ein Fall für den Bug Report.
Eine eigene Frage?
Dieser Thread ist über 16 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.