Forum: Mikrocontroller und Digitale Elektronik gleitender Maximalwert - wie umsetzen?


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hallo allerseits,

ich hab mal wieder einen Knoten im Hirn...

ich krieg alle 100ms einen Messwert, und möchte den Maximalwert über die 
letzten 100 Werte (entspricht den letzten 10 Sekunden) wissen.

Eigentlich einfach: Ich mach einen Ringbuffer mit 100 Slots, schieb den 
neuen Wert hinein, und berechne danach das Maximum über den gesamten 
Ringbuffer.

Jetzt bin ich aber überzeugt davon dass das einfacher und effizienter 
gehen muss...

Idee #1: ich muss nicht jedesmal das Maximum über den gesamten Buffer 
suchen, sondern nur dann wenn der "rausfallende" Wert dem (vorigen) 
Maximum entspricht. Sonst muss das Maximum noch im Buffer sein, und ich 
kann mit dem alten Maximum weiterrechnen.

Irgendwie müsste man auch den (großen) Ringbuffer verkleinern oder 
(fast) ganz weglassen können....

Idee #2: ich merke mir das Maximum und dessen "Alter". Wenn der aktuelle 
Wert größer oder gleich dem bisherige Maximum ist, neues Maximum setzen, 
Alter auf 0. Ansonsten Alter hochzählen, ist das Alter > 100, Wert 
wegwerfen. Allerdings bräuchte ich dann ein neues bisheriges Maximum, 
ich müsste irgendwie einen zweiten "zweithöchsten" Wert mitführen, der 
aber immer jünger als das Maximum ist. Wenn das Maximum "abläuft", wird 
Max-Wert und Max-Alter auf den zweithöchsten gesetzt. Allerdings - womit 
fülle ich dann den zweithöchsten? Deswegen der Knoten in meinem Kopf...

Idee #3: ich mach keinen "linearen" Ringbuffer, sondern irgendwas 
anderes, so in der Art: Maximalwert der letzten 0.1 Sekunden, Max über 
0.2sec, 0.4 sec, 0.8sec, 1.6sec also immer verdoppelt. Mit 8 Werten käme 
ich auf 12.8Sekunden, was auch gut passen würde. Nur fehlt mir grad die 
Idee wie man das umsetzt - schon wieder Knoten im Hirn.

Ich hoffe es gibt dafür bewährte Verfahren, und ich muss nicht das Rad 
neu erfinden...

von hufnala (Gast)


Lesenswert?

Hi,
ich verstehe Dich noch nicht ganz, was soll das Ergebnis sein?

Ein array von Maximalwerten der 10s Bloecke:
Dann einfach immer für die letzten 100 Werte nur den Max Wert ermitteln 
nach Deine Idee 1 (if akt > max then max = akt).

Idee 2 mit dem Alter erschliesst sich mir nicht. Soll die Messung 
unendlich laufen oder eine vordefinierte Zeit/Werteanzahl?


//hufnala

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

hufnala schrieb:
> Soll die Messung
> unendlich laufen oder eine vordefinierte Zeit/Werteanzahl?

Unendlich/dauerhaft, und ich suche das Maximum der letzten 100 Werte / 
der letzten 10 Sekunden

von Tom V. (vzczc)


Lesenswert?

...ich würde es auch als Ringpuffer umsetzen. Alle 100ms 100 Werte 
vergleichen lastet einen MC nicht unbedingt aus ;-))

von hufnala (Gast)


Lesenswert?

Hi,

Ja, da ist der Ringpuffer das richtige...

//hufnala

von F. F. (foldi)


Lesenswert?

Michael Reinelt schrieb:
> Idee #1: ich muss nicht jedesmal das Maximum über den gesamten Buffer
> suchen, sondern nur dann wenn der "rausfallende" Wert dem (vorigen)
> Maximum entspricht. Sonst muss das Maximum noch im Buffer sein, und ich
> kann mit dem alten Maximum weiterrechnen.

Nicht wenn der dem entspricht, wenn der nächste Wert höher ist.

Du liest doch jeden neuen Wert ein. Dann vergleichst du ihn mit dem 
letzten Maximalwert und ist er höher, dann ist das dein neuer 
Maximalwert. Das machst du dann halt 100 mal.

Solange du keinen höheren Wert hast, rechnest du mit dem letzten 
Maximalwert.

http://www.mikrocontroller.net/articles/Statemachine

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Michael Reinelt schrieb:

> Idee #1: ich muss nicht jedesmal das Maximum über den gesamten Buffer
> suchen, sondern nur dann wenn der "rausfallende" Wert dem (vorigen)
> Maximum entspricht. Sonst muss das Maximum noch im Buffer sein, und ich
> kann mit dem alten Maximum weiterrechnen.

Naja.

Bei "ungünstigen" Messwerten (monoton fallend) mußt du trotzdem bei 
jedem Schritt den gesamten Puffer absuchen. Im Langzeit-Mittel wirst du 
aber mit diesem Ansatz knapp die Hälfte der Rechenzeit sparen können und 
dies mit minimalem zusätzlichen Aufwand. Also kann man diese Optimierung 
durchaus verwenden.

Man muß sich bloß klarmachen, dass die gewonnene Rechenzeit nicht für 
jeden Zweck einsetzbar ist, weil sie eben u.U. über einen längeren 
Zeitraum hinweg garnicht zur Verfügung steht. Sie wäre also nur dazu 
geeignet, nicht zeitkritische und lang laufende Hintergrundprozesse zu 
beschleunigen. Hast du solche nicht, kannst du mit der gewonnenen 
Rechenzeit auch nix anfangen.

> Irgendwie müsste man auch den (großen) Ringbuffer verkleinern oder
> (fast) ganz weglassen können....

Leider falsch.

Bei ungünstigen Messwerten führt jeder andere Ansatz als der Ringpuffer 
dazu, dass du mehr Rechenzeit und mehr Speicherplatz benötigst als 
dieser. Im Langzeit-Mittel könnte man mit solchen Ansätzen zwar 
ebenfalls den durchschnittlichen Speicherverbrauch auf gut die Hälfte 
reduzieren, aber nur im Durchschnitt verfügbarer zusätzlicher 
Speicherplatz läßt sich noch deutlich schwerer nutzbringend einsetzen 
als eben solche Rechenzeit...

Diese "Optimierung" ist also i.A. keine, sondern das genaue Gegenteil.

von Tom V. (vzczc)


Lesenswert?

...nach einer Tasse Kaffee würde ich es schlicht so umsetzen:

Neuen Messwert X einlesen und in den Ringpuffer schieben.
Ist X größer dem bisherigen Maximalwert MW? Ja, dann ist MW==X sonst 
wird der gesamte Ringpuffer auf den neuen Maximalwert MW durchsucht.

von Tom V. (vzczc)


Lesenswert?

Tom V. schrieb:
> Ist X größer

Korrektur: größer/gleich

...wennschon, dennschon...

von слюнотечение Тролль (Gast)


Lesenswert?

Nimm einen exponentiellen Mittelwert, der ist viel resourcenschonender. 
Beides, in Speicherplatz, und auch in Rechenleistung.
http://www.ibrtses.com/embedded/exponential.html

von BB84 (Gast)


Lesenswert?

Tom V. schrieb:
> ...nach einer Tasse Kaffee würde ich es schlicht so umsetzen:
>
> Neuen Messwert X einlesen und in den Ringpuffer schieben.
> Ist X größer dem bisherigen Maximalwert MW? Ja, dann ist MW==X sonst
> wird der gesamte Ringpuffer auf den neuen Maximalwert MW durchsucht.

Könnte man nicht noch zusätzlich auf das vom TO vorgeschlagene Alter 
eingehen? Also im Fall #2 nur auf neuen Maximalwerte prüfen wenn Alter 
>100?

