Hallo,

Ik had een heel tijdje geleden een ecg circuit gebouwd en registreerde het signaal toen zoals ik hier (http://www.circuitsonline.net/forum/view/114059/2) toen gezegd had (een ADC rechtstreeks uitlezen met de LPT-poort). Dit was geen ideale manier, maar het werkte wel en toen had ik al een programma gemaakt om het volledige 12 leads ecg op een blad te zetten en de hartslag, QRS-duur,.. te meten.

Nu heb ik mijn ecg schema aangesloten op mijn geluidskaard en het signaal opgenomen met audacity. Ik heb gemerkt dat het signaal wonderbaarlijk veel beter van kwaliteit wordt wanneer ik een low pass filter van 40 Hz gebruik.

Nu zou ik graag de wav-bestanden die ik opneem gebruiken in mijn programma dat ik al gemaakt had. Mijn programma had ik in visual basic gemaakt en hier sloeg ik de gegevens op in 2 array variabelen: één voor de tijd en één voor de amplitude:
Dim Itijd() As Single
Dim Ispanning() As Single
Nu zou ik in deze variabelen graag de waarden zetten die afkomstig zijn uit een wav-bestand.

Mijn vraag is dus eigenlijk:
Hoe kan ik in visual basic uit een wav-bestand de tijd en amplitude van elk meetpunt verkrijgen?

Met dank bij voorbaat,
Tom Bleeser

De structuur van een .wav-file kun je overal vinden; bijvoorbeeld hier:
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

Het tijdstip behorende bij een sample staat niet in de file. Maar omdat je het aantal samples per seconde weet, kun je dat tijdstip zelf uitrekenen.

Bedankt!

Ik lees de bestanden nu uit met
Dim Byt1() As Byte = IO.File.ReadAllBytes("c:\temp\ecg.wav")

Het lukt mij nu om bestanden met 8 bits per sample uit te lezen: deze hebben gewoon losse bytes van 0 tot 255 met 128 als nulpunt.

Bij bestanden met 16 bits per sample doe ik hetvolgende, maar dan bekom ik geen goede grafiek:


bytenummer            44   45   46   47   48   49   50   51
decimale uitlezing   117   2    218  1    70   2    27   2
hexadecimaal omgezet  75   2    DA   1    46   2    1B   2
samengevoegd hexa       275       1DA       246       21B
decimaal samen          629       474       582       539

Als ik een grafiek maak met de gegevens uit de laatste regel klopt dit niet.
Wat doe ik verkeerd?

Is het wel een gewone 'raw' PCM file?

Ja, dat is een PCM file. Is de methode die ik gebruik normaal juist?

Ik kan het nu even niet zo snel narekenen, maar het eerste dat in me opkwam: big-endian versus little-endian.

Niet helemaal 'RAW' natuurlijk; er zit immers een RIFF header voor. Maar die sloop je er af, dat ging bij de 8-bits data ook goed.

Je probeert niet toevallig een stereo-file uit te lezen? Dan is het steeds twee bytes links, dan twee bytes rechts, dan weer links, et cetera.
Als je een mono signaal als stereo opslaat, kan het zijn dat het 'andere' kanaal allemaal nullen bevat, maar sommige programma's schrijven dan gewoon L en R hetzelfde, zodat je alles twee keer ziet.
De oplossing is in beide gevallen hetzelfde: steeds twee overslaan. :)
Mocht je inderdaad een RIFX inplaats van een RIFF hebben, dan moet je lo en hi even omdraaien. Dus niet a + 256*b, maar 256*a + b.

e: Je weet toch dat de 16-bits data 2's complement is, hè? Alles wat meer dan 32767 lijkt, is eigenlijk negatief. Zo:


32768   -32768
32769   -32767
...        ...
65534       -2
65535       -1
    0        0
    1        1
...        ...
32766    32766
32767    32767

De 8 bits PCM data is inderdaad unsigned, de 16 bits is signed.

Net even geprobeerd met stereo testbestandje. Met een haastig geschreven basic programmaatje kan ik de twee golfjes plotten.
Het werkt zoals in de beschrijving: 44 bytes header, dan steeds twee bytes links, twee bytes rechts, enzovoorts; steeds eerst lo, dan hi; 2's complement.

Bedankt, ik had een mono-bestand, dus dat was niet het probleem, maar wel de 2's complement waar ik geen rekening mee gehouden had.

Ik heb het aangepast en nu heb ik al een grafiek die er op lijkt, maar nu staan er soms punten in de buurt van 0 die er niet horen te staan.

Hoe zou dat komen?

Mijn grafieken zien er nu zo uit:
https://www.dropbox.com/s/1wks80brolj7sir/Klembord01.jpg
https://www.dropbox.com/s/fz0oliudrqtu4sh/Klembord02.jpg

(bovenaan grafiek zoals in audacity, onderaan die van in mijn programma)

