aus ansteigenden Werten eine halbe Sinuswelle generieren - Arduino

#5495324
Lesenswert?

Hallo

Warum kann ich, oder die ArduinoIDE, keine Welle machen ;-)
j läuft von 0-33 immer wieder hoch und ich hätte gerne halbe (positive) 
Sinuswellen über die Schleife:

Die map() Funktion kann wohl nur mit ganzen Zahlen rechnen,
aber ich kann es auch nicht nachträglich erzwingen:

    float tick = sin(map(j, 0, 33, 0, 3141)/1000);

gibt nur das aus:

0 0.00
...
10 0.00
11 0.84
...
21 0.84
22 0.91
...
31 0.91
32 0.14
33 0.14
Gast #5495344
Lesenswert?

Kolja L. schrieb:
> Die map() Funktion kann wohl nur mit ganzen Zahlen rechnen,
> aber ich kann es auch nicht nachträglich erzwingen:
>
>     float tick = sin(map(j, 0, 33, 0, 3141)/1000);
>
> gibt nur das aus:
>
> 0 0.00
> ...
> 10 0.00

Und was gefällt dir daran nicht?
Was erwartest du?

map() ist in Arduino als long deklariert, d.h. liefert nur ganze Zahlen.
https://www.arduino.cc/reference/en/language/functions/math/map/

Durch 1000 dividiert bekommst du also auch ganze Zahlen, d.h. es können 
die Werte 0,1,2 oder 3 auftreten. Für die sin()-Berechnung werden die 
automatisch in float gekastet und die Funktion liefert dir genau die 
Werte 0.84, 0.91, 0.14 oder 0.00
Der Rechner macht genau das, was du ihm gesagt hast ;-)
#5495361
Lesenswert?

@Kolja L. (kolja82)

>Warum kann ich, oder die ArduinoIDE, keine Welle machen ;-)

Du kannst es nicht.

>j läuft von 0-33 immer wieder hoch und ich hätte gerne halbe (positive)
>Sinuswellen über die Schleife:

Und warum nimmst du dafür nicht wie jeder einfac die Sinusfunktion mit 
passender Skalierung?

>Die map() Funktion kann wohl nur mit ganzen Zahlen rechnen,

Die ist was für Knalltüten, die nicht mal 7. Klassemathematik 
beherrschen.

float tick = sin(3.1415/33*j);

Der Parameter von Sinus ist ein Winkel im Bogenmaß, 0-2Pi. Du willst nur 
bis Pi rechnen (halber Sinus), also muss man bei j=33 auf Pi kommen.
Gast #5495392
Lesenswert?

An dieser Stelle würde allerdings nicht die Rechenintensive Sinus 
Funktion benutzen, sondern eine Übersetzungstabelle, die ich vorher mit 
einer Tabellenkalkulation erstellt habe.
1
float sinus_tabelle[]={0.098, 0.195, ... };
2
float sinus=sinus_tabelle[j];

Um RAM zu sparen, könnte man diese Tabelle im Flash Speicher halten (mit 
PROGMEM).

Auch würde ich vermeiden, das Ergebnis als Fließkommazahl weiter zu 
verarbeiten. Am Ende wirst du sehr wahrscheinlich etwas digitales 
steuern, was Boolean oder Integer benötigt.

Ein PWM Ausgang braucht zum Beispiel 8bit Werte zwischen 0 und 255, 
nicht Float zwischen 0 und 1. Das kannst du bereits in der 
Übersetzungstabelle berücksichtigen.
Angehängte Dateien:
Gast #5522911
Lesenswert?

#include <math.h>
unsigned char fe[32];
int i;

void setup() {
  Serial.begin(9600);
  // Tabelle aufstellen
  for (i = 0; i < 32; i++)
    fe[i] = 127 + 127 * sin( i / 32.0 * 3.1415 );


  // Tabelle ausgeben
  for (i = 0; i < 32; i++ )
    Serial.println((int)fe[i]);
}

void loop() {
}
Gast #5523521
Lesenswert?

Oder on-the-fly ausrechnen:
1
uint8_t sine_wave[ 256]; 
2

3
void calculate_sine( void)
4
{
5
    int16_t x = 0;
6
    int16_t y = 8180;
7
    for( int i = 0; i < 256; i++)
8
    {
9
        x = x + ( y * 4) / 163;
10
        y = y - ( x * 4) / 163;
11
        sine_wave[i] = 128 + ( x >> 6);
12
    }
13
}
Gast #5527227
Lesenswert?

max123 schrieb:
> danke für das Programm und bitte um eine Programmerklärung.
Ich habe die Funktion ursprünglich hier gefunden:
http://www.technoblogy.com/show?22HF

Dort wird sie als "Minsky circle algorithm" beschrieben.

Für mich sieht es nach einem "Equi-amplitude staggered update 
oscillator" aus.
Ein bischen Theorie dazu ist u.a. hier zu finden:
http://www.usbsoundcard.com/images/pdfs/digital_resonators.pdf

Immerhin mit dem Verweis, das das grundlegende Verfahren schon 1572 von 
François Viète beschrieben und genutzt wurde...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren