Skip to content


Commands to rewrite EDFs and signals/annotations in other text-based formats

Command Description
WRITE Write a new EDF file
MATRIX Dump signals (and annotations) to a file
DUMP-RECORDS Dump annotations and signals, by EDF record


Save a (modified) EDF file to disk

Writes a new EDF to disk, that will reflect any manipulation, filtering, or masking, etc, that has been applied.

Parameter Example Description
sig sig=C3 Signal to output (only one)
edf-dir edf-dir=edfs/ Set folder where new EDFs should be written
edf-tag edf-tag=v2 Add a tag to each new EDF filename
sample-list sample-list=v2.lst Name of the new sample-list

No formal output, other than a message to the log and one or more new EDFs.


To write a set of new EDFs that (for example) have been masked, filtered and retaining only one signal, given the commands in a file, say cmd.txt as follows:

EPOCH                       % Epoch the signals

MASK epoch=1-10             % Set to retain only the first 10 epochs

RESTRUCTURE                 % Apply the above mask 

SIGNALS keep=EEG            % Only retain the EEG signal

FILTER bandpass=0.5,4.5     % Apply a bandpass filter to the signal

WRITE edf-dir=newx/         % Write new EDFs, to the folder newx/
      edf-tag=v2            % add a 'v2' tag to each EDF
      sample-list=newx.lst  % create a new sample list pointing to the new EDFs

Running this set of commands:

luna s.lst < cmd.txt

will produce a new folder newx with three new EDFs:

ls newx
learn-nsrr01-v2.edf learn-nsrr02-v2.edf learn-nsrr03-v2.edf

That is, the new EDF filenames have a -v2 tag added. The folder (which must be specified with a / character in the edf-dir argument) will be created if it does not exist. In addition, Luna creates a new sample-list called newx.lst, that points to these new EDFs:

cat newx.lst 
nsrr01        newx/learn-nsrr01-v2.edf
nsrr02        newx/learn-nsrr02-v2.edf
nsrr03        newx/learn-nsrr03-v2.edf

Note that Luna appends each item to this list, and so you may want to delete it before running the command, if it already exists.

We can use the new sample list to check the properties of the new set of EDFs:

luna newx.lst -s DESC

As expected, we do in fact see that the EDFs are now only 10 epochs in length and contain only a single channel: (here, showing output only for the first EDF):

EDF filename      : newx/learn-nsrr01-v2.edf
ID                : nsrr01
Clock time        : 21:58:17 - 22:03:17
Duration          : 00:05:00
# signals         : 1
# EDF annotations : 1
Signals           : EEG[125]

Finally, to check the filtering, we can use the MATRIX command to dump the raw signals to a file. First from the original EDF (for the first 10 epochs only):

luna s.lst 1 -s "MASK epoch=1-10 & RE & MATRIX sig=EEG file=old.txt"
luna newx.lst 1 -s "MATRIX file=new.txt"

In R

o <- scan("old.txt",skip=1)
n <- scan("new.txt",skip=1)
plot( o[1:1000] , type="l" ) 
lines( n[1:1000] , col="blue" ) 



Dumps signal information to a file

For one or more signals of similar sampling rates, this command generates a text file containing the raw signal data.

Parameter Example Description
file file=signals.txt Required parameter, to specify the filename for the output
sig sig=C3,C4 Restrict output to these signals/channels
hms hms Add a clock-time column in hh:mm:ss format
hms2 hms2 Add a clock-time column in hh:mm:ss:microsecond format
annot annot=X,Y Add columns with values 1/0 to indicate the presence/absence of that annotation
min min Minimal output to show only signal information (no headers or lead columns)

All output is written to a text file as specified by the file parameter. For example:

