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...
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
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
...ich würde es auch als Ringpuffer umsetzen. Alle 100ms 100 Werte vergleichen lastet einen MC nicht unbedingt aus ;-))
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
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.
...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.
Nimm einen exponentiellen Mittelwert, der ist viel resourcenschonender. Beides, in Speicherplatz, und auch in Rechenleistung. http://www.ibrtses.com/embedded/exponential.html
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?
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).
слюнотечение Тролль schrieb: > Nimm einen exponentiellen Mittelwert, der ist viel resourcenschonender. ein Mittelwert hat leider mit einem Maximalwert nichts zu tun
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
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.
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?
Sehe grad... Wolfgang war schneller mit seiner Prinzipdarstellung...
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.
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.
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.
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
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.
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.
Ernst Oellers schrieb: > Wenn "Maximum" heisst "grösster in den letzten x Sekunden aufgetretener > Wert", Das heisst es
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.
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.
m.n. schrieb: > Zu wenig RAM oder zu wenig FLASH-ROM? Ram. Dort tummeln sich nämlich schon viele andere Buffer.
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.
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
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§
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
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 :-)
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?
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
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...
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
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
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.
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.
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?
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...
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
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...
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. ..
Statt der Tabelle kannst du natürlich auch eine analytische Funktion nehmen.
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.
"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.
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.
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
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...
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
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.
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.
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) :-)
Noch etwas: Jede Lösung mit Ringpuffer und festen Maximalwerten ergibt keinen gleitenden Maximalwert, sondern einen springenden.
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 ...
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.
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...
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 ...
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.
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.
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 :-)
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
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).
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.
>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.
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 ;-)
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.
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?
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.
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.
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
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.
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.
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.
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
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.