Forum: Mikrocontroller und Digitale Elektronik VU-Meter, aber korrekt!


von Wolfram F. (mega-hz)


Lesenswert?

Hallo,

ich möchte gerne ein VU-Meter als korrektes Messgerät bauen.
Insperiert von hier: 
https://www.hackster.io/ericBcreator/stereo-neopixel-ring-vu-meter-b28e78

Da wird der anzuzeigende Wert per

  leftValue = map(leftAnalogValue, minValue, maxValue, 0, maxSegments);
  rightValue = map(rightAnalogValue, minValue, maxValue, 0, 
maxSegments);

map-befehl ausgewertet, was natürlich nur was "fürs Auge" ist, aber 
nicht viel mit echten Messwerten zutun hat.

Um nun jeder LED (WS2812) nun einen bestimmten Wert zuweisen zu können,
müsste ich per

IF(Spannung => 775mV)
{
 LED_0dB = true;
}
else if (Spannung => 690mV)
{
 LED_-1dB = true;
}
else if (Spannung => ....

usw

.. etliche If-Schleifen einbauen mit deren der map Befehl ersetzt wird.

Das Anzeigeband soll von -40 bis +10dB mit 70 LEDs sein.

1) Wäre es trotz der vielen IF Schleifen trotzdem noch flüssig oder 
bräuchte man Assembler Routinen?

2) Wer kennt sich aus mit Assembler Routinen unter der Arduino-IDE?


Gruß,
Wolfram.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wolfram F. schrieb:
> map-befehl ausgewertet, was natürlich nur was "fürs Auge" ist, aber
> nicht viel mit echten Messwerten zutun hat.

Kommt auf die Linearität an.

> etliche If-Schleifen

Es gibt keine "If-Schleifen".

Nein, für 70 Vergleiche braucht man keinen Assembler.

von Stefan S. (chiefeinherjar)


Lesenswert?

Ich habe soetwas (zwar ohne "Neopixel") bereits gemacht.

Im Prinzip reicht eine For-SCHLEIFE. Die Skalierung kann entweder 
logarithmisch (am besten per LUT) oder linear erfolgen.

Linear sähe das in etwa so aus:
1
for(i = 0; i < NUM_STEPS; i++){
2
      if(adc_value >= (i+1)*STEP_SIZE){
3
         led_cnt++;
4
      } else {
5
          break;
6
      }
7
}
8
LED_Activate(led_cnt);

Bei einer (logarithmischen) LUT müsste man eben anstatt mit "STEP_SIZE" 
eben "LOG_LUT[i]" schreiben.

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

Moin,

Man braucht auch nichtmal 70 Vergleiche. log(70)/log(2) = 6.firlefanz. 
Also reichen pro Messung 7 Vergleiche.

Gruss
WK

von c-hater (Gast)


Lesenswert?

Wolfram F. schrieb:

> Das Anzeigeband soll von -40 bis +10dB mit 70 LEDs sein.

Das ist prinzipiell absolut kein Problem füt einen AVR8. Für 
IF-Schleifen-Benutzer/Arduino-Jünger könnte es allerdings etwas zu 
kompliziert werden...

Das sind vermutlich auch die einzigen Leute, die es nicht einfach 
machen, sondern erst die Öffentlichkeit eines Forums mit solchen 
Trivialitäten behelligen müssen...

von Michael B. (laberkopp)


Lesenswert?

Wolfram F. schrieb:
> ich möchte gerne ein VU-Meter als korrektes Messgerät bauen.

Da bist du noch weit von entfernt.

Grundlagen siehe:

http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.30.2

> .. etliche If-Schleifen einbauen

Es gibt keine If-Schleifen.
Beim Programmieren stehst du auch noch ganz am Anfang ?

> Das Anzeigeband soll von -40 bis +10dB mit 70 LEDs sein.

> 1) Wäre es trotz der vielen IF Schleifen trotzdem noch flüssig oder
> bräuchte man Assembler Routinen?

Wolfram F. schrieb:
> 2) Wer kennt sich aus mit Assembler Routinen unter der Arduino-IDE?

Echter Arduino-Code wird zu langsam sein. Aber ein Arduino ist auch in 
richtigem C und in Assembler programmierbar.

http://www.uni-koeln.de/phil-fak/muwi/ag/praktikum/assembler_arduino.pdf

Aber das wird man nur für kleine Stücke machen. Und es gibt schnelle 
Libs für WS2812. https://www.reddit.com/r/FastLED/

