www.mikrocontroller.net

Forum: PC-Programmierung 1100hz signal über 500 ms erzeugen


Autor: Karsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi an alle,

wie kann ich unter C/C++ ein Sinusignal mit 1100Hz erzeugen über eine 
Länge von 500ms. Dieses soll so erzeugt werden das ich es blockweise in 
30ms Blöcken rausziehen kann. Hierfür würde ich den STL - Vector nutzen 
wollen.
Das Signal muss als 16bit Signal also short erzeugt werden.

Mein momentaner Versuch klappt leider nicht so ganz...es kommt kein 
sauberes Signal heraus.

Hier mal mein Code.
double dCosFreq = cos(2*M_PI*m_dFreq/m_nSampleRate); //SampleRate ist 8000hz und m_dFreq meine 1100Hz
double dCosFreq2 = 2 * dCosFreq;
double dCosFreq2A = cos(2*(2*M_PI*m_dFreq/m_nSampleRate));
double dSinFreq = sin(2*M_PI*m_dFreq/m_nSampleRate);
for(int x = 0; x < m_nNumSamples; x++) //m_nNumSamples ist Samplerate/500ms ergibt also die Anzahl der benötigten 30ms Blöcke
{
   for(int i = 0; i < m_nFrameSize; i++)
   {
      if(i > 1)
      {
         m_pBuffer[i] =  static_cast<short>(16383*(dCosFreq2 * m_pBuffer[i-1] - m_pBuffer[i-2]));
      }
      else if (i > 0)
      {
         m_pBuffer[i] =  static_cast<short>(16383*(dCosFreq2 * m_pBuffer[i-1] - dCosFreq));
      }
      else
      {
         m_pBuffer[i] =  static_cast<short>(16383*(dCosFreq2 * dCosFreq - dCosFreq2A));
      }
   }
   m_pSampleArray.push_back(m_pBuffer);
}

Ich mach sicher alles falsch:D

Gruß
Karsten

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karsten schrieb:

> Mein momentaner Versuch klappt leider nicht so ganz...es kommt kein
> sauberes Signal heraus.

Wie gibst du denn das Signal aus?
Dort wird eher das Problem liegen und nicht bei der Generierung.

>    m_pSampleArray.push_back(m_pBuffer);

Den vector hast du bei der Initialisierung schon auf die zu erwartende 
Größe gebracht?

Autor: Karsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Wie gibst du denn das Signal aus?

Das Signal wird nochmal in µLaw umgewandelt und dann übers Netz Versand.

Karl heinz Buchegger schrieb:
> Den vector hast du bei der Initialisierung schon auf die zu erwartende
> Größe gebracht?

Nein der stl::vector ist da doch dynamisch.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karsten schrieb:
> Hi an alle,
>
> wie kann ich unter C/C++

C oder C++? "C/C++" gibt es nicht.

> ein Sinusignal mit 1100Hz erzeugen über eine Länge von 500ms. Dieses
> soll so erzeugt werden das ich es blockweise in 30ms Blöcken rausziehen
> kann. Hierfür würde ich den STL - Vector nutzen wollen.

Also C++.

> //m_nNumSamples ist Samplerate/500ms ergibt also die Anzahl der
> benötigten 30ms Blöck

Die Rechnung verstehe ich nicht. Die Anzahl der Blöcke ergibt sich aus 
500ms/30ms.

Übrigens: Wo wird da dein eigentlicher Sinus berechnet? Innerhalb der 
Schleife wird nirgends eine Sinus-Funktion aufgerufen. Stattdessen 
nimmst du zum Berechnen eines Wertes immer den letzten Wert, 
multiplizierst ihn mit ca. 1,3 und ziehst dann den vorletzten Wert davon 
ab.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karsten schrieb:
> Karl heinz Buchegger schrieb:
>> Wie gibst du denn das Signal aus?
>
> Das Signal wird nochmal in µLaw umgewandelt und dann übers Netz Versand.

Vielleicht hab ich dich auch misverstanden.
Was genau meinst du mit
"es kommt kein sauberes Signal heraus."


> Nein der stl::vector ist da doch dynamisch.

Mein Fehler. Du stopfst ja sowieso das Feld als ganzes in den vector 
rein (wozu eigentlich das zusätzliche Feld? mach doch vor den Schleifen 
den vector gleich um die richtige Anzahl größer und schreib die Werte 
gleich bei der Berechnung gleich in den vector)