von Wolfgang (Gast)


Lesenswert?

c-hater schrieb:
> Bei ungünstigen Messwerten führt jeder andere Ansatz als der Ringpuffer
> dazu, dass du mehr Rechenzeit und mehr Speicherplatz benötigst als
> dieser.

Wieso "mehr Rechenzeit und mehr Speicherplatz". Die Rechenzeit läßt 
sich minimieren, wenn man einen Index nach Alter und eine verkettete 
Liste nach Größe mitführt. Wenn ein neuer Wert eintrifft, wird der 
älteste Wert rausgeschmissen und der neue Wert in die verkettete Liste 
eingeklinkt. Der erste Wert der verketteten ist dann immer der gesuchte 
größte Wert.

Kostet Speicher, aber die Rechenzeit geht nur mit log(n).

von Walter S. (avatar)


Lesenswert?

слюнотечение Тролль schrieb:
> Nimm einen exponentiellen Mittelwert, der ist viel resourcenschonender.

ein Mittelwert hat leider mit einem Maximalwert nichts zu tun

von Walter S. (avatar)


Lesenswert?

BB84 schrieb:
> Könnte man nicht noch zusätzlich auf das vom TO vorgeschlagene Alter
> eingehen? Also im Fall #2 nur auf neuen Maximalwerte prüfen wenn Alter
> >100?
das wird doch schon durch den Ringbuffer berücksichtigt

von Simpel (Gast)


Lesenswert?

Du kannst auch einen zweiten Ringpuffer (Max_Buffer) anlegen, in welchen 
immer nur die neu gefundeneden Maximalwerte (sowie die gleichgrossen) 
obenauf eingetragen werden. Somit hast du eine sortierte Max_Liste. 
Einen Zeiger auf den aktuell gültigen setzen. Fällt dieser aus dem 
ersten Ringspeicher hinten raus, wird der Zeiger des Max_Buffers 
decrementiert, d.h. auf den nächst niedrigeren Max_Wert-Index gesetzt. 
Wird ein neuer Max_Wert (>=) gefunden, wird der Zeiger incrementiert und 
dort der neue bzw. der selbe Max_Wert reingeschrieben.

Das spart Zeit, wenn du z.B. monoton fallende Werte hast, d.h. wenn 
laufend der aktuelle Max_Wert hinten rausfliegt, weil der nächstniedrige 
Max_Wert sofort adressierbar ist. Das kostet aber das Doppelte an RAM, 
was bei kleinen µCs eher Mangelware ist, als Zeit.

Inwieweit die weiter oben angesprochene exponentielle Lösung hier 
praktikabel ist, würde mich aber auch interesserieren.

von Walter S. (avatar)


Lesenswert?

Wolfgang schrieb:
> Die Rechenzeit läßt
> sich minimieren, wenn man einen Index nach Alter und eine verkettete
> Liste nach Größe mitführt.

wie kommst du auf das log(n)?
Was ist wenn du einen SÄgezahn hast und die neuen Werte in 99% der Fälle 
immer ganz hinten einsortieren musst?

von Simpel (Gast)


Lesenswert?

Sehe grad... Wolfgang war schneller mit seiner Prinzipdarstellung...

von m.n. (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Eigentlich einfach: Ich mach einen Ringbuffer mit 100 Slots, schieb den
> neuen Wert hinein, und berechne danach das Maximum über den gesamten
> Ringbuffer.

Es ist doch einfach. Warum willst Du es dann komplizierter machen?
Allerdings solltest Du keinen Wert 'einschieben'(?) sondern nur ablegen.

Du schreibst nicht, welchen Datentyp Deine Meßwerte haben und welchen 
Prozessor Du nutzt. Sofern der µC den Datentyp direkt verarbeiten kann 
und nicht zusammenstückeln muß, ist die Suche doch recht fix erledigt.

von Simpel (Gast)


Lesenswert?

Ganz so einfach, mit dem zweiten Ringspeicher funktioniert's wohl nicht. 
Hatte es nur gedanklich kurz durchgespielt. Aber die Sortierung der 
Max_Werte ist bei Zwischenwerten so nicht gewährleistet... und ein 
Sortieralgorithmus führt das Ganze ad absurdum.
Deine Idee#1 dürfte wohl die einfachste und ausreichende Methode sein.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Danke für die rege Beteiligung!

Meßwerte sind uint8, wobei das Maximum bei "nur" 127 liegt (Werte werden 
vorher "gleichgerichtet")

Prozessor ist ein ATmega328P

Rechenzeit ist ein sekundäres Problem, Speicherplatz ist knapp, und ich 
würde die 100Byte Ringbuffer gerne minimieren.

Grundsätzlich geistert mir schon eine Idee im Kopf herum, die ich erst 
noch richtig behirnen muss....

gedankenexperiment: Ich hab einen normalen Sample-Buffer mit 256 Byte. 
da sample ich mal rein, gleichzeitig merk ich mir den maximalwert, ich 
habe also nach 256 Samples einen Max-Wert.

Diesen Max-Wert schieb ich jetzt in einen zweiten 256 Byte langen 
Sample-Buffer, wiederhole also praktisch Schritt 1. Nach 256*256 Samples 
habe ich dann den maximalwert über 65536 Samples. Ich hab also 65536 
Samples untersucht, brauche aber nur 512 Byte Speicherplatz. Irgendwie 
sowas wie ein "kaskadiertes Downsampling"

Das müsste ich jetzt nur mehr umdenken in mehrere 
hintereinandergeschaltete Buffer der Länge 2; und eine effiziente 
Implementierung finden.

von Gerhard Z. (germel)


Lesenswert?

Die Idee geht, wenn ich dich ganz oben richtig verstanden habe, nicht. 
Beispiel: Im ersten 256 byte Block hast du z.B. am Angang den Wert 120 
und am Ende 119 ==> Der Max-Wert ist 120, den du dir merkst. Im nächsten 
256 byte Block ist der Max-Wert z.B. 115 und liegt am Anfang des Blocks. 
Jetzt merkst du dir 115 obwohl doch 119 kurz vorher innerhalb des 
letzten 100 Wertebereichs bzgl. des 115 Werts ist.

Oder brauchst du wirklich nur den Max-Wert in einem Block und dann im 
nächsten unabhängig davon, was rauskäme, wenn man den Block Wert für 
Wert verschiebt und die gleiche Auswertung macht?

Gerhard

von Ernst O. (ernstj)


Lesenswert?

Wie definiert sich der Begriff "Maximum" bei deinem Projekt?

Wenn "Maximum" heisst, dass vorher und nachher die Messwerte niedriger 
lagen, dann braucht man die Messwerte nicht alle abspeichern, sondern es 
müsste reichen, jeden neu ankommenden Wert mit dem letzten Maximalwert 
zu vergleichen und nur dann abzuspeichern, wenn der neue Wert grösser 
ist.

Wenn "Maximum" heisst "grösster in den letzten x Sekunden aufgetretener 
Wert", dann funktioniert mein Vorschlag natürlich nicht.

von Walter S. (avatar)


Lesenswert?

Michael Reinelt schrieb:
> gedankenexperiment: Ich hab einen normalen Sample-Buffer mit 256 Byte.
> da sample ich mal rein, gleichzeitig merk ich mir den maximalwert, ich
> habe also nach 256 Samples einen Max-Wert.

Super, dann brauchst du den ersten Samplebuffer ja gar nicht!

Nee, für diese ganzen Ideen kann man immer ein Beispiel finden in dem 
sie nicht funktionieren,
sag doch erst Mal was du überhaupt machen willst, wie das Signal 
ausschaut usw.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Ernst Oellers schrieb:
> Wenn "Maximum" heisst "grösster in den letzten x Sekunden aufgetretener
> Wert",

Das heisst es

von F. F. (foldi)


Lesenswert?

Wenn man wüsste was genau du vor hast ...
Du könntest noch einen anderen Ansatz wählen.
Wenn du den ungefähren Maximalwert weißt, den schon mal mittelst, dann 
bräuchtest du nur noch eine Abweichung größer als X prüfen und würdest 
alles sehr beschleunigen.
Dich scheint ja aus allen Messungen nur der Maximalwert zu 
interessieren.
Aber ohne zu wissen wie genau das alles sein muss und was da passiert, 
ist auch das nur ein weiterer Vorschlag ins Leere.

von m.n. (Gast)


Angehängte Dateien:

Lesenswert?

Michael Reinelt schrieb:
> Rechenzeit ist ein sekundäres Problem, Speicherplatz ist knapp, und ich
> würde die 100Byte Ringbuffer gerne minimieren.

Zu wenig RAM oder zu wenig FLASH-ROM?
Den Ringpuffer wirst Du wohl nicht vermeiden können. In meinem 
0815-Beispiel heißt er dummy[n] und die Suchfunktion braucht 24 Byte 
Code.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

m.n. schrieb:
> Zu wenig RAM oder zu wenig FLASH-ROM?

Ram. Dort tummeln sich nämlich schon viele andere Buffer.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ich würde einen Heap verwenden.

http://de.wikipedia.org/wiki/Heap_%28Datenstruktur%29

Das Eintragen des neuesten Messerts, die Bestimmung des Maximums aus den
gepeicherten n Werten und das Löschen des jeweils ältesten Werts gehen
jeweils in O(log n), alles zusammen also ebenfalls in O(log n). Ander
der bereits vorgschlagenen Lösungen sind zwar evtl. im Mittel schneller.
Da die Messwerte aber mit fester Frequenz eintreffen, ist hier der
Worst-Case entscheidend, und der ist bei den anderen Lösung O(n).

Allerdings braucht man bei Verwendung des Heaps immer noch die Ringliste
zu Bestimmung des jeweils ältesten Eintrags. Alternativ kann man auch
die Elemente des Heaps mittels Zeiger in ihrer zeitlichen Reihenfolge
verketten, was sich aber nur dann lohnt, wenn die einzelnen Messwerte
mehr Speicher belegen als ein Zeiger.

von M. P. (phpmysqlfreak)


Lesenswert?

Wie sieht denn das Ausgangssignal aus? Wie sehr können die Werte 
innerhalb von einem Messzyklus abweichen?

Oder anders: Wie sieht das Mess-Signal aus? Frequenz? Signalform?
Also kurz: Was möchtest du messen?

: Bearbeitet durch User
von Jim B (Gast)


Lesenswert?

Wieso so kompliziert? Speichere doch  das Maximum und das Alter des 
Maximums. Beim neuen Messwert inkrementierst du das Alter und schaust, 
ob der Messwert größer ist als das gespeicherte Maximum, oder das Alter 
100 erreicht hat. Die verschiedenen Konsequenzen ergeben sic, denke ich, 
mit etwas Nachdenken selbst.
Gru§

von Walter S. (avatar)


Lesenswert?

Jim B schrieb:
> Beim neuen Messwert inkrementierst du das Alter und schaust,
> ob der Messwert größer ist als das gespeicherte Maximum, oder das Alter
> 100 erreicht hat. Die verschiedenen Konsequenzen ergeben sic, denke ich,
> mit etwas Nachdenken selbst.

und was mache ich wenn das Maximum das Alter 100 erreicht hat?
Irgendwie versuchen hier viele ein Perpetuum mobile zu erfinden

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Yalu X. schrieb:
> Da die Messwerte aber mit fester Frequenz eintreffen, ist hier der
> Worst-Case entscheidend, und der ist bei den anderen Lösung O(n).

Rechenzeit ist nicht mein (primäres) Problem. ich will den Ringpuffer 
sparen.

Marcel Papst schrieb:
> Wie sieht denn das Ausgangssignal aus? Wie sehr können die Werte
> innerhalb von einem Messzyklus abweichen?
>
> Oder anders: Wie sieht das Mess-Signal aus? Frequenz? Signalform?
> Also kurz: Was möchtest du messen?

Die Meßwerte sind quasi-zufällig. Eigentlich wird ein Audio-Signal 
abgetastet, Abtastung erfolgt mit 20480 Hz, da erfolgt aber noch ein 
Downsampling um Faktor 8, gespeichert werden 256 Byte. Parallel zum 
Samplen merke ich mir den maximalwert aller 256*8 = 2048 Samples. Ein 
Sample dauert also 100msec. Alle 100msec krieg ich also einen Peak-Wert. 
Das Audio-Signal selbst ist aber sehr dynamisch, enthält kurze aber sehr 
laute Stellen, dazwischen leise Pausen von (bis zu) mehreren Sekunden. 
Den Vorverstärker kann ich steuern, damit mein Pegel "ideal" im Sinne 
von "an den lautesten Stellen knapp an der Übersteuerungsgrenze" liegt.

Was ich verhindern will ist, dass in den Pausen aufgrund des niedrigen 
Maximalwertes die Verstärkung erhöht wird. Deshalb muss ich recht weit 
"in die Vergangenheit" schauen, wars dort laut, dann lass die 
Verstärkung wie sie ist. Erst wenns >10Sec (Beispielwert) leise war, geh 
mit der Verstärkung hoch.

Ich fürchte nur dass die Erklärung des Hintergrundes meiner eigentlichen 
Problemlösung nicht zuträglich ist. Mir gehts neben der konkreten 
Anwendung auch etwas ums Prinzip.

Ich beginne das aber langsam greifbar zu machen. Ich kann gedanklich 
"Stufen" aufbauen, die immer aus zwei Samples den Maximalwert ermitteln. 
Dazu brauch ich nur zwei Byte Speicher, plus ein Bit um "jedes zweite 
Mal" zu kodieren.

Pseudo-Code:
1
stage (uint8_t input) {
2
   old = new;
3
   new = input;
4
   if (bit == 0) {
5
      bit = 1;
6
   } else {
7
      bit = 0;
8
      next_stage(max(old, new));
9
   }
10
}

wenn ich 8 solcher Stufen hintereinanderschalte, brauche ich 2*8=16 Byte 
+ 1 byte für die 8 bits, habe aber einen viel größeren zeitraum 
abgedeckt.

Anders gesagt wäre das ein "komprimierter" Ringbuffer, wo die zeitliche 
Auflösung sich von Slot zu Slot verdoppelt

Aber der Knoten in meinem Kopf ist immer noch da :-)

von Walter S. (avatar)


Lesenswert?

Michael Reinelt schrieb:
> Ich fürchte nur dass die Erklärung des Hintergrundes meiner eigentlichen
> Problemlösung nicht zuträglich ist.

ja, das stimmt, denn wenn du das "Problem" gelöst hast, was machst du 
wenn nach 11 sec, du die Verstärkung hochregelst und plötzlich ein 
Paukenschlag kommt?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michael Reinelt schrieb:
> Erst wenns >10Sec (Beispielwert) leise war, geh mit der Verstärkung
> hoch.
Dir hilft also nicht der Maximalwert der letzten 10 Sekunden, denn es 
kann ja sein, dann 1x 127 kommt, und danach für 9s immer 126 und dann 0. 
Ergo wirst du bei einer Methode, die nur den einen Maximalwert 127 
ansieht und speichert, alle die 126 verlieren und schon nach 1s falsch 
reagieren

