kramann.info
© Guido Kramann

Login: Passwort:










COACH2
1 Planung
2 Architektur
3 Anzeige
4 EEPROM
5 I2C
..5.1 MasterSendByte
..5.2 MasterSend2Bytes
..5.3 MasterReceiveByte
..5.4 MasterReceive2Bytes
6 UART
7 DFT
8 FFT
9 Planung2
10 Klassen
..10.1 AnzeigeTaster
..10.2 RS232
..10.3 MotorServo
..10.4 Drehgeber
..10.5 Sensor
..10.6 Funk
11 Adaption
..11.1 Programmiertechnik
..11.2 Evoopt
12 Fuzzy
..12.1 Uebungsaufgabe
..12.2 Fuzzygroesse
..12.3 Fuzzyset
..12.4 Lookuptable
13 Skript
..13.1 Funkkorrektur
..13.2 Skriptsprachen
..13.3 Anforderungen
..13.4 Agentensysteme
..13.5 Implementierung
..13.6 Experimente
14 Gesamtkonzept
..14.1 Skripterweiterung
..14.2 Makroverhalten
67 Echtzeitsysteme
..67.1 Einfuehrung
....67.1.1 Echtzeit
....67.1.2 Korrektheit
....67.1.3 Hardware
....67.1.4 Ziele
....67.1.5 Synchronprogramm
..67.2 Threads
....67.2.1 Java
....67.2.2 Synchronisierung
..67.3 COACH
....67.3.1 Kaskadenregler
....67.3.2 Zeitebene1
....67.3.3 Zeitebene2
....67.3.4 Zeitebene3
....67.3.5 Puck
....67.3.6 Puckschwarm
..67.4 RTAIlab
....67.4.1 Slax
....67.4.1 USB_Stick
....67.4.2 Sinus
..67.5 Semaphor
....67.5.1 Laufkatze
....67.5.2 Java
....67.5.3 Semaphor
..67.6 Audio
....67.6.1 wav
....67.6.2 Linux
..67.7 Lookup
....67.7.1 Fuzzy
....67.7.2 PWM
..67.8 NeuronaleNetze
....67.8.1 Neuron
....67.8.2 Backpropagation
....67.8.3 Umsetzung
....67.8.4 Winkelerkennung
..67.9 Internetprogrammierung
....67.9.1 Codegenerierung
....67.9.2 PHP_Programmierung
....67.9.3 PHP_OOP
....67.9.4 Java
....67.9.5 UDP
..67.10 DFT
..67.11 FFT
..67.12 Zustandsmaschine
..67.13 Fuzzy
....67.13.1 Fuzzylogik
....67.13.2 FuzzyRegler
....67.13.3 Uebung9
....67.13.5 Softwareentwicklung
......67.13.5.1 AgileSoftwareentwicklung
......67.13.5.2 FuzzyRegler
......67.13.5.3 Uebung
....67.13.6 Umsetzung
......67.13.6.1 FuzzyRegler
......67.13.6.2 Simulation
......67.13.6.3 Optimierung
......67.13.6.4 Uebung
....67.13.7 Haengependel
......67.13.7.1 Haengependel
......67.13.7.2 Simulation
......67.13.7.3 FuzzyRegler
......67.13.7.4 Optimierer
......67.13.7.5 Genetisch
....67.13.8 Information
....67.13.9 Energie

67.6.1 Erzeugen und Verarbeiten von .wav-Dateien in C/C++

  • Das .wav-Audio-Format ist ein nicht komprimierendes Speicherformat für Audiodateien.
  • Es ist möglich .wav-Dateien als Array in ein Scilab/C/C++/Java - Programm zu laden, oder umgekehrt die Daten für eine .wav-Datei zu generieren und dann zu speichern.

Eigenschaften der .wav-Dateien

  • Die ersten 44 Byte sind Header und enthalten Informationen über Samplingrate, Bitauflösung, Anzahl der Kanäle (Mono/Stereo) und die Anzahl der Bytes sowohl mit (restlichem), als auch ohne Haeder.
  • Direkt hinter dem Header folgen die unkomprimierten Datenbytes.
  • Bei einer Bitauflösung von 16Bit und einem Stereosignal folgen für jeden Samplingschritt 4 Byte:
  • Byte0: Niederwertiges Byte des rechten Kanals
  • Byte1: Höherwertiges Byte des rechten Kanals
  • Byte2: Niederwertiges Byte des rechten Kanals
  • Byte3: Höherwertiges Byte des rechten Kanals

