ASCII to EDF format

834 views
Skip to first unread message

Gianluca Moro

unread,
Nov 4, 2011, 7:48:00 AM11/4/11
to medic...@googlegroups.com
hi all,

here a simple tool to convert and ASCII data set to EDF format
(see the comments in the code for the format).

Application:
- suppose to have a device for EEG, such as Emotiv Epoc.
- get the raw data in some way (Research edition version,
Emokit hack ...)
- write them to ASCII file in the described format
- pipe to this utility to get an EDF file format

Tested with Emotiv Epoc -> (acquisition) -> a2edf -> EDFbrowser.

Hope this helps
bye
giammy

/*

Copyright 2011 Gianluca Moro - giang...@gmai.com - www.giammy.com

This file is a2edf utility.

a2edf is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your
option) any later version.

a2edf is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Foobar. If not, see http://www.gnu.org/licenses/.

*/

/*
An ASCII to EDF format converter

./a2edf <in >out.edf

THIS IS AN IMPLEMENTATION TO TEST THE FORMAT CONVERSION
AND THE EDF SPECIFICATION.
TO BE USED IN REAL APPLICATION THE SOURCE MUST BE MODIFIED!

The input file is an ASCII file, each line is a sequence of
17 integers, space separated representing the following type
of data:
Freq giroX giroY F3 FC6 P7 T8 F7 F8 T7 P8 AF4 F4 AF3 O2 O1 FC5
where Freq is the audio frequency emitted in that instant,
giroX and giroY are a giroscope input and the others are EEG sensors.

The header is built ad hoc, all the fields should be setted runtime,
in particular the
printf("%-8s", "324"); // TODO DATA number of data record
(see the note below)

References:

@article{
Kemp_Värri_Rosa_Nielsen_Gade_1992,
title={A simple format for exchange of digitized polygraphic recordings.},
volume={82},
url={http://linkinghub.elsevier.com/retrieve/pii/0013469492900097},
number={5},
journal={Electroencephalography and Clinical Neurophysiology},
author={Kemp, B and Värri, A and Rosa, A C and Nielsen, K D and Gade, J},
year={1992},
pages={391--393}}


*** Note ***
The implementation has been checked with EDFbrowser
http://www.teuniz.net/edfbrowser/ but the field
"number of data record" accordingly to the paper
could be -1 (in my interpretation: read as many data
record as you find in the file), while EDFbrowser want
a real number of data record.

For the date/time format, the paper writes:
"startdate of recordlng (dd mn yy)" i.e. dd,mm and yy are
space separated, while EDFbrowser wants them point separated.

*/

#include <stdio.h>
#include <stdlib.h>

#define LINE_SIZE 256

#define NCH 17
#define NSECPERRECORD 1
#define FREQ 128

short dataRecord[NCH][NSECPERRECORD*FREQ];
int currentDataRecordSamples = 0;

#define LO(x) ((unsigned char)((x)&0xff))
#define HI(x) ((unsigned char)(((x)>>8)&0xff))

void printEDFHeader() {
int i;
// main header
printf("%-8s", "0"); // version
printf("%-80s", "Giammy"); // TODO TEST local patient id
printf("%-80s", "Casa mia"); // TODO TEST local recordin id
printf("%-8s", "14.10.11"); // TODO TEST start recording date
printf("%-8s", "14.15.16"); // TODO TEST start recording time
printf("%-8d", 256+256*NCH); // header size: 256+ns*256
printf("%-44s", ""); // reserved
printf("%-8s", "324"); // TODO DATA number of data record
printf("%-8d", NSECPERRECORD); // duration of data record in seconds
printf("%-4d", NCH); // number of signals in data record

#define FOR_ALL for (i=0; i<NCH; i++)

// data header
printf("%-16s", "Freq"); // label
printf("%-16s", "giroX"); // label
printf("%-16s", "giroY"); // label
printf("%-16s", "F3"); // label
printf("%-16s", "FC6"); // label
printf("%-16s", "P7"); // label
printf("%-16s", "T8"); // label
printf("%-16s", "F7"); // label
printf("%-16s", "F8"); // label
printf("%-16s", "T7"); // label
printf("%-16s", "P8"); // label
printf("%-16s", "AF4"); // label
printf("%-16s", "F4"); // label
printf("%-16s", "AF3"); // label
printf("%-16s", "O2"); // label
printf("%-16s", "O1"); // label
printf("%-16s", "FC5"); // label

FOR_ALL {
printf("%-80s", "Transducer type");// transducer type
}
FOR_ALL {
if (i==0)
printf("%-8s", "Hz"); // physical dimens.
else
printf("%-8s", "raw"); // physical dimens.
}
FOR_ALL {
switch (i) {
case 0:
printf("%-8s", "0"); // physical min
break;
default:
printf("%-8s", "-500"); // physical min
}
}
FOR_ALL {
switch (i) {
case 0:
printf("%-8s", "5000"); // physical max
break;
default:
printf("%-8s", "500"); // physical max
}
}
FOR_ALL {
switch (i) {
case 1:
case 2:
printf("%-8s", "-128"); // digital min
break;
default:
printf("%-8s", "0"); // digital min
}
}
FOR_ALL {
switch (i) {
case 1:
case 2:
printf("%-8s", "128"); // digital max
break;
default:
printf("%-8s", "16384"); // digital max
}
}
FOR_ALL {
printf("%-80s", "prefiltering"); // prefiltering
}
FOR_ALL {
printf("%-8d", FREQ); // number of samples per data record
}
FOR_ALL {
printf("%-32s", ""); // reserved
}
}