ID    E   S   SP   T           EOG-L      EOG-R     EMG       EEG      
id01  1   0   0    0           -6.07448   4.18193   31.044    0.763126  
id01  1   0   1    0.00390625  -0.030525  2.83883   52.7778   11.5079   
id01  1   0   2    0.0078125   7.23443    2.22833   45.3297   23.0464   
id01  1   0   3    0.0117188   11.569     2.10623   23.4127   29.4567   
id01  1   0   4    0.015625    12.9731    2.16728   8.82173   31.2882  
id01  1   0   5    0.0195312   12.79      2.22833   -4.73138  30.7387  
id01  1   0   6    0.0234375   12.1795    2.28938   -13.6447  29.6398  
id01  1   0   7    0.0273438   11.6911    2.22833   -14.1331  28.663   
id01  1   0   8    0.03125     11.3858    2.22833   -11.8742  28.0525  
id01  1   0   9    0.0351562   11.2027    2.16728   -13.4615  27.6862  
... cont'd ...

Here, the first five columns are:

  • ID: individual/EDF ID
  • E: epoch number
  • S: elapsed time in seconds (integer)
  • SP: sample point in the EDF record
  • T: elapsed time in seconds

The subsequent columns represent the channels in the EDF (or those specified by the sig parameter).

If the min (or minimal) parameter is specified, then the header and the first five columns are omitted.

If the hms parameter is specified, then an additional column HMS is added, which is the clock-time in hh:mm:ss format. If hms2 is specified instead of hms, this field is printed with micro-second resolution.

If the annot parameter is specified, additional columns are added with the same names as the annotations specified, e.g. annot=X,Y will add two columns X and Y. For each sample point, these columns will have a 0 or 1 value to indicate whether or not that annotation was present at that point.


Writes detailed annotation and signal data to standard output

This command is unlikely to be of great utility to most users. It dumps detailed information about the signals and annotations to stdout.

Parameter Example Description
no-signals no-signals Do not show signal data
no-annots no-annots Do not show annotation information

All output is sent to the console (stdout) and so can be redirected, etc. Output is organized by EDF record, e.g.:

Record 1 of 40920 total (30 retained)
followed by Luna annotation information:
Generic Annotations-----------------------
wake    wake    0.00->30.00     wake[flag]=.
and then any EDF+ annotations:
EDF Annotations--------------------------
Signal 15 EDF Annotations
<0||(time-stamp, secs)>
Signals are then displayed, organized by record (in this instance, 1 second); the first signal SaO2 has a sample rate of 1 Hz, and so there is only one entry per record:
s = 0
interval = 0-999999999999
RECORD-DUMP     SaO2    rec=0   1/1     0       0       95.115587
Likewise for the second signal PR:
s = 1
interval = 0-999999999999
RECORD-DUMP     PR      rec=0   1/1     0       0       74.222934
In this example, the third signal (s=2) is EEG(sec), which has a sample rate of 125Hz (and so 125 entries here):
s = 2
interval = 0-999999999999
RECORD-DUMP     EEG(sec)        rec=0   1/125   0       0       -0.49019608
RECORD-DUMP     EEG(sec)        rec=0   2/125   8000000000      0.008   1.4705882
RECORD-DUMP     EEG(sec)        rec=0   3/125   16000000000     0.016   6.372549
RECORD-DUMP     EEG(sec)        rec=0   4/125   24000000000     0.024   3.4313725
RECORD-DUMP     EEG(sec)        rec=0   5/125   32000000000     0.032   -10.294118
RECORD-DUMP     EEG(sec)        rec=0   6/125   40000000000     0.04    -8.3333333
RECORD-DUMP     EEG(sec)        rec=0   7/125   48000000000     0.048   1.4705882
RECORD-DUMP     EEG(sec)        rec=0   8/125   56000000000     0.056   -0.49019608
RECORD-DUMP     EEG(sec)        rec=0   9/125   64000000000     0.064   -0.49019608
RECORD-DUMP     EEG(sec)        rec=0   10/125  72000000000     0.072   7.3529412
RECORD-DUMP     EEG(sec)        rec=0   11/125  80000000000     0.08    11.27451
... cont'd ...
The columns for signals are

  • a standard RECORD-DUMP
  • signal name
  • record number (starting at 0)
  • the sample point per record (e.g. 1/125, 2/125, etc)
  • the starting time for that sample point in time units
  • time in seconds
  • the value of the signal

For most purposes, the MATRIX command will likely be an easier route to achieve direct access to the signals in an EDF. (In fact, this command was in large part only added to assist in debugging during Luna development, but is described here for completeness.)