Scilab - Verwenden von .wav-Dateien in Scilab

  • Das folgende Programm erzeugt zunächst eine Sinusschwingung von 220Hz und 660Hz (Quinte/2. Oberton zu 220Hz) in zwei Arrays.
  • Die Auflösung wird dabei so gewählt, dass sie einer Samplingrate von 44100Hz entspricht.
  • Die Amplitude darf dabei maximal +/-1 betragen und wird hier entsprechend kleiner gewählt.
  • Beide Arrays werden zu einem zusammengefügt und bilden dann ein Stereo-Signal.
  • Dieses wird abgespeichert und kann dann beispielsweise auch mit dem Multimediaplayer abgespielt werden.
  • Im Anschluß wird dieses File wieder in Scilab geladen.
  • Die Stereo-Kanäle werden zu einem Monosignal zusammengefaßt.
  • Vorbereitend auf eine Spektrumsanalyse wird ein Resampling durchgeführt.
  • D.h. die Samplerate wird auf 1/10 herabgesetzt, um den Umfang der zu transformierenden Daten zu reduzieren.
  • Da dann die Samplingrate immer noch bei 4410Hz liegt, können damit immer noch die beiden Tonsignale im Spektrum scharf getrennt werden.
//Stacksize erhöhen, wegen hohen Datenaufkommens:
stacksize(100000000);
//Sinustöne erzeugen und abspeichern:
fs=44100; //Samplingrate
f1=220; //Frequenz Tonsignal 1
f2=660; //Frequenz Tonsignal 2
y1=zeros(1,44100);
y2=zeros(1,44100);
t=0.0;
for i=1:44100
    y1(i) = 0.4*sin(2*%pi*f1*t);    
    y2(i) = 0.4*sin(2*%pi*f2*t);    
    t=t+(1/fs);
end
y = [y1;y2];
wavwrite(y,fs,'toene.wav');
//.wav-Datei laden und analysieren:
z = wavread('toene.wav');
mono = z(1,:)+z(2,:);
fs_neu = 4410;
t     = zeros(1,44100);
N     = 4410;
t_neu = zeros(1,N);
for i=1:44100
    t(i)=(i-1)*(1/fs);
end
for i=1:N
    t_neu(i)=(i-1)*(1/fs_neu);
end
mono_neu = interp1(t,mono,t_neu,'linear');
//plot(t_neu,mono_neu);
spektrum = abs(dft(mono_neu,-1));
//Bestimmung der Frequenzen in der Ordninate zum Spektrum (vergl. DFT in Vorlesung):
frequenzen = zeros(1,4410);
for i=1:N
    frequenzen(i) = ((i-1)*fs_neu)/N;
end
plot(frequenzen,spektrum);

Code 67.6.1-1: Verwenden von .wav-Dateien in Scilab

Plot des Spektrums

Bild 67.6.1-1: Plot des Spektrums

C/C++ - Verwenden von .wav-Dateien in C/C++

  • Die folgende Klasse "Ton" erlaubt es, .wav-Dateien zu laden und zu speichern.
  • Die Amplitude wird dabei auf einen double-Wert zwischen -1.0 und +1.0 umgesetzt.
  • Die Klasse ist darauf beschränkt, Stereo-.wav-Dateien mit einer Samplingrate von 44100Hz und 16Bit Bittiefe zu verarbeiten.
  • Anstatt alle Parameter des Headers neu zu schreiben, wird in einen vordefinierten Header lediglich die Filelänge an den beiden notwendigen Stellen hineingeschrieben.
  • Wavdateien speichern:
  • Zum Speichern einer .wav-Datei wird ein Objekt der Klasse Ton unter Angabe der Anzahl der Samples gebildet.
  • Mit den Methoden setLinks(long int i, double l) und setRechts(long int i, double l) können dann zunächst double-Werte in den dem linken bzw. rechten Kanal zugeordneten Array geschrieben werden.
  • Wenn die Audio-Datei vollständig ist, kann sie mit Hilfe der Methode speicher(string filename) abgespeichert werden.
  • Die Methode speicher(string filename) wird nun näher erläutert:
  • Mit folgendem Codeabschnitt wird die Anzahl der notwendigen Bytes bestimmt und in den Header eingetragen:
  • Dabei ist zu beachten, dass ab Index 4 des Headers auch der Rest des Headers als Bytezahl geschrieben werden muß.
  • An Index 40 des Headers (Array kopf) wird die eigentliche Bytezahl der Audiodatei geschrieben.
  • Diese entspricht der vierfachen Anzahl der Samples (Variable anzahl_aktuell).
  • Die Bytezahl wird als 4-Byte-unsigned-Integer-Zahl formatiert.
            z1 = anzahl_aktuell*4+36;
            z2 = anzahl_aktuell*4;
            //KOPF bilden
            for(int i=0;i<4;i++)
            {  
                zahl1[i] = z1%teiler;
                z1/=256;
                kopf[4+i] = zahl1[i];
            }
            for(int i=0;i<4;i++)
            {
                zahl2[i] = z2%teiler;
                z2/=256;
                kopf[40+i] = zahl2[i];
            }