Ich würde einen Maximalwert speichern, dann denn gespeicherten 
Maximalwert mit der Zeit verringern (z.B. pro 1/10s um 1, dann ist aus 
den 127 nach 10 Sekunden der Wert 27 geworden). Und wenn zwischendurch 
ein neuer Maximalwert über diesem zurücklaufenden Maximalwert liegt, 
dann wird dieser Wert als neuer Maximalwert genpmmen und von dort aus 
zurückgezählt. So, wie die Peak-Anzeige in den VU-Metern auch 
funktioniert, nur eben mit gaaaaannnz langsamem Rücklauf...

: Bearbeitet durch Moderator
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Walter S. schrieb:
> ja, das stimmt, denn wenn du das "Problem" gelöst hast, was machst du
> wenn nach 11 sec, du die Verstärkung hochregelst und plötzlich ein
> Paukenschlag kommt?

Was ich dann mache: Pech haben :-)

Lothar Miller schrieb:
> Ich würde einen Maximalwert speichern, dann denn gespeicherten
> Maximalwert mit der Zeit verringern (z.B. pro 1/10s um 1, dann ist aus
> den 127 nach 10 Sekunden der Wert 27 geworden). Und wenn zwischendurch
> ein neuer Maximalwert über diesem zurücklaufenden Maximalwert liegt,
> dann wird dieser Wert als neuer Maximalwert genpmmen und von dort aus
> zurückgezählt. So, wie die Peak-Anzeige in den VU-Metern auch
> funktioniert, nur eben mit gaaaaannnz langsamem Rücklauf...

SO hab ichs derzeit. Das funktioniert leider ganz schlecht. Durch die 
langsame aber im Endeffekt zu schnelle Verringerung komm ich immer 
wieder in die Begrenzung, was die FFT (aus verständlichen Gründen) gar 
nicht mag...

von Anja (Gast)


Lesenswert?

Hallo,

warum machst Du es dann nicht so wie bei einer analogen ALC.

Ein Spitzenwertgleichrichter lädt den Kondensator mit einer geringen 
Zeitkonstante (attack) auf und mit einem Widerstand wird der Kondensator 
mit einer hohen Zeitkonstanten (decay) wieder entladen.

Gruß Anja

von Klaus (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Die Meßwerte sind quasi-zufällig. Eigentlich wird ein Audio-Signal
> abgetastet, Abtastung erfolgt mit 20480 Hz, da erfolgt aber noch ein
> Downsampling um Faktor 8, gespeichert werden 256 Byte. Parallel zum
> Samplen merke ich mir den maximalwert aller 256*8 = 2048 Samples. Ein
> Sample dauert also 100msec. Alle 100msec krieg ich also einen Peak-Wert.
> Das Audio-Signal selbst ist aber sehr dynamisch, enthält kurze aber sehr
> laute Stellen, dazwischen leise Pausen von (bis zu) mehreren Sekunden.
> Den Vorverstärker kann ich steuern, damit mein Pegel "ideal" im Sinne
> von "an den lautesten Stellen knapp an der Übersteuerungsgrenze" liegt.

Ich denke mit mit dem Maximum der letzten 100 Samples könnte das schief 
gehen. Nur mal als Beispiel: es gibt ein sehr lautes Sample, danach ist 
es ruhig. 99 mal ist das sehr laute Sample das Maximum und plötzlich, 
eine Samplezeit weiter gilt ein viel kleinerer Wert als Maximum.

Ich würde einfach eine Variable fürs Maximum nehmen. Kommt ein neues 
Sample rein das größer als der alte Max-Wert ist, wird das der neue 
Max-Wert. Ist es kleiner, wird vom alten Max-Wert etwas abgezogen und 
das wird der neue Max-Wert. Wieviel abgezogen wird, bestimmt dann das 
dynamische Verhalten des Systems. So gibt es keine Sprünge im Verhalten.

Nur mal so eine Idee mit wenig Speicherverbrauch.

Da war jemand schneller:

Lothar Miller schrieb:
> Ich würde einen Maximalwert speichern, dann denn gespeicherten
> Maximalwert mit der Zeit verringern (z.B. pro 1/10s um 1, dann ist aus
> den 127 nach 10 Sekunden der Wert 27 geworden). Und wenn zwischendurch
> ein neuer Maximalwert über diesem zurücklaufenden Maximalwert liegt,
> dann wird dieser Wert als neuer Maximalwert genpmmen und von dort aus
> zurückgezählt. So, wie die Peak-Anzeige in den VU-Metern auch
> funktioniert, nur eben mit gaaaaannnz langsamem Rücklauf...

MfG Klaus

von Yalu X. (yalu) (Moderator)


Lesenswert?

Michael Reinelt schrieb:
> Rechenzeit ist nicht mein (primäres) Problem. ich will den Ringpuffer
> sparen.

Da kommst du wohl nicht darum herum. Ist die Folge der Messwerte bspw.
101, 100, 99, ... 3, 2, 1, 0, 0, 0, ..., so taucht jeder der Werte
100 bis 1 der Reihe nach einmal als Maximum auf. Beim Eintreffen der
ersten 0 fällt die 101 aus dem FIFO-Puffer heraus, und 100 ist das neue
Maximum. Da die darauffolgenden Maximalwerte 99, 98, ... 0 lauten, darf
zu diesem Zeitpunkt keiner dieser 100 Werte verworfen werden, dewegen
braucht man Speicher für mindestens 100 Werte.

von Possetitjel (Gast)


Lesenswert?

Michael Reinelt schrieb:

> ich will den Ringpuffer sparen.

Im allgemeinen Falle geht das nicht. Das Beispiel, an dem
man das sieht, wurde auch schon genannt: Eine monotone
Wertefolge, z.B. monoton fallend. Dann ist immer der
älteste Wert das Maximum. Wenn ein neuer Wert kommt,
rücken alle eins weiter, und der zweitälteste wird zum
Maximum usf.
Aus der Folge kannst Du keinen Wert einsparen - sonst wird
das Maximum falsch.

Man könnte den Gedanken umdrehen und sich zu überlegen
versuchen, ob es genügt, alle lokalen Maxima zu speichern,
d.h. alle Werte, die größer sind als alle anderen Werte
ihrer Umgebung. Aus der Folge ...120, 12, 14, 11, 110...
kann man mMn die Teilfolge ...12, 14, 11... entfernen, da
nur 120 und 110 geeignete "Maximum-Kandidaten" sind. Das
läuft auf eine Art Datenkompression hinaus.
Den Wurst-Käse, dass Du evtl. alle Elemente speichern musst,
wirst Du auf diese Art aber nicht los.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michael Reinelt schrieb:
> Durch die langsame aber im Endeffekt zu schnelle Verringerung komm ich
> immer wieder in die Begrenzung
Kapiere ich nicht. Wenn du ein Signal hast, das nicht grösser als der 
letzte und sich inzwischen verringernde Maximalwert ist, wie kannst du 
dann übersteuern?

von c-hater (Gast)


Lesenswert?

Possetitjel schrieb:

> Im allgemeinen Falle geht das nicht.

Genau. Das bedarf unter logisch denkenden Programmierern eigentlich 
sowieso keiner Diskussion.

> Man könnte den Gedanken umdrehen und sich zu überlegen
> versuchen, ob es genügt, alle lokalen Maxima zu speichern

Das ist dann genau das, womit du durchschnittlich bestenfalls etwa die 
Hälfte des Speicherplatzbedarfs sparen kannst, im worst case aber mehr 
brauchst als der simpel gestrickte Ringpuffer.

Über den realen Nutzen dieser Ersparnis habe ich mich oben eigentlich 
bereits hinreichend ausgelassen. Er ist auf kleinen µC-Systemen 
definitiv praktisch Null und selbst auf großen Maschinen mit dynamischer 
Speicherverwaltung ist der Nutzen gering bis nicht vorhanden, weil die 
unvermeidliche Fragmentierung des Speichers es de facto verhindert, daß 
der "gewonnene" Speicherplatz sinnvoll verwendet werden kann.

Auch wenn es bitter für den OP ist: Nein, es gibt leider keine 
Optimierung für das Problem, die tatsächlich eine Ersparnis an SRAM 
bringen könnte.

Jetzt kann man anfangen zu heulen oder einfach den nächstgrößeren 
Controller verwenden, der i.A. auch mehr SRAM hat. Oder man kann 
anfangen, in größeren Zusammenhängen zu denken. Die Gewinnung des 
Maximums der letzten 100 Samples wird doch wohl wahrscheinlich nicht das 
einzige sein, was mit diesen Samples passiert...

Wenn überhaupt eine real nutzbare Speicherplatzersparnis rauskommen 
soll, dann kann sie nur durch Mehrfachnutzung von Speicher zustande 
kommen.

Und wenn ich im Thread lese, daß auf die Daten eine FFT angewendet wird 
(wozu das im konkreten Fall auch immer gut sein mag), dann rollen sich 
mir sofort die Fußnägel hoch. Eine FFT (vielmehr die dabei verwendeten 
Buffer) sind doch schließlich nichts anderes als eine Signalhistorie...

Die muß man nur clever mitnutzen und schon kommt man ohne einen 
zusätzlichen Buffer aus...

von karl (Gast)


Lesenswert?

Oder man verweigert sich der globalgalaktischen Lösung und löst es 
pragmatisch.

z.b maxwert = max(neuer wert, maxwert * tabelle[alter des alten max 
wertes])

Damit kann man das Verhalten der aufsteuerung beliebig vorgeben. Z.b 10 
s halten und dann irgendwie abfallen. Umsetzung kann per 
Ablaufsteuerung oder linear interpolierter Kennlinie oder Tabelle 
erfolgen.

Speicherbedarf: 1x maxwert 1x alter + Tabelle im Flash

von c-hater (Gast)


Lesenswert?

karl schrieb:

> Oder man verweigert sich der globalgalaktischen Lösung und löst es
> pragmatisch.
>
> z.b maxwert = max(neuer wert, maxwert * tabelle[alter des alten max
> wertes])

Selten so einem deutlichen Ausdruck von krassem Unwissen und 
Unverständnis begegnet.

Deine "tabelle[alter des max wertes]", ist im worst case exakt so groß 
wie der Ringpuffer, nur sehr viel komplizierter zu verwalten...

Solange du das nicht begreifst, bist du kein Programmierer...

von dbdb (Gast)


Lesenswert?

c-hater schrieb:
> karl schrieb:
>
> Oder man verweigert sich der globalgalaktischen Lösung und löst es
> pragmatisch.
> z.b maxwert = max(neuer wert, maxwert * tabelle[alter des alten max
> wertes])
>
> Selten so einem deutlichen Ausdruck von krassem Unwissen und
> Unverständnis begegnet.
>
> Deine "tabelle[alter des max wertes]", ist im worst case exakt so groß
> wie der Ringpuffer, nur sehr viel komplizierter zu verwalten...
>
> Solange du das nicht begreifst, bist du kein Programmierer...

Diese liegt aber im Flash. ..

von dbdb (Gast)


Lesenswert?

Statt der Tabelle kannst du natürlich auch eine analytische Funktion 
nehmen.

von Jens P. (picler)


Lesenswert?

Es funktioniert nur Idee 1 zuverlässig. Bei Idee 2 hast du das Problem, 
dass wenn nach 100 Messungen kein neuer Maximalwert kam, du ganz ohne 
Maximum da stehst. Das bisherige Maximum verwirft du wegen dem Alter und 
hast somit kein neues. Jetzt könntest du zwar den nächsten Wert der 
kommt als neues Maximum nehmen, aber dann ist es ja kein gleitendes 
Maximum mehr.

von Dieter F. (Gast)


Lesenswert?

"Slice the elephant" :)