Das Mapping wird man sicherlich klüger programmieren. Zudem wird man den 
VU und den Peak-Wert mappen wollen, und das auch noch stereo.

Grundlage wäre: Man braucht 30us pro LED, für einen 70er Strip also 
2.1ms, stereo 4.2ms, macht 230 Hz Update refreshrate. Das reicht. Man 
kann es verkürzen, in dem man kürzere Strips parallel mit Daten 
versorgt.

Wenn deine +10dB so 3.16Vrms also 4.5Vpeak wären, sind -40dB so 10mV, 
das passt in 10 bit A/D und ein Array von 1024 bytes ist nicht zu gross, 
man wird also einfach
1
 einzuschaltende_LED_Position = vorberechnetesArray[Spannung_aus_ADC]
nutzen. Das geht schnell.

von Wolfram F. (mega-hz)


Lesenswert?

wieso sollen +10dB 3.16V sein?
Dachte das wären 2,449V!

Siehe http://www.sengpielaudio.com/dB-Tabelle.htm

Ok, ich werds mit ner Tabelle versuchen, Pointer auf diese..

von Wolfram F. (mega-hz)


Lesenswert?

c-hater schrieb:
> Wolfram F. schrieb:
>
>> Das Anzeigeband soll von -40 bis +10dB mit 70 LEDs sein.
>
> Das ist prinzipiell absolut kein Problem füt einen AVR8. Für
> IF-Schleifen-Benutzer/Arduino-Jünger könnte es allerdings etwas zu
> kompliziert werden...
>
> Das sind vermutlich auch die einzigen Leute, die es nicht einfach
> machen, sondern erst die Öffentlichkeit eines Forums mit solchen
> Trivialitäten behelligen müssen...

Danke für Deinen sinnlosen Kommentar!
Gerade in diesem Forum gibt es zu hauf immer wieder Leute wie Dich,
weshalb es immer unsympatischer wird..
Lass es!

von Michael B. (laberkopp)


Lesenswert?

Wolfram F. schrieb:
> wieso sollen +10dB 3.16V sein?

Damit der ganze Messbereich des A/D-Wandlers genutzt wird.
Da vor dem Analogeingang eh ein Gleichrichter und Hüllkurvenfilter sein 
muss, z.B. AD636, deine Prohrammierkenntnisse reichen nicht für eine 
Echtzeit-rms-Wandlung, kann man den Spannungspegel gleich passsend 
verstärken.

Je nach Signalquelle läge der 0dB Normpegel bei 1.228V (XLR), 0.775V 
(Cinch), 1.55V (ARD), 0.3162V (Klinke) oder 1uA (Diodenbuchse).

: Bearbeitet durch User
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

c-hater schrieb:
> Das sind vermutlich auch die einzigen Leute, die es nicht einfach
> machen, sondern erst die Öffentlichkeit eines Forums mit solchen
> Trivialitäten behelligen müssen...

... das wird hier langsam zur seuche und die tu's ziehen das niveau 
weiter und weiter runter, bäh!


mt

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Wolfram F. schrieb:
> Danke für Deinen sinnlosen Kommentar!
> Gerade in diesem Forum gibt es zu hauf immer wieder Leute wie Dich,
> weshalb es immer unsympatischer wird..
> Lass es!

sinnlos ist hier nur das gequake.
für blinde und talentfreie war dieses forum nie gedacht!

mt

von Klaus R. (klara)


Lesenswert?

Wolfram F. schrieb:
> ich möchte gerne ein VU-Meter als korrektes Messgerät bauen.

Aber natürlich. Nur Effektivwerte lassen sich nicht so leicht korrekt 
messen.
mfg Klaus

von Percy N. (vox_bovi)


Lesenswert?

Apollo M. schrieb:
> c-hater schrieb:
>> Das sind vermutlich auch die einzigen Leute, die es nicht einfach
>> machen, sondern erst die Öffentlichkeit eines Forums mit solchen
>> Trivialitäten behelligen müssen...
>
> ... das wird hier langsam zur seuche und die tu's ziehen das niveau
> weiter und weiter runter, bäh!
>

Dann erweise doch der Menschheit die Gnade und hebe das Niveau dieses 
Forums, indem Du selbst etwas sinnvolles zum Besten gibst. Die größte 
Belästigung hier geht von Leuten wie Dir aus, die völlig sinnfrei das 
Forum zumüllen.

Wenn Wolfram alles wüsste, bräuchte er hier nicht zu fragen.

Wenn Du etwas wüsstest, könntest Du es anderen mitteilen.