Code 67.6.1-2: Header anpassen in Methode speicher(string filename) der Klasse Ton.

  • Um die Amplitudenwerte in ihre 16-Bit-Darstellung zu bringen, werden die Ausgangs-double-Werte zunächst in positive Integerzahlen umgerechnet (Variable gesamt).
  • Anschließend wird diese Zahl in ein niederwertiges und ein höherwertiges Byte aufgeteilt (Variablen hi und lo).
  • Schließlich müssen die so gewonnenen unsigned-character-Werte noch in signed character-Werte umgewandelt werden.
  • Diese Umrechnungen für den linken Kanal zeigt folgender Codeausschnitt:
                wert = links[i];
                gesamt = (int)(wert*gross + gross);    
                hi = gesamt/256;
                lo = gesamt - hi*256;
                zh = hi-128;
                if(lo<=127)
                    zl = lo;
                else        
                    zl = lo-256;                  
                file.put(zl);    
                file.put(zh);    

Code 67.6.1-3: Umwandlung von einer double-Zahl in ein 16-Bit-Wort und Abspeichern des Samples.

  • Wavdateien laden
  • Um eine Wavdatei zu laden wird der leere Konstruktor der Klasse Ton verwendet um ein Objekt zu erzeugen.
  • Bei Aufruf der Methode lade(string filename) passiert folgendes:
  • Aufgrund der Angaben im Header der zu ladenden .wav-Datei, wird die Sample-Anzahl gefunden (Variable anzahl_aktuell) und entsprechender Speicherplatz allokiert.
  • Für jedes Sample verläuft hier der Umrechnungsvorgang umgekehrt zum Speichervorgang:
                 zl = file.get();
                 zh = file.get();
                 if(zl>127)
                     zl-=256;
                 if(zh>127)
                     zh-=256;
                 lo     =  zl;
                 if(lo<0)
                     lo+=256;
                 gesamt = (zh+128)*256;
                 gesamt+=lo;
                 links[i] = ((double)gesamt - gross)/gross;        

Code 67.6.1-4: Umrechnung der 16-Bit-Worte in double-Werte beim Ladevorgang.

  • Das folgende Beispielprogramm erzeugt in den Objekten ton und ton3 jeweils Sinustöne der Frequenzen 441Hz, bzw. 882Hz.
  • Das ton-Objekt wird unter dem Namen "sinus2.wav" gespeichert, dann erneut in das Objekt ton2 geladen und wiederum unter "sinus3.wav" gespeichert.
#include<math.h>
#include<iostream>
#include<fstream>
using namespace std;
#include "Ton.h"
int main()
{
    long int anzahl_samples = 44100;
    Ton ton(anzahl_samples);
    Ton ton2(anzahl_samples);
    Ton ton3(anzahl_samples);
    double f1 = 441;
    double f2 = 882;
    double dt = 1.0/44100.0;
    double  t = 0.0;
    for(int i=0;i<anzahl_samples;i++)
    {
        ton.setLinks(i,0.0);
        ton.setRechts(i,0.0);
        t+=dt;
    }
    t = 0.0;
    for(int i=0;i<44100;i++)
    {
        ton.setLinks(i,0.9*sin(2.0*M_PI*f1*t));
        ton.setRechts(i,0.9*cos(2.0*M_PI*f2*t));
        ton3.setLinks(i,0.9*sin(2.0*M_PI*f1*t));
        ton3.setRechts(i,0.9*sin(2.0*M_PI*f1*t));
        t+=dt;
    }
    ton.speicher("sinus2.wav");   
    ton2.lade("sinus2.wav");   
    ton2.speicher("sinus3.wav");   
}

Code 67.6.1-5: Wavdateiverarbeitung in C/C++

wav_cpp.zip - Obiges C++ - Projekt.
wav_java.zip - Vergleichbare Realisierung in Java.