Ich würde kleinere Pakete - meinetwegen jeweils 10 in einem Paket - 
machen und für die vergangenen 9 Pakete nur den jeweiligen Top-Wert in 
einem Ring-Puffer speichern. Für das 10. Paket würde ich die 10 Werte 
sammeln, wenn voll den Maximal-Wert in das letzte "Top-Paket" schieben 
und im Ring entsprechend weiterschieben. Ist dann zwar "etwas wackelig" 
(wenn Du 10 vergangene Pakete nimmst sollte das auch weg sein), sollte 
aber ausreichen.

von karl (Gast)


Lesenswert?

c-hater schrieb:
> Solange du das nicht begreifst, bist du kein Programmierer...

Glashaus, Steine. Hörst Du öfter, oder?

Aber du hast recht.  Bin kein Programmierer. Verdiene meine Brötchen 
meist mit Funktionsentwicklung und nicht mit dem runterschreiben von c 
oder gar Assembler.

Problem: Verstärkung an Hand des vergangenen Signals steuern. Der OP 
denkt er bräuchte dazu den gleitenden Maximalwert. Abgesehen von der 
tatsächlich interessanten Lösung dieses Problems wird er mit dessen 
Ergebnis mehr oder weniger zufrieden sein. Der Op wird aber an Hand des 
vergangenen Signals immer sagen können, wie er es gergeberne gehabt 
hätte. Da ist eine einfache Kennlinie Gold wert weil er sie ganz leicht 
anpassen kann. Das Verhalten ist ohne Änderung des Programmmablaufs 
ändernbar. Diese trennung von programmlogik und Kalibrierung vereinfacht 
das Lösen des eigentlichen Problems und hat sich überall dort 
durchgesetzt wo ein einzelner Hacker nicht ausreicht.

von Florian R. (Firma: TU Wien) (frist)


Lesenswert?

Hi
schade, dass der OP nicht das Maximum über sagen wir 200 Werte wissen 
möchte. Da er nur einen Wertebereich von 0-127 hat würde es sich dann 
nämlich lohnen statt der 200 Werte in einem Ringpuffer für die 128 
möglichen Werte je ihr letztes Auftreten zu speichern und dann immer 
durch absuchen dieser Liste den aktuellen Maximalwert zu ermitteln. 
Sprich sobald der Puffer länger ist als der Wertebereich große gibts 
Optimierungspotential (Speicher und Rechenleistung), oder irre mich da?

Grüße
Flo

von c-hater (Gast)


Lesenswert?

dbdb schrieb:

> Diese liegt aber im Flash. ..

Wohl kaum.

Das würde erfordern, das es für jede denkbare Variante der Historie eine 
solche Tabelle gäbe und natürlich einen zweiten Tabellenindex, über den 
anhand des aktuellen Samples auf die passende Variante zugegriffen wird.

Gesamt-Speicherbedarf weit jenseits dessen, was mit dem Flash einem 
Atmega möglich ist...

von Dieter F. (Gast)


Lesenswert?

Lustig, was ihr euch so akademisch ausdenkt ... :-)

von Walter S. (avatar)


Lesenswert?

Florian Rist schrieb:
> oder irre mich da?

nee, klingt gut,
und wenn man jetzt den Wertebereich weiter einschränkt (durch dividieren 
und/oder min/max Werte) kommt man z.B. mit 64 Einträgen aus

von Lattice User (Gast)


Lesenswert?

Florian Rist schrieb:
> Hi
> schade, dass der OP nicht das Maximum über sagen wir 200 Werte wissen
> möchte. Da er nur einen Wertebereich von 0-127 hat würde es sich dann
> nämlich lohnen statt der 200 Werte in einem Ringpuffer für die 128
> möglichen Werte je ihr letztes Auftreten zu speichern und dann immer
> durch absuchen dieser Liste den aktuellen Maximalwert zu ermitteln.
> Sprich sobald der Puffer länger ist als der Wertebereich große gibts
> Optimierungspotential (Speicher und Rechenleistung), oder irre mich da?
>

