-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathedfReader.go
159 lines (130 loc) · 4.1 KB
/
edfReader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package edf
import (
"bytes"
"encoding/binary"
"os"
)
/* --- MAIN FUNCTIONS --- */
// ReadFile reads an EDF file, parsing it into the header and the records.
// The header will be a map relating the properties to a string with the raw data
// The records will be a matrix storing the raw bytes in the file
func ReadFile(input string) Edf {
inlet, err := os.Open(input)
if err != nil {
panic(err)
}
defer inlet.Close()
header := ReadHeader(inlet)
records := ReadRecords(inlet, header)
physicalRecords := GetConvertedRecords(&records, header)
return NewEdf(header, records, physicalRecords)
}
// ReadHeader reads the header of an EDF file. Requires the opened EDF file, the list of
// specifications and the length in bytes for each of them, as described by
// the EDF standard. The specs can be accessed though the GetSpecsList
// function, and their lenghts through the GetSpecsLength one.
func ReadHeader(inlet *os.File) map[string]string {
specsList := GetSpecsList()
specsLength := GetSpecsLength()
header := make(map[string]string)
index := 0
// Reading header's header
for index < len(specsList) {
spec := specsList[index]
if spec == "label" {
break
} else {
data := make([]byte, specsLength[spec])
n, _ := inlet.Read(data)
header[spec] = string(data[:n])
}
index++
}
// Reading header's records
numberSignals := getNumberSignals(header)
for j := index; j < len(specsList); j++ {
spec := specsList[j]
data := make([]byte, specsLength[spec]*numberSignals)
n, _ := inlet.Read(data)
header[spec] = string(data[:n])
}
return header
}
// ReadRecords reads the data records from the EDF file. Its parameters are the pointer to
// file; and header information, as returned by the ReadHeader function.
func ReadRecords(inlet *os.File, header map[string]string) [][]int16 {
numberSignals := getNumberSignals(header)
numberSamples := getNumberSamples(header)
records := make([][]int16, numberSignals)
dataRecords := str2int(header["datarecords"])
// setup records
for i := 0; i < numberSignals; i++ {
records[i] = make([]int16, 0, dataRecords*numberSamples[i])
}
// Reading records
dataRecordsSize := 2 * dataRecords * Sigma(numberSamples)
data := make([]byte, dataRecordsSize)
inlet.Read(data)
transData := translate(data)
// translate data
i := 0
for d := 0; d < dataRecords; d++ {
for s := 0; s < numberSignals; s++ {
step := numberSamples[s]
piece := transData[i : i+step]
records[s] = append(records[s], piece...)
i += step
}
}
return records
}
// GetConvertedRecords gets the convertion factor to each channel.
func GetConvertedRecords(records *[][]int16, header map[string]string) [][]float64 {
ns := getNumberSignals(header)
convertedRecords := make([][]float64, ns)
dmaxs := separateString(header["digitalmaximum"], ns)
dmins := separateString(header["digitalminimum"], ns)
pmaxs := separateString(header["physicalmaximum"], ns)
pmins := separateString(header["physicalminimum"], ns)
for i := 0; i < ns; i++ {
dmax := str2float64(dmaxs[i])
dmin := str2float64(dmins[i])
pmax := str2float64(pmaxs[i])
pmin := str2float64(pmins[i])
k := (pmax - pmin) / (dmax - dmin)
convertedRecords[i] = make([]float64, len((*records)[i]))
for j := 0; j < len((*records)[i]); j++ {
convertedRecords[i][j] = k*(float64((*records)[i][j])-dmin) + pmin
}
}
return convertedRecords
}
/* --- AUXILIAR FUNCTIONS --- */
func translate(inlet []byte) []int16 {
var data int16
limit := len(inlet) / 2
outlet := make([]int16, limit)
buffer := bytes.NewReader(inlet)
for i := 0; i < limit; i++ {
oops := binary.Read(buffer, binary.LittleEndian, &data)
if oops == nil {
outlet[i] = data
} else {
panic(oops)
}
}
return outlet
}
func getNumberSignals(header map[string]string) int {
raw := header["numbersignals"]
return str2int(raw)
}
func getNumberSamples(header map[string]string) []int {
numberSignals := getNumberSignals(header)
numberSamples := make([]int, numberSignals)
samples := separateString(header["samplesrecord"], numberSignals)
for i := 0; i < numberSignals; i++ {
numberSamples[i] = str2int(samples[i])
}
return numberSamples
}