Seite 1 von 1

Hilfe bei Datentyp Formatierung

Verfasst: Freitag 27. November 2015, 11:56
von DerIng
Hallo allerseits,

vor einiger Zeit hatte ich in diesem Beitrag : viewtopic.php?f=1&t=37503 meinen Sachverhalt erwähnt. Dank einer schnellen Hilfe von einem Forummitglied konnte ich das Problem lösen.
Nun stehe ich vor einer neuen Herausforderung. Das Sägezahsignal, das ich erzeuge schicke ich über die Soundkarte raus und nehme es simultan wieder auf. Soweit alles gut!
Ich soll das empfangene Signal an die UDP schnittstelle schicken und mit Matlab die Schnittstelle lauschen, ob daten vorhanden sind. Dies habe ich auch schon implementiert und die Kommunikation zwischen Python und Matlab aufgebaut. Jedoch entspricht das Signal, was ich sende nicht dem, was ich in Matlab empfange.
Durch einige Tests habe ich festgestellt, dass es an dem Datentyp liegt. Denn das Sägezahnsignal, was aufgenommen wird, ist als 2 byte - character abgespeichert. Wie schaffe ich es die Daten an die UDP Schnittstelle zu schicken, sodass ich in Matlab wieder das richtige Signal auswerten kann?
Hier die Funktionen, die für den Sachverhalt relevant sind:

Code: Alles auswählen

def make_sawtooth(f0=100,A=1,fs=96000):
  n=int(fs/f0)
  wav=''

  for i in range(0,n):
    Saw=int(A*signal.sawtooth(-i*2*np.pi*f0/fs))
    #print "Sawtooth:", Saw
    wav +=chr(Saw & 0xFF) + chr((Saw & 0xFF00) >> 8)
  return wav
  #plt.plot(Saw)
  #plt.show() 

def play_audio(forHowLong):

    data= make_sawtooth(f0=200,A=600,fs=96000)
    #data2= sin_wave(f0=400,A=600,fs=96000)


    p = pyaudio.PyAudio() #sets up portaudio system
    stream = p.open(format=p.get_format_from_width(2),
                channels=1,
                rate=96000,
                output=True)


    start = time.time()
    while time.time() < start + forHowLong:
            stream.write(data)

    stream.stop_stream()
    stream.close()
    p.terminate()


def record_audio(forHowLong):
    NUM_SAMPLES = 512
    FORMAT = pyaudio.get_format_from_width(2)
    CHANNELS = 1
    RATE = 96000
    RECORD_SECONDS = forHowLong
    WAVE_OUTPUT_FILENAME = "output.wav"
    UDP_IP ="129.69.32.192"
    UDP_PORT=5005

    p = pyaudio.PyAudio()

    stream = p.open(format=FORMAT,
            channels=CHANNELS,
            rate=RATE,
            input=True,
            frames_per_buffer=NUM_SAMPLES)

    print("* recording")

    r= array('c')
    frames = []
    start = time.time()
    while time.time()  < start + forHowLong:
            data=array('c',stream.read(NUM_SAMPLES))
            if byteorder == 'big':
                   data=byteswap()
            r.extend(data)

           # frames.append(data)


    print("* done recording")

    stream.stop_stream()
    stream.close()
    p.terminate()

    print "Datalength:",len(data)

    sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    try:
        sock.connect((UDP_IP,UDP_PORT))

    except:
        print "Connection failed"

    sock.send(value)


    wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(r))
    wf.close()
    print "UDP target IP:", UDP_IP
    print "UDP target port:", UDP_PORT
Hinweis: Nur durch die Amplitude von A= 600 erreiche kann ich in Matlab ein Sägezahnsignal von -1 bis 1 plotten.

Für Unterstützungen, Ideen danke ich schon im Voraus.

Viele Grüße
DerIng

Re: Hilfe bei Datentyp Formatierung

Verfasst: Freitag 27. November 2015, 12:28
von BlackJack
@DerIng: Das Senden an einen UPD-Port solltest Du nicht mit in die Aufnahmefunktion stecken. Eine Funktion sollte eine begrenzte Aufgabe erfüllen. Zum Beispiel damit man diese Aufgabe auch separat testen kann. In diesem Fall zum Beispiel das senden von Daten ohne die tatsächlich per Hardware aufnehmen zu müssen, was ja auch impliziert das man das was da aufgenommen wird, jedes mal erzeugen muss. Das Senden von vorbereiteten Testdaten macht wesentlich weniger Aufwand und man kann sich sicher sein das Probleme in den Daten weder durch das Abspielen noch durch das Aufnehmen entstanden sind.

Die Funktion tut so nicht. Du versucht einen Wert `value` zu verwenden der nicht definiert ist. `byteorder` ist ebenfalls nicht definiert. Wäre es an den Wert 'big' gebunden, dann würde `byteswap()` den nächsten `NameError` auslösen. `frames` wird definiert, aber dann nirgends benutzt. Genau wie `RECORD_SECONDS`, was zusätzlich noch verwirrend ist wegen der Schreibweise weil durchgehend Grossbuchstaben per Konvention eine Konstante bedeuten und deren Definition erwartet man auf Modulebene oder als Klassenattribut, aber nicht in Funktionen.

Zum `array`-Datentyp wäre die Information dass es sich um den aus dem `array`-Modul in der Standardbibliothek handelt nützlich gewesen, weil Du ja auch `scipy.signal` verwendest, und da würde der `array`-Datentyp aus dem Numpy-Package näherliegen.

Falls Matlab eine andere Bytereihenfolge erwartet dann müsstest Du die `byteswap()`-Methode *auf* dem `array.array`-Objekt aufrufen. Das verändert dann die Daten *in* dem Objekt. Allerdings auch nur wenn dessen Elemente einen Datentyp haben bei denen Bytes vertauscht werden können. Das geht bei einzelnen Bytes schlecht. Wenn Du also 16-Bit-Werte aufnimmst, dann sollte der Typcode, also das erste Argument von `array()` auch einen 16-Bit-Wert beschreiben. Das müsste dann wohl 'h' oder 'H' sein, je nachdem ob Vorzeichenbehaftet oder nicht. Die Dokumentation sollte aufklären.

UDP ist paketorientiert und nicht verbindungsorientiert, ein `connect()` ist also falsch, genau wie `send()` weil das keine Angabe dies Ziels erlaubt. In der Dokumentation zum `socket`-Modul sollten eigentlich Beispiele sein.

Ich weis nicht ob schon mal jemand den Style Guide for Python Code erwähnt hat…

Re: Hilfe bei Datentyp Formatierung

Verfasst: Freitag 27. November 2015, 17:22
von snafu
@DerIng
Bezüglich `socket`: Lass bei Verwendung des UDP-Protokolls das `connect()` weg und verwende `sendto()` mit den entsprechenden Angaben anstelle von `send()`. UDP kennt keine Verbindungen. Man sendet stattdessen die Pakete einzeln an das gewünschte Ziel und "hofft" auf deren erfolgreiche Zustellung.