Das ist IMO ein sehr guter Ansatz.

Bei jedem Durchlauf alle Einträge in dieser Tabelle die größer Null sind 
decrementieren. Danach den Eintrag für den aktuellen Wert auf 100 bzw 
die Zahl der Wrte über die man den den maximalen Wert ermittelen möchts.

Der Wertebereich 0-127 ist ja ohnehin schon runterskaliert, 0-63 oder 
gar 0-31 ist vielleicht keine grosse Einschränkung.

von Jobst Q. (joquis)


Lesenswert?

Anja schrieb:
> Hallo,
>
> warum machst Du es dann nicht so wie bei einer analogen ALC.
>
> Ein Spitzenwertgleichrichter lädt den Kondensator mit einer geringen
> Zeitkonstante (attack) auf und mit einem Widerstand wird der Kondensator
> mit einer hohen Zeitkonstanten (decay) wieder entladen.
>
> Gruß Anja

Genau das halte ich für die praktikabelste Lösung. Ähnlich wie Lothars 
Vorschlag, aber die Reduzierung proportional statt linear. Dann ergibt 
sich eine Kurve wie die Entladung eines Kondensators über einen 
Widerstand. Der Vergleich mit neuen Maximas entspricht dem 
Spitzenwertgleichrichter.

von Dieter F. (Gast)


Lesenswert?

Lattice User schrieb:
> Das ist IMO ein sehr guter Ansatz.
>
> Bei jedem Durchlauf alle Einträge in dieser Tabelle die größer Null sind
> decrementieren. Danach den Eintrag für den aktuellen Wert auf 100 bzw
> die Zahl der Wrte über die man den den maximalen Wert ermittelen möchts.
>
> Der Wertebereich 0-127 ist ja ohnehin schon runterskaliert, 0-63 oder
> gar 0-31 ist vielleicht keine grosse Einschränkung.

Wäre da nicht eine Mutation der 3. Transwarp-Gleichung ein möglicher 
Ansatz (in Teilen zumindest) :-)

von Jobst Q. (joquis)


Lesenswert?

Noch etwas: Jede Lösung mit Ringpuffer und festen Maximalwerten ergibt 
keinen gleitenden Maximalwert, sondern einen springenden.

von Dieter F. (Gast)


Lesenswert?

Jobst Quis schrieb:
> Noch etwas: Jede Lösung mit Ringpuffer und festen Maximalwerten ergibt
> keinen gleitenden Maximalwert, sondern einen springenden.

Maximalwerte springen immer - oder? Man kann periodisch einen 
Durchschnitt über x vergangene Perioden bilden und das dann gleitend 
nennen ...

von karl (Gast)


Lesenswert?

c-hater schrieb:
> Das würde erfordern, das es für jede denkbare Variante der Historie eine
> solche Tabelle gäbe und natürlich einen zweiten Tabellenindex, über den
> anhand des aktuellen Samples auf die passende Variante zugegriffen wird.

Wlkikiv. In die Tabelle geht das Alter des letzten maximums.

Im Prinzip wie die attack und decay Geschichte nur dass man das 
decay-Verhalten sehr detailliert steuern kann. Praktikable Ergebnisse 
erreicht man mit 3 Bis 5 stützstellen und linearer  Interpolation.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Danke nochmal für eure Inputs.

Nach intensivem Nachdenken ist mir jetzt auch klar, dass ich um den 
Ringpuffer nicht herumkomme. Naja, immerhin auch eine Erkenntnis.

Zur Erläuterung, warum Lösungen wie von Lothar oder Anja vorgeschlagen 
schlecht funktionieren (ich übertreibe/überzeichne bewusst, unm das 
problem klar darzustellen):

"Dahinter" liegt eine FFT die Eingangssignale von -128..127 kriegt, vom 
ADC. Damit ich eine "schöne" aussteuerung habe, versuche ich den 
maximalpegel auf +/-100 auszuregeln, um noch etwas Headroom zu haben.

Gesampelt wird in Paketen zu 100 msec, nach einem (sehr kurzen) 
Preprocessing startet sofort das nächste Sample. Während eines Paketes 
kann und will ich die Verstärkung nicht anpassen (wäre auch der FFT 
nicht zuträglich). Problematisch sind Übersteuerungen, wo der ADC in die 
Begrenzung geht, da ich dann sofort Harmonische in der FFT habe. Also 
ist die Idee, nach jedem Paket den Peak zu ermitteln, und die 
Verstärkung so einzustellen dass der nächste Peak möglichst bei 100 
liegt. Das hab ich auch soweit im Griff (problematisch sind 
Übersteuerungen, da ich bei einem peak von 128 nicht weiss ob der peak 
128, 150, 200 oder 1000 ist, deshalb etwas improvisieren muss)

Und jetzt kommt das eigentliche Problem: Abgenommen wird ein Schlagzeug.

Angenommen, jemand tritt alle 2 Sekunden in die Bassdrum. Ich krieg also 
alle 2 Sekunden = alle 20 Pakete einen starken Peak. Idealerweise stelle 
ich die Verstärkung so ein, dass dieser Peak in einem maximalen ADC-Wert 
von 100 resultiert. Allerdings sollte ich 19 weitere Pakete die 
Verstärkung nicht ändern, auch wenn es leise ist, weil beim 20sten Paket 
wieder ein Peak kommt. Tu ich das, auch wenn stark gedämpft und 
exponentiell usw, laufe ich Gefahr beim nächsten Peak zu übersteuern 
bzw. in die Begrenzung zu laufen.

Allzu langsam soll es dann aber auch nicht sein: jemand steigt von 
Sticks auf den Besen um, die resultierenden Peaks sind wesentlich 
kleiner. Das System sollte sich also nach einer gewissen Wartezeit doch 
wieder schnell auf leisere pegel einstellen.

Ich weiss, nicht ganz einfach, aber man wächst ja mit seinen Aufgaben...

von Dieter F. (Gast)


Lesenswert?

karl schrieb:
> Wlkikiv.

Jetzt ist mir alles klar!

karl schrieb:
> Im Prinzip wie die attack und decay Geschichte nur dass man das
> decay-Verhalten sehr detailliert steuern kann. Praktikable Ergebnisse
> erreicht man mit 3 Bis 5 stützstellen und linearer  Interpolation.

Jo, eine Hüllkurve passt da prima. Schon mal geschaut, was der TO 
wollte?

Michael Reinelt schrieb:
> ich krieg alle 100ms einen Messwert, und möchte den Maximalwert über die
> letzten 100 Werte (entspricht den letzten 10 Sekunden) wissen.

In Folge muss ich aber auf meinen Beitrag

Dieter Frohnapfel schrieb:
> Wäre da nicht eine Mutation der 3. Transwarp-Gleichung ein möglicher
> Ansatz (in Teilen zumindest) :-)

verweisen ... der passt genau so gut!

Aber ich gebe jetzt auf ...

von karl (Gast)


Lesenswert?

Hast du versucht meinen Vorschlag zu verstehen?  Damit könntest du 
spielend 10 s halten und dann innerhalb von 2 s auf die gewünschte 
Verstärkung überblenden. Und das auch noch ohne undefinierte sprünge.

Wenn du möchtest, frag nach. Bin mir sicher das mein Vorschlag für dich 
gut funktioniert und außer 2 bytes keinen statisch belegten speicher 
braucht.

von karl (Gast)


Lesenswert?

Dieter Frohnapfel schrieb:
> Schon mal geschaut, was der TO wollte?
Sorry. Wlkikiv = wer lesen kann ist klar im Vorteil. Gilt aber nicht 
dir.