Hoe zou ik die horizontale puntenlijn weg kunnen krijgen?

Nu gebruik ik volgende code:

(De array Byt1 bevat de bytes uit het wav bestand)


For teller = 0 To aantalsamples * 2 - 1
    tijd(teller / 2) = (teller / 2) * (1 / samplefreq)
    samengezetdecimaal = (Convert.ToInt32(Hex(Byt1(teller + 45)) & Hex(Byt1(teller + 44)), 16))
    If samengezetdecimaal > 32767 Then
       spanning(teller / 2) = -(65536 - samengezetdecimaal)
    Else
       spanning(teller / 2) = samengezetdecimaal
    End If
       teller = teller + 1
Next

[Bericht gewijzigd door Henry S. op (58%)]

Gebruik je wel integers? Want dit lijkt op afrondfouten. Bovendien lijkt mij de berekening van een 16-bits getal uit twee unsigned decimals een beetje omslachtig, waarom niet gewoon

C = a * 256 + b ?

Hoe zou ik die horizontale puntenlijn weg kunnen krijgen?

Lijkt op Buffer over/under runs .. een bekend fenomeen als de buffersize niet klopt.

Beetje opschonen, alle keer 2, /2 kan weg en breuk omdraaien voor foutcorrectie!

De teller ophogen binnen de for lus is not done, gebruik dan op zijn minst de 'step' parameter van for (juck!)

Is er trouwens niet gewoon een functie (call, whatever, ken de taal niet) waarbij je in één keer een signed integer inleest uit de file?

het probleem zit hem hier:

Hex(Byt1(teller + 44)

Ik denk dat Byt1 je data uit de file is. door er een hexadecimaal getal van te maken, kun je deze inderdaad samenvoegen.

die spikes komen doordat je de binaire waarde omzet naar een ascii string, die concat en dan terugconvert naar int. de functie hex geeft meestal 2 karakters, maar niet altijd.
http://msdn.microsoft.com/en-us/library/963zt96e(v=vs.90).aspx

Dim TestHex As String 
' Returns 5.
TestHex = Hex(5)
' Returns A.
TestHex = Hex(10)
' Returns 1CB.
TestHex = Hex(459)

de beste methode is natuurlijk die van Rob:

Op 3 februari 2014 09:11:53 schreef RobvdVeer:
C = a * 256 + b ?

http://msdn.microsoft.com/en-us/library/zew1e4wc(v=vs.90).aspx
door de ASC functie te gebruiken kun je binaire waarde van de byte als getal gebruiken. daarna kun je die vermenigvuldigen (eigenlijk 8 plaatsen shiften) en optellen.

in jouw geval krijg je bijv voor de 2 samplewaarden 19215 en 19216
19215=4B0F (opgeslagen als 15,75)
19216=4B10 (opgeslagen als 16,75)


samengezetdecimaal = (Convert.ToInt32(hex(75)&hex(15), 16))
samengezetdecimaal = (Convert.ToInt32(hex(75)&hex(16), 16))
wordt:

samengezetdecimaal = (Convert.ToInt32("4B"&"F", 16))
samengezetdecimaal = (Convert.ToInt32("4B"&"10", 16))

4BA =1215
4B10=19216
4BA =1215
4B10=19216

Ik denk dat hier het probleem ook zit. Je mist de voorloopnul.

4B0A

het probleem is niet de voorloopnul, dat is het gevolg van de verkeerde methode.

natuurlijk is het makkelijk om bytes als hexadecimale karakters te concatten, maar het is veel beter om de bytes te shiften en als getallen te behandelen.

Bedankt!!!

Nu werkt het!

Ik heb het nu zo gedaan:


For teller = 0 To aantalsamples * 2 - 2
   tijd(teller / 2) = (teller / 2) * (1 / samplefreq)
   samengezetdecimaal = Byt1(teller + 45) * 256 + Byt1(teller + 44)
   If samengezetdecimaal > 32767 Then
      spanning(teller / 2) = -(65536 - samengezetdecimaal)
   Else
      spanning(teller / 2) = samengezetdecimaal
   End If
   teller = teller + 1
Next

Op 3 februari 2014 20:13:55 schreef Progger:
het probleem is niet de voorloopnul, dat is het gevolg van de verkeerde methode.

natuurlijk is het makkelijk om bytes als hexadecimale karakters te concatten, maar het is veel beter om de bytes te shiften en als getallen te behandelen.

Er is een verschil tussen foute code, en code die beter kan. De voorloopnul missen is een fout met incorrect resultaat tot gevolg, de *256 is een "verbetering" (improvement).

Overigens vind ik "bytes als hex (...) concatten" persoonlijk niet vallen onder de categorie 'eenvoudig', maar dat is mijn persoonlijke mening. Fout is fout, en goed kan beter, maar is nooit fout.