Deine Berechnung .... sieht eigenartig aus.

Autor: Karsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus schrieb:
> Die Rechnung verstehe ich nicht. Die Anzahl der Blöcke ergibt sich aus
>
> 500ms/30ms.

Hehe...da hast du recht...falsch gedacht.

Rolf Magnus schrieb:
> Wo wird da dein eigentlicher Sinus berechnet?

Stimmt...gute Frage???:D

Karl heinz Buchegger schrieb:
> wozu eigentlich das zusätzliche Feld?

So kann ich am Ende den Vector blockweise auslesen und brauch nur immer 
nen offset mit übergeben wenn ich den nächsten Block brauche.

Karl heinz Buchegger schrieb:
> Deine Berechnung .... sieht eigenartig aus

Inwieweit eigenartig?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karsten schrieb:

> Karl heinz Buchegger schrieb:
>> wozu eigentlich das zusätzliche Feld?
>
> So kann ich am Ende den Vector blockweise auslesen und brauch nur immer
> nen offset mit übergeben wenn ich den nächsten Block brauche.

Vergiss es.
Ohne Datentypen muss man raten und ich hab offenbar falsch geraten.


> Karl heinz Buchegger schrieb:
>> Deine Berechnung .... sieht eigenartig aus
>
> Inwieweit eigenartig?

Weil ich innerhalb der Schleife einen Sinus erwartet hätte.

Wenn ich eine Tabelle erstellen will, in der alle Quadrate der Zahlen 
von 0 bis 100 enthalten sind, dann habe ich

     for( i = 0; i < 100; ++i )
       tabelle[i] = i * i;

das Quadrat kommt in der Schleife vor

Will ich eine Tabelle aller Wurzeln von 0 bis 100

     for( i = 0; i < 100; ++i )
       tabelle[i] = sqrt( i );

die Wurzel kommt innerhalb der Schleife vor

Will ich eine Tabelle aller Sinuswerte von 0 bis 100

     for( i = 0; i < 100; ++i )
       tabelle[i] = sin( i );

logischerweise kommt dann der Sinus in der Tabelle vor. Und das sehe ich 
bei dir nicht. Gut, die 100 muss man jetzt natürlich so anpassen, dass 
sich beim Abspielen dieses Samples in einer bestimmten Zeit die 
gewünschte Freuenz ergibt. Aber nichts desto trotz hätte ich da einen 
sin innerhalb der Schleife erwartet.

OK. Jetzt gibt es natürlich bei Quadraten und Wurzeln die Möglichkeit, 
dass man sich den unmittelbar nächsten Wert mit dem vorhergehenden 
berechnen kann und so nicht durch die Quadrat/Wurzelberechnung durch 
muss. Vielleicht hast du ja auch so etwas für einen Sinus gefunden, 
daher hab ich eigenartig gesagt und nicht falsch. Denn irgendwas 
berechnest du mit dem jeweiligen Vorgängerwert. Nur was?

Autor: Karsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> logischerweise kommt dann der Sinus in der Tabelle vor. Und das sehe ich
>
> bei dir nicht.

Ja da hast du vollkommen recht...da hab ich irgendwie nen ganz groben 
Denkfehler weiß aber gerade nicht wie ich den Sinus da jetzt korrekt 
unterbringe???

Aber die Berechnungen mit dem Cosinus sind doch soweit erstmal richtig 
oder?
Ich beschäftige mich noch nicht so lange mit dem Thema.
Wie würde man das denn normalerweise machen?


Ich komm gerad irgendwie nicht drauf???

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karsten schrieb:

> Denkfehler weiß aber gerade nicht wie ich den Sinus da jetzt korrekt
> unterbringe???

Das allgemeine Schema hab ich dir ja schon aufgezeigt.

> Aber die Berechnungen mit dem Cosinus sind doch soweit erstmal richtig
> oder?

Das kann ich nicht sagen, weil die noch unverständlicher sind.

> Ich beschäftige mich noch nicht so lange mit dem Thema.
> Wie würde man das denn normalerweise machen?
>
>
> Ich komm gerad irgendwie nicht drauf???

Dann solltest du darüber mal nachdenken.

WEnn du eine Tabelle haben willst, die 100 Einträge hat und in der eine 
komplette Sinusschwingung 1 mal darin enthalten ist, wie machst du das?