Beides scheint nicht zuzutreffen.

von Minimalist (Gast)


Lesenswert?

Stefan S. schrieb:
> Linear sähe das in etwa so aus:for(i = 0; i < NUM_STEPS; i++){
>       if(adc_value >= (i+1)*STEP_SIZE){
>          led_cnt++;
>       } else {
>           break;
>       }
> }
> LED_Activate(led_cnt);
>
> Bei einer (logarithmischen) LUT müsste man eben anstatt mit "STEP_SIZE"
> eben "LOG_LUT[i]" schreiben.

Dann kannst du die LUT direkt so aufsetzen, dass LED_Cnt rauskommt. Dann 
brauchst gar keinen Vergleich mehr. Nur ne Exceltabelle und ein bisschen 
Hirnschmalz im Vorraus.
In etwa:
LED_Cnt = LUT[adc_value]

von Wolfram F. (mega-hz)


Lesenswert?

aha, d.h., wenn ich ein Array mit 1024 Werten erstelle, kann für jede
Stufe des AD-Wandlers der Wert für die LED Nr. definiert werden?

etwa so:

byte LUT[1024] = {
  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1, 
1,   1,
  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1, 
1,   1,
  1,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3, 
4,   4,
  4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   6,   7,   7,   7, 
7,   8,

...

  69, 70 };

leftValue = LUT[analogRead(leftPin)];
rightValue = LUT[analogRead(rightPin)];

wird ne riesen Tabelle, kann man die nicht noch vereinfachen?

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Wolfram F. schrieb:
> kann man die nicht noch vereinfachen?

Was und wieso willst du denn immer noch weiter vereinfachen? Die 
eigentliche Software sind 2 Zeilen C fuer Stereo. Performancemaessig 
auch Anschlag. Klar, die olle Tabelle sind 1024 Eintraege, von denen am 
einen Ende immer ziemlich viele hintereinander gleich sind. So what?
Du musst die Tabelle nicht von Hand mit einem Taschenrechner erstellen, 
sondern darfst die C-sourcen auch per Sprache deiner Wahl erzeugen 
lassen.

Gruss
WK

von leo (Gast)


Lesenswert?

Wolfram F. schrieb:
> wird ne riesen Tabelle, kann man die nicht noch vereinfachen?

Ja, durch eine eingange kategorisch verworfene map()-Funktion. Diese 
setzt einen linearen Zusammenhang zwischen Signal und Ausgang voraus. 
Man kann auch quadratisch usw. mittels Formel interpolieren.
1
long map(long x, long in_min, long in_max, long out_min, long out_max)
2
{
3
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
4
}

Es ist wie oft eine Abwaegung zwischen Codegroesse und Geschwindigkeit, 
die man nur fuer die Zielarchitektur messen kann. Bei einer rein 
optischen Anzeige spielt das keine Rolle.

leo

von Wolfram F. (mega-hz)


Lesenswert?

so in etwa ist es jetzt auch, aber ich bezweifel, daß die Ergebnisse
des MAP Befehls so exakt sind wie die LUT-Methode!

  // map values
  float log10MaxDisplaySegments = log10(maxSegments);
  leftValue = map(leftAnalogValue, minValue, maxValue, 0, maxSegments);
  rightValue = map(rightAnalogValue, minValue, maxValue, 0, 
maxSegments);
  leftValue = ((log10(leftValue  + 1) / log10MaxDisplaySegments * 
maxSegments));
  rightValue = ((log10(rightValue  + 1) / log10MaxDisplaySegments * 
maxSegments));

von Wolfram F. (mega-hz)


Lesenswert?

Dergute W. schrieb:
> Du musst die Tabelle nicht von Hand mit einem Taschenrechner erstellen,
> sondern darfst die C-sourcen auch per Sprache deiner Wahl erzeugen
> lassen.
>
> Gruss
> WK

Sorry, ich komme nicht darauf, wie ich das Array richtig füllen kann,
zeigst Du mir bitte, wie?

von leo (Gast)


Lesenswert?

Wolfram F. schrieb:
> so in etwa ist es jetzt auch, aber ich bezweifel, daß die Ergebnisse
> des MAP Befehls so exakt sind wie die LUT-Methode!

Das ist keine Meinungsfrage. Es geht um linear oder nicht.

leo

von Karl K. (karl2go)


Lesenswert?

Wolfram F. schrieb:
> Gerade in diesem Forum gibt es zu hauf immer wieder Leute wie Dich,
> weshalb es immer unsympatischer wird..

