kann es sein, dass tone(), nicht jede ganzzahlige Frequenz ausgeben kann, sondern gewisse Schrittgrößen, bzw. Raster hat?
Ich habe eine Anwendung, die ein Messsignal als Rechteckspannung ausgeben soll und dazu benutzte ich tone() mit variablem Parameter.
Die Ausgangsfrequenz ist 3000 Hz, mein Oszilloskop zeigt mir allerdings 3010 Hz an. Kleine Schritte ändern diesen Wert nicht, erst ab etwa 2070 Hz geht die Frequenz tatsächlich runter - es scheint also kein Offset zu sein, sondern ein Raster, über das die Frequenz läuft.
Kann das jemand bestätigen?
kann es sein, dass tone(), nicht jede ganzzahlige Frequenz ausgeben kann, sondern gewisse Schrittgrößen, bzw. Raster hat?
Ja, natürlich. Du bist hier bei Digitaltechnik.
Und aus dem Systemtakt von 16 MHz läßt sich durch die wenigen verfügbaren ganzzahlige Vorteiler(Prescaler) und Teiler nicht jede beliebige andere ganzzahlige Fequenz hundertprozentig exakt herstellen.
Die einstellbaren Frequenzen liegen im unteren Frequenzbereich bis zu wenigen tausend Hertz allerdings immer recht nah an der Wunschfrequenz, mit nur sehr geringen Frequenzabweichungen. Aber oberhalb des Hörbereichs im Ultraschallbereich werden die Frequenzabweichungen dann ggf. auch mal größer ausfallen.
Die von Dir behauptete Frequenzlücke zwischen 3010 und 2070 Hz halte ich allerdings für viel zu hoch, die sollte meiner Meinung nach deutlich geringer sein.
Ich weiß zwar nicht wie groß die Frequenzdiffernz zwischen 2 nahen Frequenzen ist, aber hier https://www.arduino.cc/en/Tutorial/ToneKeyboard?from=Tutorial.Tone3 ist eine Liste der Frequenzen von den Musiktönen. Ich nehme an, daß diese schon von tone() gespielt werden können.
Dass ich es mit diskreten Werten zu tun habe war mir schon klar, ich hatte nur blauäugig erst einmal angenommen, dass diese auf den Ganzzahlen liegen.
Ich bin die Frequenzen einmal abgelaufen und habe gemessen, ab wann sie jeweils auf die nächste Frequenz umspringen. Ich habe festgestellt, dass das Spektrum überhaupt nicht gleichmäßig abgedeckt wird.
Ich hätte erwartet, dass die Abstände größer werden, also Verdopplung der Frequenz = Verdopplung der Frequenzlücke oder etwas ähnliches.
Im Messbereich von 3000 bis 3960 wachsen die Lücken aber von 36 - 60 und von 3937 bis 4166 gehen sie dann von 15 - 17, weiter habe ich nicht gemessen.
Nach 2000 kommt 2016, nach 4000 kommt 4016 und nach 8000 kommt 8064.
Vielleicht kennt sich jemand mit der Funktion genauer aus und kann erklären, wie die Spannung generiert wird?
Im Wesentlichen möchte ich einfach nur in der Lage sein, ganzzahlige Sensorwerte von -1080 bis +1080, also gut 2000 verschiedene Werte, analog auszugeben.
Nik_Del:
Vielleicht kennt sich jemand mit der Funktion genauer aus und kann erklären, wie die Spannung generiert wird?
Im Wesentlichen möchte ich einfach nur in der Lage sein, ganzzahlige Sensorwerte von -1080 bis +1080, also gut 2000 verschiedene Werte, analog auszugeben.
So ganz detailliert habe ich mir die tone() Funktion nicht angesehen, als dass ich es Dir haarklein erklären könnte, aber meines Wissens nach arbeitet die tone() Funktion so:
Es wird ein sehr schneller Timer-Interrupt aufgesetzt, mit einer Frequenz über 20 kHz, und in der Timer-Interruptbehandlung wird abgezählt: Aus der Häufigkeit, wie oft die Interrupt-Behandlungsroutine aufgerufen wird und der bekannten Zeitdauer zwischen zwei Timer-Interrupts wird abgezählt, nach wie vielen Interrupts wieder ein Flankenwechsel stattfinden muss, und der wird dann auf den Ausgang geschrieben. Die Frequenzlücken ergeben sich dann daraus, daß einerseits die Frequenz des Timer-Interrupts in kein ganzzahliges Vielfaches der auszugebenden Frequenz sein wird und dass anderseits beim Abzählen der Interrupts zwischen zwei Flankenwechseln immer ein Rundungsfehler von bis zu einem Interrupt-Takt im Algorithmus auftreten kann. Und das führt eben dazu, dass am Ende nicht jede ganzzahlige Frequenz bis auf die dritte Stelle nach dem Komma akkurat ausgegeben werden kann, sondern Frequenzlücken entstehen, mit der Folge, dass fast alle ganzzahligen Frequenzen nur mit einer Abweichung von der Sollvorgabe erzeugt werden können.
ich glaube das kann so nicht sein wie du es beschreibst
Nehmen wir 20Khz als Timerfrequenz an, wäre ein 20KHz Tone möglich, der nächste könnte aber nur 10KHz haben. Alles dazwischen wäre garnicht machbar. Dann 5K, dann 2,5k usw. Also halbierend. Weil du ja nur ganzzahlig teilen kannst. Selbst bei 100KHz Timerfrequenz sind dann nur sehr grobe Abstufungen möglich
100KHz/50 = 2KHz
100KHz/51 = 1960Hz
100KHz/100 = 1KHz
100KHz/101 = 990Hz
Eher wird da wohl ein Timer genau so gesetzt das aus dem Grundtakt die Frequenz entsteht und bei jedem Aufruf wird der Ausgang getoggelt. Auch das bleibt halt stufig. Wieso aber solche Abweichungen in den Stufen...wäre interessant zu erfahren.
chefin:
ich glaube das kann so nicht sein wie du es beschreibst
Nehmen wir 20Khz als Timerfrequenz an, wäre ein 20KHz Tone möglich, der nächste könnte aber nur 10KHz haben. Alles dazwischen wäre garnicht machbar. Dann 5K, dann 2,5k usw. Also halbierend. Weil du ja nur ganzzahlig teilen kannst. Selbst bei 100KHz Timerfrequenz sind dann nur sehr grobe Abstufungen möglich
100KHz/50 = 2KHz
100KHz/51 = 1960Hz
100KHz/100 = 1KHz
100KHz/101 = 990Hz
Eher wird da wohl ein Timer genau so gesetzt das aus dem Grundtakt die Frequenz entsteht und bei jedem Aufruf wird der Ausgang getoggelt. Auch das bleibt halt stufig. Wieso aber solche Abweichungen in den Stufen...wäre interessant zu erfahren.
Ja, so ungefähr hätte ich es erwartet. Es scheint so, als gäbe es verschiedene Bereiche, innerhalb derer die Abstände mit der Frequenz gleichmäßig wachsen, bis ein neuer Bereich anfängt.
Ich habe übrigens mittlerweile die Library toneAC gefunden, die tatsächlich in der Lage ist, auch um 2 kHz herum Frequenzen mit Unterschieden von 1 Hz zu erzeugen. Der Teufel steckt also offenbar nicht (nur) in der Hardware, sondern in der Library. Mein Kernproblem ist damit gelöst
Wenn man tone() nur für einfache Töne braucht, sollte es reichen.
Die in der üblichen Musik verwendeten Töne
12 Schritte bis die doppelte/halbe Frequenz ("Oktave") erreicht ist
die auch in der üblichen Notenschrift dargestellt werden können
für die es Namen in der Library (pitches.h) gibtliegen um ca. 5,95% auseinander. Das reicht näherungsweise mit den hier verwendeten Zählern, selbst bei einem 8-bit Timer.
Der nächste Ton nach einem "a" (NOTE_A4) mit 440 Hz ist das "ais" oder "b" (NOTE_AS4) mit 466 Hz.
Den Unterschied zwischen 2000 und 2001 Hz bemerkt ein normaler Mensch nur, wenn beide Töne gleichzeitig zu hören sind, an den überlagerten "Schwebungen".
In der Digitaltechnik gibt es sowieso keine stufenlosen Unterschiede.
(Im echten Leben übrigens auch nicht, wenn man es quantenphysikalisch sieht)
Fragt sich immer, wie genau man was braucht.
So ab 100KHz Timerfrequenz (also alle 10µs einen Interrupt) kommt man in den bereich, das tiefe Töne bis hin zum Sprachbereich nur Abweichungen von ca 5Hz haben. Wobei manche Töne bis auf 0,0xHz genau getroffen werden, aber auch bis zu 5 Hz abweichen.
Höher als 1Khz Tonhöhe und die Abweichungen gehen auch mal bis zu 10Hz daneben.
100KHz Timerfrequenz dürfte aber den Arduino nahezu völlig auslasten, weil ihm gerade mal 160 Takte zwischen 2 Interrupts bleiben.
Es ist sicherlich eine Möglichkeit, aber die spielt extrem falsch, so falsch das selbst unmusikalische Menschen das hören und sie kostet viel CPU-Last.
Eleganter ist es, den Timer auf die Frequenz zu setzen. Will ich 4KHz, lasse ich alle 125µsec einen Interrupt kommen. Gegenüber der Teilervariante die alle 10µsec einen Interrupt auslöst ist das deutlich schonender. Und brauche ich nur 1Khz Ton, bin ich bei 0,5msec. So bekomme ich viel genauer den Ton hin und deutlich CPU-schonender.
Und da der Threadstarter das Problem mit einer anderen Bibliothek lösen konnte, gehts hier eigentlich nur noch um theoretische Ansätze. Aber ich nehme mir trotzdem die Freiheit einen relativ untauglichen Ansatz zu bewerten. Natürlich kommt da irgendwas an Musik dabei raus, aber die Masse an Nachteilen ist so hoch, das man es besser wieder vergisst
Hast du auch mal tone.cpp angeguckt?
Deine Berechnungen sind relativ irrelevant, ausser du willst was völlig anderes erfinden.
Frequenzabweichungen als Differenz zu betrachten, ist übrigens der falsche Ansatz:
10 Hz Unterschied ist nur ganz leicht verstimmt bei 2000 Hz , aber bei tieferen Tönen schon ein ganzer Ton daneben (z.B E3 = 164,8 Hz / F3 = 174,6 Hz).
tone() ist nett, um einigermassen wiedererkennbare Melodien auf einem Piezo zu erzeugen, mehr nicht. Allein die fehlende Möglichkeit der Lautstärke-Änderung zeigt, dass tone() nicht wirklich mit Musik-Erzeugung zu tun hat.
Eine weitere Frage ist, wie lange dein Messsignal ausgewertet wird. Um 2000 von 2001Hz zu unterscheiden, musst du mindestens eine Sekunde lang messen. Je nach Anwendung ist das eine Ewigkeit.
... Oder 499,75 µs von 500,0 µs unterscheiden können. Dann kannst du zu jedem Signalwechsel sofort die Frequenz angeben. Wenn man nur 4997 µs von 5000 µs unterscheiden kann, braucht man eben 5 ms oder 10 Perioden, um 2000 Hz von 2001 Hz unterscheiden zu können. (usw.)
Wenn man nur die Anzahl Schwingungen je festem ZeitIntervall zählt, dauert es länger, da hast du recht.
michael_x:
... Oder 499,75 µs von 500,0 µs unterscheiden können. Dann kannst du zu jedem Signalwechsel sofort die Frequenz angeben.
Das setzt aber auch voraus, dass das Timing der Signalerzeugung perfekt gleichmäßig ist und kein Jitter im Signal ist. Der Unterschied von 0,25µs sind nur 4 Prozessortakte bei 16Mhz.
Der Unterschied von 0,25µs sind nur 4 Prozessortakte bei 16Mhz.
Schon richtig. Wollte nur darauf hinweisen, dass man nicht unbedingt eine ganze Sekunde braucht, um den Unterschied zwischen 2000 Hz und 2001 Hz zu erkennen