Du rechnest dir aus, um wieviel der Winkel (von dem du den Sinus nehmen 
wirst) von einem Schritt zum nächsten zunehmen muss, sodass der Winkel 
in 100 Schritten einen Vollkreis (=360 Grad) überstreicht.

Das Winkelinkrement ist daher   2*PI / 100

Eine Schleife

     winkel = 0.0;
     inkrement = 2*PI / 100;

     for( i = 0; i < 100; ++i ) {
       tabelle[i] = sin( winkel );
       winkel += inkrement;
     }

erzeugt daher eine Tabelle mit 100 Werten, wobei das die Werte 1 
Sinusschwingung sind.

Sollen in denselben 100 Werten 2 komplette Schwingungen untergebracht 
werden, dann muss der gedankliche Winkel nicht von 0 bis 360 Grad 
verändert werden, sondern von 0 bis 720 Grad. Denn 720 Grad sind 2 
Umdrehungen.

     winkel = 0.0;
     inkrement = 2 * 2*PI / 100;

     for( i = 0; i < 100; ++i ) {
       tabelle[i] = sin( winkel );
       winkel += inkrement;
     }

Bei der berechnung des Inkrements wird also die Anzahl der zu 
erzeugenden Schwingungen eingehen.

Das andere was variiert werden kann ist natürlich die Tabellenlänge. 
Wenn die Tabelle nicht 100 Einträge sondern 500 umfassen soll, dann wird 
sich das
 * bei der Berechnung des Inkrements
 * in der Steuerung der for-Schleife bemerkbar machen

Inkrement ist auch klar. Wenn ich 500 Meter zurücklegen soll und dafür 
300 Schritte machen darf, dann kann ich kleinere Schritte machen als 
jemand der dieselbe Strecke mit nur 100 Schritten zurücklegen soll.


Vielleicht solltest du auch erst mal mit ein paar Testprogrammen 
anfangen und dir die erzeugten Werte erst mal auf dem Monitor per printf 
ausgeben lassen. Müssen ja nicht gleich 1100 Herz und eine Tabellenlänge 
von 8000 Samples sein. Mit kleineren Werten sieht man das auch schon 
sehr gut und man erkennt auch gleich viel besser wie die mathematischen 
Zusammenhänge sind.
Was gerade bei Schwingungen immer sehr gut kommt, ist wenn man sich die 
Werte dergestalt ausgibt, dass der Wert in eine Anzahl Leerzeichen 
übersetzt wird und dahinter dann ein *.
Dann sieht man nämlich auch auf dem Monitor sehr schön, wie sich der 
Sinus in den Daten abbildet ohne dass man lange auf Zahlen starren muss


                               *
                                      *
                                          *
                                            *
                                          *
                                      *
                               *
                        *
                     *
                   *
                     *
                        *
                               *


Das wäre 1 Sinusschwingung, umgesetzt in einer Tabelle mit 13 Einträgen

(Macht man heutzutage eigentlich keine Experimente mehr? Als 
Programmierneuling haben wir Stunden damit verbracht, solche Kurven zu 
generieren. Verschiedene Kurvenformen, Achsen, Achsbeschriftungen .... 
alles nur mit printf und zeilenweiser Ausgabe)

Autor: mano (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich würde es so schreiben

#define COUNT_MAX 2000

double f = 1100;       // Freq. vom Sinus
double fs = 4000;      // Abtastfreq.
double Ts = 1/fs;
double amp = 1.0;     // Verstärkung

double sinusPoints[COUNT_MAX];

for(int i = 0; i < COUNT_MAX; ++i) {
    sinusPoints[i] = amp * sin(2*pi*f*i*Ts);
}


Autor: Karsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Vielleicht solltest du auch erst mal mit ein paar Testprogrammen
>
> anfangen und dir die erzeugten Werte erst mal auf dem Monitor per printf
>
> ausgeben lassen. Müssen ja nicht gleich 1100 Herz und eine Tabellenlänge
>
> von 8000 Samples sein. Mit kleineren Werten sieht man das auch schon
>
> sehr gut und man erkennt auch gleich viel besser wie die mathematischen
>
> Zusammenhänge sind.

Da werd ich mich am WE mal genauer mit beschäftigen...danke für die 
unterstützenden Hilfen.

Dank auch mano.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.