Leider gibt es im Forum auch immer mehr Leute wie Dich, durch die es mit 
trivialen Fragen zugemüllt wird.

Nicht dass Fragen ansich etwas Schlechtes wäre, aber wenn so sehr 
deutlich wird, dass sich der Fragende so gar keine Gedanken gemacht 
hat...

leo schrieb:
> return (x - in_min) * (out_max - out_min) / (in_max - in_min) +
> out_min;

Wobei Dir das / auf dem Avr wieder die Performance versaut. Es sei denn 
Du bist so schlau die Werte auf 1024 und 0 zu setzen (was nicht ganz 
korrekt ist, denn in_max wäre ja 1023) und der Compiler kann da ein shr 
10 draus machen.

Wolfram F. schrieb:
> wird ne riesen Tabelle, kann man die nicht noch vereinfachen?

Drehs halt um: Mach eine Tabelle, wo für jede LED der ADC-Schwellwert 
drinsteht, und durchsuche dann die Tabelle bis Eingangswert < 
Schwellwert. Sind 144 statt 1024 Byte.

Wenn Du das linear durchsuchst, ist es immer noch schneller als das div 
mit longs. Wenn Du es verzweigt durchsuchst, bist Du mit 7 Schritten 
fertig.

von Karl K. (karl2go)


Lesenswert?

Wolfram F. schrieb:
> float log10MaxDisplaySegments = log10(maxSegments);

Oh bitte, beschäftige Dich mal mit den Grundlagen der µC-Programmierung.

float ist hier so ziemlich das Letzte, was Du nehmen solltest, und sowas 
wie log10 ist ganz böse. So ein AVR Controller hat keinen 
Mathe-Coprozessor.

Wolfram F. schrieb:
> ich komme nicht darauf, wie ich das Array richtig füllen kann,

Mit LibreOffice => Calc. Mehr brauchst Du nicht. LEDs 1 bis 72, dazu die 
Schwellwerte berechnen lassen, sinnvoll runden.

von Wolfram F. (mega-hz)


Lesenswert?

Karl K. schrieb:
> Drehs halt um: Mach eine Tabelle, wo für jede LED der ADC-Schwellwert
> drinsteht, und durchsuche dann die Tabelle bis Eingangswert <
> Schwellwert. Sind 144 statt 1024 Byte.

oder 70 Bytes, da ich 2 IOs für 2 Stripes mit je 70 LEDs verwenden will,
die Suche nach den richtigen Schwellwert kann ja einmal für den linken 
und einmal für den rechten Kanal aufgerufen werden.

Der Tip ist super, das werde ich die Tage probieren!

von Wolfram F. (mega-hz)


Lesenswert?

Karl K. schrieb:
>> float log10MaxDisplaySegments = log10(maxSegments);
>
> Oh bitte, beschäftige Dich mal mit den Grundlagen der µC-Programmierung.

:-) ich weiss, dieser Code stammt nicht von mir sonder aus dem o.g. 
Link...

von Karl K. (karl2go)


Lesenswert?

Wolfram F. schrieb:
> oder 70 Bytes

Words, da Du dann natürlich den Wertebereich des AD-Wandlers abbilden 
musst.

von Stefan S. (chiefeinherjar)


Lesenswert?

Karl K. schrieb:
> Drehs halt um: Mach eine Tabelle, wo für jede LED der ADC-Schwellwert
> drinsteht, und durchsuche dann die Tabelle bis Eingangswert <
> Schwellwert. Sind 144 statt 1024 Byte.

Das war auch eher das, worauf ich hinaus wollte; so hatte ich dies für 
"nur" 2 Mal 64 LEDs auch gelöst gehabt.
Bei meinem ursprünglichen Post habe ich dies etwas missverständlich per 
Nachtrag eingefügt gehabt.

Die Liste habe ich mir per Excel berechnen lassen und per Copy/Paste als 
LUT abgelegt.

von Michael B. (laberkopp)


Lesenswert?

Wolfram F. schrieb:
> kann man die nicht noch vereinfachen?

Man muss die Tabelle nicht eintippen, man kann sie am Programmanfang 
ausrechnen lassen.

von Minimalist (Gast)


Lesenswert?

Die Arduinos haben doch idr einen Mega328 oder vergleichbares an board. 
Mit 32k Flash würde ich mir nicht die Mühe machen da sparen zu wollen. 
Wir reden hier von 1/32 ~= 3% des verfügbaren Speichers.

von Karl K. (karl2go)


Lesenswert?