Der TO will eine Verstärkung Regeln. Dabei ist er zufällig am gleitenden 
Maximum vorbei gekommen, was sein Problem aber nur unzureichend lösen 
wird.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

karl schrieb:
> Hast du versucht meinen Vorschlag zu verstehen?  Damit könntest du
> spielend 10 s halten und dann innerhalb von 2 s auf die gewünschte
> Verstärkung überblenden. Und das auch noch ohne undefinierte sprünge.
>
> Wenn du möchtest, frag nach. Bin mir sicher das mein Vorschlag für dich
> gut funktioniert und außer 2 bytes keinen statisch belegten speicher
> braucht.

Ich komme gerne auf dich zurück, ich gestehe ich hab deinen Vorschlag 
nicht verstanden :-)

von Jobst Q. (joquis)


Lesenswert?

Dieter Frohnapfel schrieb:
> Jobst Quis schrieb:
>> Noch etwas: Jede Lösung mit Ringpuffer und festen Maximalwerten ergibt
>> keinen gleitenden Maximalwert, sondern einen springenden.
>
> Maximalwerte springen immer - oder? Man kann periodisch einen
> Durchschnitt über x vergangene Perioden bilden und das dann gleitend
> nennen ...

Maximalwerte können immer nach oben springen, das liegt in ihrer Natur. 
Aber bei den Ringpufferlösungen mit festen Maximalwerten springen sie 
auch nach unten, wenn die 10 Sekunden (oder was auch immer) vorbei sind.

Bei der dynamischen Lösung von Lothar, Anja und mir gleitet der Wert bei 
sinkendem Pegel elegant nach unten und die Sprünge nach oben sind 
häufiger, aber kleiner.

: Bearbeitet durch User
von X4U (Gast)


Lesenswert?

Michael Reinelt schrieb:
> ich krieg alle 100ms einen Messwert, und möchte den Maximalwert über die
> letzten 100 Werte (entspricht den letzten 10 Sekunden) wissen.

so quick und dirty: geht das nicht über die Dynamik?


> Was ich verhindern will ist, dass in den Pausen aufgrund des niedrigen
> Maximalwertes die Verstärkung erhöht

Mit dem Mittelwert des (abs) Delta der Sample lässt sich das Signal 
evtl. besser bewerten (bzw. charakterisieren).

von Gerd E. (robberknight)


Lesenswert?

Für mich hört sich die ganze Aufgabe ein wenig so an als ob da 
eigentlich ein Kompressor gesucht wird.

Mit dem Stichwort findest Du wahrscheinlich Ansätze wie andere das 
gelöst haben. Oder aber auch ein fertiges Modul was Du mal zum Testen 
vor Deine Schaltung hängen kannst.

von jens (Gast)


Lesenswert?

>Angenommen, jemand tritt alle 2 Sekunden in die Bassdrum. Ich krieg also
>alle 2 Sekunden = alle 20 Pakete einen starken Peak. Idealerweise stelle
>ich die Verstärkung so ein, dass dieser Peak in einem maximalen ADC-Wert
>von 100 resultiert. Allerdings sollte ich 19 weitere Pakete die
>Verstärkung nicht ändern, auch wenn es leise ist, weil beim 20sten Paket
>wieder ein Peak kommt. Tu ich das, auch wenn stark gedämpft und
>exponentiell usw, laufe ich Gefahr beim nächsten Peak zu übersteuern
>bzw. in die Begrenzung zu laufen.

Kombiniere doch einfach deine 2.Idee mit dem was Lothar vorgeschlagen 
hat.

>Idee #2: ich merke mir das Maximum und dessen "Alter". Wenn der aktuelle
>Wert größer oder gleich dem bisherige Maximum ist, neues Maximum setzen,
>Alter auf 0. Ansonsten Alter hochzählen, ist das Alter > 100,

wird der gespeicherten Maximalwert mit der Zeit verringert.

Damit bleibt ein gespeicherte Maximalwert bist zum Alter 100 konstant, 
solange kein größerer auftaucht.

von asdfasd (Gast)


Lesenswert?

Wenn du unbedingt dein Verfahren (max über Zeit x) verwenden willst, 
könntest du den Buffer in die (Analog-)Hardware verlegen: das Signal 
über eine Diode in einen Kondensator geben und den auf einen freien 
Analog-Pin legen (also ein Peak-Detector).  Nach dem Abfragen den Pin 
auf Ausgang schalten und den C löschen.  Hat den Vorteil, dass immer der 
Peak des realen Analog-Signals gemessen wird, auch wenn die Samples 
übersteuert waren.  Du brauchst also keinen Buffer mehr und weisst 
sogar, wieviel du übersteuert bist.

Profis legen den Ausgang des Peak-Detectors direkt auf den AGC des 
Verstärkers, entladen den C über einen Widerstand und nennen das ganze 
dann Kompressor ;-)

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Jobst Quis schrieb:
> Bei der dynamischen Lösung von Lothar, Anja und mir gleitet der Wert bei
> sinkendem Pegel elegant nach unten und die Sprünge nach oben sind
> häufiger, aber kleiner.

Klingt zwar gut, ist es aber nicht. Annahme: zum Zeitpunkt 0 kommt ein 
lautes Signal, der Einfachheit halber nehmen wir an die Verstärkung wäre 
bereits so eingestellt dass ich ADC-Werte genau im gewünschten Bereich 
-100..100 bekomme, ich hab also genügend "Luft" bis zur Begrenzung. Dann 
ist zwei Sekunden leise, die Werte sind -10..10, Maximalwert 
entsprechend 10, und nun lässt du die Verstärkung "elegant nach oben 
gleiten". Dann, zum Zeitpunkt 2 Sekunden, kommt wieder das exakt gleich 
laute Signal wie am Anfang. Die Verstärkung wurde aber erhöht, meine 
ADC-Werte wären nun (theoretisch) -150..150 praktisch bin ich aber voll 
in der Begrenzung.

X4U schrieb:
> Mit dem Mittelwert des (abs) Delta der Sample lässt sich das Signal
> evtl. besser bewerten (bzw. charakterisieren).

Die Bewertung zielt einzig darauf hinaus, das Signal nicht zu clippen, 
und dafür ist der Maximalwert am besten geeignet.

Gerd E. schrieb:
> Für mich hört sich die ganze Aufgabe ein wenig so an als ob da
> eigentlich ein Kompressor gesucht wird.

Kompressor wäre eine Möglichkeit, müsste ich aber analog realisieren, 
und dazu ist es zu spät. Abgesehen davon dass ich nicht weiss wie sich 
die Kompression in der FFT auswirkt.

asdfasd schrieb:
> at den Vorteil, dass immer der
> Peak des realen Analog-Signals gemessen wird, auch wenn die Samples
> übersteuert waren.  Du brauchst also keinen Buffer mehr und weisst
> sogar, wieviel du übersteuert bist.

Aufgrund der (nicht ganz geschickten) Schaltungsauslegung geht mir 
gleichzeitig mit dem ADC auch der OPV davon in die Begrenzung. Außerdem 
löst das mein Problem nicht: auch wenn ich weiß wieviel ich übersteuere, 
muss ich mir das immer noch meine 10 Sekunden merken.

ich werd jetzt mal meine 100 Byte für den Ringbuffer "suchen", eventuell 
temporär freimachen, und mal sehen wie sich das macht. Vielleicht löst 
sich das Problem ohnehin in Luft auf, weil mein "gleitender Maximalwert" 
nicht zum gewünschten Ergebnis führt.

von Tom B. (botas)


Lesenswert?

Hi,

hier noch ein weiterer Lösungsvorschlag:
Du kennst grob dein Signal. Also kann man mit einem gut gewählten 
Schwellwert zwischen Pause und "da spielt wer" unterscheiden. Oder man 
macht einen langsam gleitenden Mittelwert dafür. Kostet ja nur ein Byte:
Schwellwert = ((Schwellwert * viel) + neuerWert) / (viel +1)
Den sollte man dann aber auch etwas begrenzen. Es macht ja wenig Sinn 
nach einer längeren Pause den Verstärker so weit hoch zu drehen das man 
das Rauschen analysiert.

Nun nimmt man einen Zähler denn man, immer wenn ein Messwert über dem 
Schwellwert liegt, auf die Hälfte oder vielleicht auch nur ein Drittel 
der typischen ein Trommel-Schlag-Signaldauer setzt.

Bei jedem Durchlauf wird der Zähler decrementiert. So lange er größer 
Null ist kommen die Samples in den Ringbuffer. Dieser kann nun kleiner 
sein da die Pausen herausgefiltert sind.

Eigentlich kann man sich den Buffer dann auch sparen und den schon 
erwähnten UV-Meter "langsam abfallen"-Algorithmus nehmen. Die Pausen die 
ihn stören sind ja weg.

Und schon reicht eine handvoll RAM.


P.s. etwas OT: ich kenn mich mit FFT nicht so gut aus. Kommen da mit 8 
Bit Dynamik schon sinnvolle Ergebnisse raus?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Tom B. schrieb:
> P.s. etwas OT: ich kenn mich mit FFT nicht so gut aus. Kommen da mit 8
> Bit Dynamik schon sinnvolle Ergebnisse raus?

Ja. wobei - definiere "sinnvoll" :-) Für meine Anwendung reichts.

von Jobst Q. (joquis)


Lesenswert?

Michael Reinelt schrieb:
> Jobst Quis schrieb:
>> Bei der dynamischen Lösung von Lothar, Anja und mir gleitet der Wert bei
>> sinkendem Pegel elegant nach unten und die Sprünge nach oben sind
>> häufiger, aber kleiner.
>
> Klingt zwar gut, ist es aber nicht. Annahme: zum Zeitpunkt 0 kommt ein
> lautes Signal, der Einfachheit halber nehmen wir an die Verstärkung wäre
> bereits so eingestellt dass ich ADC-Werte genau im gewünschten Bereich
> -100..100 bekomme, ich hab also genügend "Luft" bis zur Begrenzung. Dann
> ist zwei Sekunden leise, die Werte sind -10..10, Maximalwert
> entsprechend 10, und nun lässt du die Verstärkung "elegant nach oben
> gleiten". Dann, zum Zeitpunkt 2 Sekunden, kommt wieder das exakt gleich
> laute Signal wie am Anfang. Die Verstärkung wurde aber erhöht, meine
> ADC-Werte wären nun (theoretisch) -150..150 praktisch bin ich aber voll
> in der Begrenzung.

Nur wenn du den Zeitfaktor zu klein machst. Aber es wird immer eine 
Musik geben, die für ein Konzept den Worst-Case darstellt. Für 10 
sekunden einen Wert zu halten und dann große Sprünge in der Verstärkung 
zu machen, wird die FFT und darauf folgendes auch irritieren.

Schreib doch mal, was du mit den FFT-Daten anstellen willst. Falls es 
eine Art Musikanalyse/Visualisierung sein soll, ist eine FFT eh nur 
bedingt tauglich, da sie frequenzlineare Daten ausgibt, die musikalische 
Struktur aber logarithmisch ist. Bei 20480 Samples/sek gibt eine 8-Bit 
FFT Daten im 80hz Raster aus. Also gibt es für die ersten beiden Oktaven 
des Hörbereichs nur einen Wert, dafür gibt es reichlich Daten in der 
Oktave ab 10khz, die kaum jemand hört.

Da im Bassbereich mit der FFT eh nur Matsch dargestellt werden kann, 
kannst du ihn mit einem Hochpass von der FFT wegfiltern und ihn auf 
anderer Weise detektieren.Dann gibts weniger Probleme mit Bassdrum und 
weniger Oberwellen bei Übersteuerung.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Jobst Quis schrieb:
> Für 10
> sekunden einen Wert zu halten und dann große Sprünge in der Verstärkung
> zu machen, wird die FFT und darauf folgendes auch irritieren.

Nein, weil die FFT immer nur mit 100msec-Paketen arbeitet, während denen 
der Gain nicht verändert wird.

Jobst Quis schrieb:
> Bei 20480 Samples/sek gibt eine 8-Bit FFT Daten im 80hz Raster aus.
Achtung Mißverständnis: Es wird zwar mit 20480Hz gesampelt, aber 
dahinter kommt ein 8:1 Dezimator + FIR, die für die FFT effektive 
Sample-Frequenz beträgt also 2560 Hz, Auflösung 10 Hz

Jobst Quis schrieb:
> Da im Bassbereich mit der FFT eh nur Matsch dargestellt werden kann,
Eben genau nicht. Mit der 10Hz Auflösung kann ich einzelne Trommeln 
trennen.

: Bearbeitet durch User
von X4U (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Die Bewertung zielt einzig darauf hinaus, das Signal nicht zu clippen,
> und dafür ist der Maximalwert am besten geeignet.

Meine Antwort bezog sich auf den Teil wo kein Signal gesendet.

Vielleicht ist es besser diesen Fall gesondert zu behandeln.

von Jobst Q. (joquis)


Lesenswert?

Michael Reinelt schrieb:
> Jobst Quis schrieb:
>> Für 10
>> sekunden einen Wert zu halten und dann große Sprünge in der Verstärkung
>> zu machen, wird die FFT und darauf folgendes auch irritieren.
>
> Nein, weil die FFT immer nur mit 100msec-Paketen arbeitet, während denen
> der Gain nicht verändert wird.

Wenn die Verstärkung springt, werden auch die FFT-Daten springen (von 
einem Block zum nächsten). Wenn das aber nicht stört, kannst du auch vor 
jedem FFT-Aufruf die Werte so skalieren, dass sie bis nahe an +-127 
gehen und nicht übersteuern.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Jobst Quis schrieb:
> kannst du auch vor
> jedem FFT-Aufruf die Werte so skalieren, dass sie bis nahe an +-127
> gehen und nicht übersteuern.

Da ist nix zu skalieren, weil die Übersteuerung/Begrenzung schon im ADC 
stattfindet.

von Jobst Q. (joquis)


Lesenswert?

Michael Reinelt schrieb:

> Da ist nix zu skalieren, weil die Übersteuerung/Begrenzung schon im ADC
> stattfindet.

Ich dachte, die ATMega-ADCs hätten mindestens 10 Bits.

: Bearbeitet durch User
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Jobst Quis schrieb:
> Ich dachte, die ATMega-ADCs hätten mindestens 10 Bits.

Haben sie auch, ändert aber nix, die Übersteuerung findet bereits am 
Eingang bzw. in den OPs vorher statt: Eingangssignal * Verstärkung > 5V, 
dann ist Schluß, auch mit beliebig vielen Bits des ADC.

von Jobst Q. (joquis)


Lesenswert?

Unter diesen gegebenen Umständen halte ich die Lösung von Karl mit der 
Tabelle im Flash für am besten. Da kannst du wenigstens das am wenigsten 
störende Verhalten einstellen.

Wenn es optimal werden soll, wäre eine Neukonzeption mit besseren 
Bauteilen angesagt.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Jobst Quis schrieb:
> Wenn es optimal werden soll, wäre eine Neukonzeption mit besseren
> Bauteilen angesagt.

Das liebe ich an der heutigen Zeit: Wenn Nachdenken körperliche 
Schmerzen verursacht, bewerfen wir das Problem lieber mit Hardware...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.