int main(int argc, char *argv[])
{
int i,j;
int ch[NCH];
char theLine[LINE_SIZE];
char *ret;

for (i=0; i<NCH; i++) {
ch[i] = 0;
}

printEDFHeader();

while ((ret = fgets(theLine, LINE_SIZE, stdin)) != 0) {
//printf("Read %d '%s'\n", (int)ret, theLine);
sscanf(theLine, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
&ch[0], &ch[1], &ch[2], &ch[3], &ch[4], &ch[5], &ch[6], &ch[7],
&ch[8], &ch[9], &ch[10], &ch[11], &ch[12],
&ch[13],&ch[14], &ch[15], &ch[16]);

for (i=0; i<NCH; i++)
dataRecord[i][currentDataRecordSamples] = ch[i];
++currentDataRecordSamples;

if (currentDataRecordSamples >= NSECPERRECORD*FREQ) {
for (i=0;i<NCH;i++) {
for (j=0;j<NSECPERRECORD*FREQ;j++) {
putchar(LO(dataRecord[i][j]));
putchar(HI(dataRecord[i][j]));
}
}
currentDataRecordSamples = 0;
}
}
}

--
Gianluca Moro
N.s.A - Note su Android                http://www.giammy.com/nsa
Medical Brain Computer Interface  https://groups.google.com/group/medical-bci/

Teuniz

unread,
Jan 5, 2013, 9:18:47 AM1/5/13
to medic...@googlegroups.com


On Friday, November 4, 2011 12:48:00 PM UTC+1, giangiammy wrote:
 *** Note ***

 The implementation has been checked with EDFbrowser
 http://www.teuniz.net/edfbrowser/ but the field
 "number of data record" accordingly to the paper
 could be -1 (in my interpretation: read as many data
 record as you find in the file), while EDFbrowser want
 a real number of data record.

 For the date/time format, the paper writes:
 "startdate of recordlng (dd mn yy)" i.e. dd,mm and yy are
 space separated, while EDFbrowser wants them point separated.

 
The EDF format specifies that the field "number of datarecords" can be -1 when the number is unknown (i.e. during an aquisition).
When the application stops writing to the EDF-file and closes the EDF-file, the number of datarecords is known and must be written into the header.

Also, the field "startdate" must use dots as separators.

http://www.edfplus.info/specs/edf.html

http://www.teuniz.net/edfbrowser/edf%20format%20description.html

Arthur Lambert

unread,
Dec 9, 2014, 8:28:41 AM12/9/14
to medic...@googlegroups.com, teu...@gmail.com
Hi,

I know that this topic is very old but I am trying to implement a c code to convert csv file to edf file.
Value that I get from EEG are in double format. I can see that you convert the value from double to integer. There is no particular issue by doing this ?

I can see on all my edf result file that the signal is very crenelated. Morover I does not see your gain computation in this code. For example In my code I have his to to edf specification:

                int value;
                value
= channel_data[index][channel];


 value
= value - PHYS_MIN;
 value
= value * (DIG_MAX - DIG_MIN) / (PHYS_MAX - PHYS_MIN);
 value
= value + DIG_MIN;


 lo
= (unsigned char) (value);
 lo
= lo & 0xff;
 hi
= (unsigned char) (value >> 8);
 hi
= hi & 0xff;


 fputc
(lo, edf);
 fputc
(hi, edf);

Thanks & Regards,
Arthur.
Reply all
Reply to author
Forward
0 new messages