Minimalist schrieb:
> Mit 32k Flash würde ich mir nicht die Mühe machen da sparen zu wollen.

Dann muss man die LUT aber auch richtig im Flash ablegen, und nicht 
einfach als Array definieren, wo sie dann im Ram rumliegt.

Und: Es ist nie falsch sich Gedanken um effizientes Programmieren zu 
machen. Sonst kommt dann der nächste Heulthread: Hilfe, mein Arduino 
reicht nicht für den LED-Blinker, ich brauch dafür einen Raspberry.

von Wolfram F. (mega-hz)


Lesenswert?

Michael B. schrieb:
> Wolfram F. schrieb:
>> kann man die nicht noch vereinfachen?
>
> Man muss die Tabelle nicht eintippen, man kann sie am Programmanfang
> ausrechnen lassen.

das versuche ich gerade, komme aber nicht weiter... blöde Mathematik..

  // --- setup LookUpTable -------------
  Serial.begin(9600);
  for (i = 0; i < 1024; i++)
  {
    LUT[i] = log10(i / 70);
    Serial.println(LUT[i]);
  }
  // -----------------------------------

: Bearbeitet durch User
von Minimalist (Gast)


Lesenswert?

Mir fällt jetzt erst auf,  das -40db bis +10db Dynamik gewünscht wird. 
Das wird mit dem 10 bit ADC nicht gehen. Wahrscheinlich werden es mehr 
so -30db bis +5db werden.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Minimalist schrieb:
> Das wird mit dem 10 bit ADC nicht gehen.

Und wieso? Ich mein, nachdem hier zwar uldrakorreggd gemessen werden 
soll, aber bislang noch kein Wort ueber die Schaltung am Eingang des 
ADCs verloren wurde, glaub' ich zwar auch nicht so direkt an den 
sofortigen Erfolg, aber - watt solls? :-)
Fuer alle, die besser ihren Namen tanzen koennen als rechnen, hier ein 
Vorschlag fuer so eine 50dB Tabelle fuer 70 LEDs:
1
uint8_t bla[]={
2
 0, 0, 7,11,14,16,18,20,21,22,23,24,25,26,27,27,
3
28,29,29,30,30,31,31,32,32,33,33,33,34,34,34,35,
4
35,35,36,36,36,37,37,37,37,38,38,38,38,39,39,39,
5
39,39,40,40,40,40,40,41,41,41,41,41,41,42,42,42,
6
42,42,42,43,43,43,43,43,43,43,44,44,44,44,44,44,
7
44,45,45,45,45,45,45,45,45,45,46,46,46,46,46,46,
8
46,46,46,47,47,47,47,47,47,47,47,47,47,48,48,48,
9
48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49,
10
49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,
11
50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,
12
51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
13
52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
14
53,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,
15
54,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,
16
55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,
17
56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
18
56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,
19
57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
20
57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,
21
58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,
22
58,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,
23
59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,
24
59,59,59,60,60,60,60,60,60,60,60,60,60,60,60,60,
25
60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
26
60,60,60,60,60,60,60,60,61,61,61,61,61,61,61,61,
27
61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
28
61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
29
61,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,
30
62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,
31
62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,63,
32
63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,
33
63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,
34
63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,64,
35
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
36
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
37
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
38
64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65,
39
65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
40
65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
41
65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
42
65,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
43
66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
44
66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
45
66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
46
66,66,66,66,67,67,67,67,67,67,67,67,67,67,67,67,
47
67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,
48
67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,
49
67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,
50
67,67,67,67,67,67,67,67,67,67,67,67,67,67,68,68,
51
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
52
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
53
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
54
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
55
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,69,
56
69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
57
69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
58
69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
59
69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
60
69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
61
69,69,69,69,69,69,69,69,70,70,70,70,70,70,70,70,
62
70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,
63
70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,
64
70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,
65
70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70
66
};

Gruss
WK

von Rolf M. (rmagnus)


Lesenswert?

Wolfram F. schrieb:
> Das Anzeigeband soll von -40 bis +10dB mit 70 LEDs sein.

Also 0,714 dB pro LED?

Wolfram F. schrieb:
> das versuche ich gerade, komme aber nicht weiter... blöde Mathematik..
>
>   // --- setup LookUpTable -------------
>   Serial.begin(9600);
>   for (i = 0; i < 1024; i++)
>   {
>     LUT[i] = log10(i / 70);

Von welchem Typ ist i? Wenn es ein Integer ist, dann ist i / 70 eine 
Integer-Division, spirch: Nachkommastellen fehlen. Und davon wird dann 
dein Logarithmus gebildet.

>     Serial.println(LUT[i]);
>   }
>   // -----------------------------------

von Wolfram F. (mega-hz)


Lesenswert?

Dergute W. schrieb:
> Vorschlag fuer so eine 50dB Tabelle fuer 70 LEDs:
> uint8_t bla[]={
>  0, 0, 7,11,14,16,18,20,21,22,23,24,25,26,27,27,

hmm, was ist mit den LEDs 1,2,3,4,5 und 6?
die leuchten nach deiner Tabelle nie...

zur eingangsschaltung: ich habe vor, einen NE5532 als Anpassung an den 
AD vorzusetzen. Als gleichrichtung müsste eine Halbwelle doch reichen, 
oder?
Der AD soll eine externe Referenz-Spannungsquelle bekommen, dachte an 
4.096V.

Die Skala sollte +10,+9,+8,+7,+6,+5,+4,+3,+2,+1,0 und im
negativen Bereich -0.1, -0.2, -0,3, -0.4 -0.5, -0.6, -0.7, -0.8, -0.9, 
-1,
-1.5, -2, -2.5, -3, -3.5, -4, -4.5, -5, -5.5, -6, -6.5, -7, -7.5, -8,
-8.5, -9, -9.5, -10, -10.5, -11, -11.5, -12, -12.5, -13, -13.5, -14,
-14.5, -15, -15.5, -16, -16.5, -17, -17.5, -18, -18.5, -19, -19.5, -20,
-20.5, -21, -21.5, -22, -22.5, -23, -23.5, -24, -25, -30, -40
definiert werden.

Dazu ist sicherlich die Methode mit den Schwellwerten in einem Array 
wesentlich besser geeignet.
Der Verstärkungsfaktor des OPs wird dann so eingestellt, daß 4.096V 
+10db bzw. den AD Wert 1023 ergibt.

Wie "sauber" sampled der AD eigentlich? sollte man noch ein Oversampling 
mit einbauen? Und einen Lowpass filter < 25kHz ?

: Bearbeitet durch User
von Thorsten S. (thosch)


Lesenswert?

Dergute W. schrieb:
> Moin,
>
> Minimalist schrieb:
>> Das wird mit dem 10 bit ADC nicht gehen.
>
> Und wieso? Ich mein, nachdem hier zwar uldrakorreggd gemessen werden
> soll, aber bislang noch kein Wort ueber die Schaltung am Eingang des
> ADCs verloren wurde, glaub' ich zwar auch nicht so direkt an den
> sofortigen Erfolg, aber - watt solls? :-)
> Fuer alle, die besser ihren Namen tanzen koennen als rechnen, hier ein
> Vorschlag fuer so eine 50dB Tabelle fuer 70 LEDs:
>
> [c]uint8_t bla[]={
>  0, 0, 7,11,14,16,18,20,21,22,23,24,25,26,27,27,

Und hier reicht es, sich die erste Zeile anzuschauen,
um zu sehen, daß der ADC hierfür zu wenig Auflösung hat.

Denn wo sind die Einträge für die LEDs 1 bis 6, 9, 10, 13, 15, 17, 19?
Nach 0 LEDs gehen hier direkt die ersten 7 an, was natürlich Mist ist, 
denn von einem VU Meter erwartet man zu Recht, daß mit langsam 
steigendem Pegel eine LED nach der anderen angeht und nicht auf einen 
Schlag die ersten sieben.

Daß vor den ADC Input zumindest noch ein RMS-Wandler gehört, damit sowas 
wie ein VU-Meter dabei herauskommt, ist noch eine ganz andere Baustelle.

: Bearbeitet durch User
von ChrisMicro (Gast)


Lesenswert?

Hier bitteschön:
https://github.com/m5stack/M5Stack/blob/master/examples/Fire/M5StackFire_NeoPixelVUmeter/M5StackFire_NeoPixelVUmeter.ino

Den Logarithmus kann man sich sparen, weil die Tresholds über die 
Exponentialfunktione ( btw. Schrittweise Multiplikation ) berechnet 
werden können.

von Wolfram F. (mega-hz)


Lesenswert?

So, ich habe es nun hinbekommen!

Zuerst habe ich die 70 Spannungswerte in ein Array von Hand eingetragen:
1
// Spannungen in mV entsprechend dB
2
word LUT_U[71] =
3
{
4
  8, 25, 43, 48, 52, 55, 58, 62, 65, 69, // -40.0 -30.0 -25.0 -24.0 -23.5 -23.0 -22.5 -22.0 -21.5 -21.0
5
  73, 77, 82, 86, 92, 97, 103, 109, 116, 123, // -20.5 -20.0 -19.5 -19.0 -18.5 -18.0 -17.5 -17.0 -16.5 -16.0
6
  130, 138, 146, 155, 164, 173, 184, 195, 206, 218, // -15.5 -15.0 -14.5 -14.0 -13.5 -13.0 -12.5 -12.0 -11.5 -11.0
7
  231, 245, 259, 275, 291, 308, 327, 346, 367, 388, // -10.5 -10.0  -9.5  -9.0  -8.5  -8.0  -7.5  -7.0  -6.5  -6.0
8
  411, 436, 461, 489, 518, 548, 581, 615, 652, 690, //  -5.5  -5.0  -4.5  -4.0  -3.5  -3.0  -2.5  -2.0  -1.5  -1.0
9
  698, 706, 715, 723, 731, 740, 748, 757, 766, 775, //  -0.9  -0.8  -0.7  -0.6  -0.5  -0.4  -0.3  -0.2  -0.1   0.0
10
  869, 975, 1095, 1228, 1377, 1549, 1734, 1946, 2183, 2449  //  +1.0  +2.0  +3.0  +4.0  +5.0  +6.0  +7.0  +8.0  +9.0 +10.0
11
};
Dann eine zweite (leere) LUT erstellt,
1
word LUT_ADC[71] =
2
{
3
  // AD-Werte entsprechend dB (werden von der make_adc_value Routine erzeugt)
4
  0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, // -40.0 -30.0 -25.0 -24.0 -23.5 -23.0 -22.5 -22.0 -21.5 -21.0
5
  0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, // -20.5 -20.0 -19.5 -19.0 -18.5 -18.0 -17.5 -17.0 -16.5 -16.0
6
  0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, // -15.5 -15.0 -14.5 -14.0 -13.5 -13.0 -12.5 -12.0 -11.5 -11.0
7
  0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, // -10.5 -10.0  -9.5  -9.0  -8.5  -8.0  -7.5  -7.0  -6.5  -6.0
8
  0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, //  -5.5  -5.0  -4.5  -4.0  -3.5  -3.0  -2.5  -2.0  -1.5  -1.0
9
  0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, //  -0.9  -0.8  -0.7  -0.6  -0.5  -0.4  -0.3  -0.2  -0.1   0.0
10
  0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 1023  //  +1.0  +2.0  +3.0  +4.0  +5.0  +6.0  +7.0  +8.0  +9.0 +10.0
11
};
diese wird entsprechend dem Faktor 1023/Vref (z.z. 2.449V) mit den 
ADC-Werten gefüllt:
1
float faktor = 1023 / 2449.0 ;
2
void make_adc_value()
3
{
4
  for (i = 0; i < 71; i++)
5
  {
6
    LUT_ADC[i] = (int)LUT_U[i] * faktor + 0.5;
7
  }
8
}
Hier die Auswerte-Routine die die Anzahl der LEDs in leftValue bzw. 
rightValue ergibt:
1
void readValues() {
2
  leftAnalogValue = analogRead(leftPin);
3
  rightAnalogValue = analogRead(rightPin);
4
5
  for (i = 0; i < 71; i++)
6
  {
7
    if (leftAnalogValue < LUT_ADC[i])
8
    {
9
      leftValue = i;
10
      break;
11
    }
12
  }
13
  for (i = 0; i < 71; i++)
14
  {
15
    if (rightAnalogValue < LUT_ADC[i])
16
    {
17
      rightValue = i;
18
      break;
19
    }
20
  }
21
22
  Serial.print("LED: ");
23
  Serial.print(leftValue);
24
  Serial.print("      ADC: ");
25
  Serial.print(LUT_ADC[i]);
26
  Serial.print("      mV: ");
27
  Serial.println(LUT_U[i]);
28
}
natürlich dann ohne die Serial.prints...

Ergebnis passt super!
Serial:
1
LED: 43      ADC: 129      mV: 308
2
LED: 42      ADC: 122      mV: 291
3
LED: 42      ADC: 145      mV: 346
4
LED: 42      ADC: 145      mV: 346
5
LED: 42      ADC: 145      mV: 346
6
LED: 42      ADC: 145      mV: 346
7
LED: 41      ADC: 137      mV: 327
8
LED: 41      ADC: 137      mV: 327
9
LED: 41      ADC: 137      mV: 327
10
LED: 41      ADC: 137      mV: 327
11
LED: 41      ADC: 229      mV: 548
12
LED: 40      ADC: 229      mV: 548
13
LED: 40      ADC: 229      mV: 548
14
LED: 40      ADC: 216      mV: 518
15
LED: 40      ADC: 216      mV: 518
16
LED: 40      ADC: 216      mV: 518
17
LED: 39      ADC: 216      mV: 518
18
LED: 39      ADC: 216      mV: 518
19
LED: 39      ADC: 216      mV: 518
20
LED: 39      ADC: 204      mV: 489
21
LED: 39      ADC: 204      mV: 489
22
LED: 38      ADC: 204      mV: 489
23
LED: 38      ADC: 204      mV: 489
24
LED: 38      ADC: 204      mV: 489
25
LED: 38      ADC: 204      mV: 489
26
LED: 37      ADC: 193      mV: 461
27
LED: 37      ADC: 193      mV: 461

Soweit so gut, vielleicht könnte man da noch etwas optimieren?
Danke an alle die mir hier geholfen haben!
Nun gehts an die Referenzspannungsquelle, Gleichrichtung und um den 
OP...

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

Moin,

Thorsten S. schrieb:
> Nach 0 LEDs gehen hier direkt die ersten 7 an, was natürlich Mist ist,
> denn von einem VU Meter erwartet man zu Recht, daß mit langsam
> steigendem Pegel eine LED nach der anderen angeht und nicht auf einen
> Schlag die ersten sieben.

Ja Mei. So 'n Logarithmus ist halt ein klassicher Vertreter einer 
nicht linearen Funktion. Da kann sowas schonmal passieren, auch wenns 
einem so ueberhaupt nicht in den Kram passt...

Wolfram F. schrieb:
> vielleicht könnte man da noch etwas optimieren?

Laeuft doch alles. Hoer' doch mal auf, immer alles ums Verrecken 
optimieren zu wollen. Mach' erstmal. Wenns dann irgendwo zu langsam oder 
zu gross oder zu Teppich wird, kannste immernoch mit "optimieren" 
anfangen.

ChrisMicro schrieb:
> Hier bitteschön:
> 
https://github.com/m5stack/M5Stack/blob/master/examples/Fire/M5StackFire_NeoPixelVUmeter/M5StackFire_NeoPixelVUmeter.ino

Ja, jeder Depp hat wohl schonmal sowas zusammengespaxt; das www ist voll 
davon. Ich nehm' mich da mal nicht aus:-)

Beitrag "VU-Meter mit Attiny13a statt LM3916"

Gruss
WK

von Wolfram F. (mega-hz)


Lesenswert?

Dergute W. schrieb:
> Laeuft doch alles. Hoer' doch mal auf, immer alles ums Verrecken
> optimieren zu wollen. Mach' erstmal. Wenns dann irgendwo zu langsam oder
> zu gross oder zu Teppich wird, kannste immernoch mit "optimieren"
> anfangen.

Na ich mag es eben wenns geht, gleich optimal zu programmieren.
Das habe ich mir angewöhnt, seit dem ich mal meine Listings von 1988 
unter 6502 Assembler angeschaut habe :-)

Platine und Gehäuse sind in Arbeit, wird sicher ein schönes Gerät.

von ChrisMicro (Gast)


Lesenswert?

>Beitrag "VU-Meter mit Attiny13a statt LM3916"

Den Effektivwert über die 1000 Samples berechne ich auch. Es hat sich 
auch herausgestellt, dass beim M5Stack den Gleichspannungsoffset am 
besten abzieht.

Ich habe den Logarithmus durch die Umkehrfunktion ersetzt, weil ich den 
Code minimalistisch halten wollte. Das Ergebnis ist gleich. Der Code ist 
nicht zeitoptimiert, muss er meiner Meinung nach auch nicht sein.

Wenn man es genau machen will, ist der Wikipedia-Beitrag nützlich.
Speziell was das Timing angeht:

https://en.wikipedia.org/wiki/VU_meter

Hab's leider auch erst jetzt gesehen.

>Ja, jeder Depp hat wohl schonmal sowas zusammengespaxt; das www ist voll
>davon. Ich nehm' mich da mal nicht aus:-)

Lass diese Ausdrucksweise bleiben.

von Karl K. (karl2go)


Lesenswert?

ChrisMicro schrieb:
> Lass diese Ausdrucksweise bleiben.

Heul doch!

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.