edfize 0.1.0.beta8 → 0.1.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -16
- data/README.md +17 -126
- data/edfize.gemspec +0 -2
- data/lib/edfize/edf.rb +134 -164
- data/lib/edfize/signal.rb +12 -42
- data/lib/edfize/version.rb +1 -1
- data/lib/edfize.rb +10 -27
- metadata +2 -22
- data/lib/edfize/tests/check_length.rb +0 -16
- data/lib/edfize/tests/check_reserved_area.rb +0 -15
- data/lib/edfize/tests/check_reserved_signal_areas.rb +0 -17
- data/lib/edfize/tests/result.rb +0 -7
- data/lib/edfize/tests/runner.rb +0 -43
- data/lib/edfize/tests.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2067540b9f8f67b1f56d3b14932dd5941aaa8c5e
|
4
|
+
data.tar.gz: 78bd7d36d221cd07a77a9ecefb9b6f67b68d0f1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf85cdd7723bb127c1dcbfaa2cf5707b6916a65c9729ea51857d38107bb1042f1655cdf0b5584cc1a951601fe9f2b87a0deadeba56c2e654f28f033da8a70090
|
7
|
+
data.tar.gz: b120948717c189f774f6a6c58a6764d2d7d7df5a98aceca29cf3323acd70e509d97471b1519797ed507d142771d2e170d08716af8a62ed2635bba6773e7b1e94
|
data/CHANGELOG.md
CHANGED
@@ -1,21 +1,8 @@
|
|
1
1
|
## 0.1.0
|
2
2
|
- Initial EDF class to load headers and signals into Ruby objects
|
3
3
|
- `edfize` command has the following actions:
|
4
|
-
- `
|
5
|
-
|
6
|
-
|
7
|
-
- To suppress descriptive test failures, add the flag `--quiet`
|
8
|
-
- `edfize test --quiet`
|
9
|
-
- Both flags can be used together
|
10
|
-
- `edfize test --failing --quiet`
|
11
|
-
- `run`: Prints out the headers of all edfs in the current directory and subdirectories
|
4
|
+
- `check`: Validates EDFs in the current directory for errors
|
5
|
+
- `test`: Same as `check`
|
6
|
+
- `run`: Prints out the headers of all edfs in the current directory
|
12
7
|
- `help`: Displays information about `edfize` along with all available commands
|
13
8
|
- `version`: Displays the current `edfize` version
|
14
|
-
- `edfize test` checks for the following:
|
15
|
-
- Expected Length Check: The expected total size is computed from the (`number
|
16
|
-
of data records` * `total samples across all signals`) + `size of header` and
|
17
|
-
this is compared to the actual file size.
|
18
|
-
- Reserved Area Checks: The header and the individual header reserved areas are
|
19
|
-
checked to validate that they are blank. Non-blank areas are a sign that the
|
20
|
-
edf header is corrupt and that data from the signal data block have leaked into
|
21
|
-
the header itself.
|
data/README.md
CHANGED
@@ -8,35 +8,33 @@ Ruby gem used to load, validate, and parse European Data Format files. Used for
|
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
-
|
11
|
+
Add this line to your application's Gemfile:
|
12
12
|
|
13
|
-
|
13
|
+
gem 'edfize'
|
14
14
|
|
15
|
-
|
15
|
+
And then execute:
|
16
16
|
|
17
|
-
|
17
|
+
$ bundle
|
18
18
|
|
19
|
-
|
19
|
+
Or install it yourself as:
|
20
20
|
|
21
|
-
|
22
|
-
edfize test
|
21
|
+
$ gem install edfize
|
23
22
|
|
24
|
-
|
23
|
+
## Usage
|
25
24
|
|
26
|
-
|
27
|
-
- **Reserved Area Checks**: Check that reserved areas are blank. Non-blank reserved areas can indicate a sign of header or EDF file corruption.
|
25
|
+
### Validate EDFs
|
28
26
|
|
29
|
-
|
27
|
+
Use `edfize check` to check that EDFs stored in the current directory have a valid format.
|
30
28
|
|
31
|
-
-
|
32
|
-
|
29
|
+
cd <edf-directory>
|
30
|
+
edfize check
|
33
31
|
|
34
32
|
### Print Signal Header information
|
35
33
|
|
36
34
|
Use `edfize run` to print out signal header information for each EDF in the current directory.
|
37
35
|
|
38
36
|
cd <edf-directory>
|
39
|
-
edfize
|
37
|
+
edfize check
|
40
38
|
|
41
39
|
### View A List of All Available Commands for Edfize
|
42
40
|
|
@@ -50,118 +48,11 @@ Use `edfize version` to check the version of Edfize.
|
|
50
48
|
|
51
49
|
edfize version
|
52
50
|
|
53
|
-
###
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
`
|
58
|
-
```ruby
|
59
|
-
# Tutorial 01 - Load EDF and Signals
|
60
|
-
#
|
61
|
-
# gem install edfize
|
62
|
-
#
|
63
|
-
# ruby tutorial_01_load_edf_and_signals.rb
|
64
|
-
#
|
65
|
-
# The EDF exists at:
|
66
|
-
#
|
67
|
-
# https://sleepdata.org/datasets/shhs/files/edfs/shhs1?f=shhs1-200001.edf
|
68
|
-
#
|
69
|
-
|
70
|
-
require 'rubygems'
|
71
|
-
require 'edfize'
|
72
|
-
|
73
|
-
# Loads the file and reads the EDF Header
|
74
|
-
edf = Edfize::Edf.new('shhs1-200001.edf')
|
75
|
-
|
76
|
-
# Loads the data section of the EDF into Signal objects
|
77
|
-
edf.load_signals
|
78
|
-
|
79
|
-
# Print out information on the signals
|
80
|
-
puts "EDF #{edf.filename} contains the following #{edf.signals.count} signal#{'s' unless edf.signals.count == 1}:\n\n"
|
81
|
-
|
82
|
-
edf.signals.each do |signal|
|
83
|
-
puts "Signal"
|
84
|
-
puts " Label : #{signal.label}"
|
85
|
-
puts " Samples Per Data Record : #{signal.samples_per_data_record}"
|
86
|
-
puts " First 10 Physical Values : #{(signal.physical_values[0..10] + ['...']).inspect}\n\n"
|
87
|
-
end
|
88
|
-
```
|
89
|
-
|
90
|
-
When run, the code above will output the following:
|
91
|
-
|
92
|
-
```console
|
93
|
-
EDF shhs1-200001.edf contains the following 14 signals:
|
94
|
-
|
95
|
-
Signal
|
96
|
-
Label : SaO2
|
97
|
-
Samples Per Data Record : 1
|
98
|
-
First 10 Physical Values : [95.31242847333486, 95.31242847333486, 95.31242847333486, 95.31242847333486, 95.31242847333486, 95.31242847333486, 95.31242847333486, 95.31242847333486, 94.14053559166858, 94.14053559166858, 94.14053559166858, "..."]
|
99
|
-
|
100
|
-
Signal
|
101
|
-
Label : H.R.
|
102
|
-
Samples Per Data Record : 1
|
103
|
-
First 10 Physical Values : [77.34416723887999, 77.34416723887999, 77.34416723887999, 76.56595712214848, 76.56595712214848, 76.56595712214848, 75.00190737773708, 75.00190737773708, 75.00190737773708, 75.00190737773708, 75.00190737773708, "..."]
|
104
|
-
|
105
|
-
Signal
|
106
|
-
Label : EEG(sec)
|
107
|
-
Samples Per Data Record : 125
|
108
|
-
First 10 Physical Values : [-4.411764705882348, 5.392156862745111, 2.4509803921568647, 0.49019607843136725, -0.49019607843136725, -10.294117647058826, 3.4313725490196134, 12.25490196078431, -1.470588235294116, -2.4509803921568647, -8.333333333333329, "..."]
|
109
|
-
|
110
|
-
Signal
|
111
|
-
Label : ECG
|
112
|
-
Samples Per Data Record : 125
|
113
|
-
First 10 Physical Values : [0.03431372549019618, 0.03431372549019618, 0.03431372549019618, 0.03431372549019618, 0.044117647058823595, 0.044117647058823595, 0.044117647058823595, 0.044117647058823595, 0.044117647058823595, 0.03431372549019618, 0.03431372549019618, "..."]
|
114
|
-
|
115
|
-
Signal
|
116
|
-
Label : EMG
|
117
|
-
Samples Per Data Record : 125
|
118
|
-
First 10 Physical Values : [12.622549019607845, 3.7990196078431353, -3.5539215686274517, -2.5735294117647065, 8.455882352941174, 1.5931372549019613, 9.436274509803923, -8.700980392156861, -2.5735294117647065, 13.112745098039213, -12.867647058823529, "..."]
|
119
|
-
|
120
|
-
Signal
|
121
|
-
Label : EOG(L)
|
122
|
-
Samples Per Data Record : 50
|
123
|
-
First 10 Physical Values : [28.921568627450966, 17.15686274509804, 25.0, 19.117647058823536, -5.392156862745097, -9.313725490196077, -0.49019607843136725, -1.470588235294116, 1.470588235294116, -1.470588235294116, 0.49019607843136725, "..."]
|
124
|
-
|
125
|
-
Signal
|
126
|
-
Label : EOG(R)
|
127
|
-
Samples Per Data Record : 50
|
128
|
-
First 10 Physical Values : [12.25490196078431, 1.470588235294116, 10.294117647058812, 5.392156862745111, 17.15686274509804, 18.137254901960773, 25.980392156862735, 32.84313725490196, 25.0, 26.960784313725497, 22.058823529411768, "..."]
|
129
|
-
|
130
|
-
Signal
|
131
|
-
Label : EEG
|
132
|
-
Samples Per Data Record : 125
|
133
|
-
First 10 Physical Values : [-2.4509803921568647, 1.470588235294116, -9.313725490196077, -6.372549019607845, -0.49019607843136725, -10.294117647058826, -12.25490196078431, -12.25490196078431, -7.352941176470594, 1.470588235294116, 6.372549019607845, "..."]
|
134
|
-
|
135
|
-
Signal
|
136
|
-
Label : THOR RES
|
137
|
-
Samples Per Data Record : 10
|
138
|
-
First 10 Physical Values : [0.207843137254902, 0.207843137254902, 0.15294117647058825, 0.0980392156862745, 0.03529411764705881, -0.0117647058823529, -0.050980392156862786, -0.08235294117647052, -0.10588235294117654, -0.1215686274509804, -0.13725490196078427, "..."]
|
139
|
-
|
140
|
-
Signal
|
141
|
-
Label : ABDO RES
|
142
|
-
Samples Per Data Record : 10
|
143
|
-
First 10 Physical Values : [0.30980392156862746, 0.24705882352941178, 0.16078431372549018, 0.06666666666666665, -0.0039215686274509665, -0.08235294117647052, -0.1607843137254903, -0.2078431372549019, -0.2313725490196079, -0.2549019607843137, -0.2705882352941176, "..."]
|
144
|
-
|
145
|
-
Signal
|
146
|
-
Label : POSITION
|
147
|
-
Samples Per Data Record : 1
|
148
|
-
First 10 Physical Values : [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, "..."]
|
149
|
-
|
150
|
-
Signal
|
151
|
-
Label : LIGHT
|
152
|
-
Samples Per Data Record : 1
|
153
|
-
First 10 Physical Values : [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, "..."]
|
154
|
-
|
155
|
-
Signal
|
156
|
-
Label : NEW AIR
|
157
|
-
Samples Per Data Record : 10
|
158
|
-
First 10 Physical Values : [6.372549019607845, 6.372549019607845, 5.392156862745111, 3.4313725490196134, 7.35294117647058, 6.372549019607845, 8.333333333333343, 9.313725490196077, 6.372549019607845, 6.372549019607845, 7.35294117647058, "..."]
|
159
|
-
|
160
|
-
Signal
|
161
|
-
Label : OX stat
|
162
|
-
Samples Per Data Record : 1
|
163
|
-
First 10 Physical Values : [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, "..."]
|
164
|
-
```
|
51
|
+
### Upgrade Edfize
|
52
|
+
|
53
|
+
Use `gem install edfize` to update Edfize to the latest stable
|
54
|
+
|
55
|
+
Use `gem install edfize --pre` to update Edfize to the latest prerelease
|
165
56
|
|
166
57
|
## Contributing
|
167
58
|
|
data/edfize.gemspec
CHANGED
@@ -26,8 +26,6 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.test_files = spec.files.grep(%r{^(test)/})
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
|
29
|
-
spec.add_dependency "colorize", "~> 0.7.2"
|
30
|
-
|
31
29
|
spec.add_development_dependency "bundler", "~> 1.6"
|
32
30
|
spec.add_development_dependency "rake"
|
33
31
|
end
|
data/lib/edfize/edf.rb
CHANGED
@@ -2,226 +2,196 @@ require 'edfize/signal'
|
|
2
2
|
|
3
3
|
module Edfize
|
4
4
|
class Edf
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# Header Information
|
9
|
-
attr_accessor :version
|
10
|
-
attr_accessor :local_patient_identification
|
11
|
-
attr_accessor :local_recording_identification
|
12
|
-
attr_accessor :start_date_of_recording
|
13
|
-
attr_accessor :start_time_of_recording
|
14
|
-
attr_accessor :number_of_bytes_in_header
|
15
|
-
attr_accessor :reserved
|
16
|
-
attr_accessor :number_of_data_records
|
17
|
-
attr_accessor :duration_of_a_data_record
|
18
|
-
attr_accessor :number_of_signals
|
19
|
-
|
20
|
-
attr_accessor :signals
|
21
|
-
|
22
|
-
HEADER_CONFIG = {
|
23
|
-
version: { size: 8, after_read: :to_i, name: 'Version' },
|
24
|
-
local_patient_identification: { size: 80, after_read: :strip, name: 'Local Patient Identification' },
|
25
|
-
local_recording_identification: { size: 80, after_read: :strip, name: 'Local Recording Identification' },
|
26
|
-
start_date_of_recording: { size: 8, name: 'Start Date of Recording', description: '(dd.mm.yy)' },
|
27
|
-
start_time_of_recording: { size: 8, name: 'Start Time of Recording', description: '(hh.mm.ss)'},
|
28
|
-
number_of_bytes_in_header: { size: 8, after_read: :to_i, name: 'Number of Bytes in Header' },
|
29
|
-
reserved: { size: 44, name: 'Reserved' },
|
30
|
-
number_of_data_records: { size: 8, after_read: :to_i, name: 'Number of Data Records' },
|
31
|
-
duration_of_a_data_record: { size: 8, after_read: :to_i, name: 'Duration of a Data Record', units: 'second' },
|
32
|
-
number_of_signals: { size: 4, after_read: :to_i, name: 'Number of Signals' }
|
33
|
-
}
|
34
|
-
|
35
|
-
HEADER_OFFSET = HEADER_CONFIG.collect{|k,h| h[:size]}.inject(:+)
|
36
|
-
|
37
|
-
SIZE_OF_SAMPLE_IN_BYTES = 2
|
38
|
-
|
39
|
-
# Used by tests
|
40
|
-
RESERVED_SIZE = HEADER_CONFIG[:reserved][:size]
|
41
|
-
|
42
|
-
def self.create(filename, &block)
|
43
|
-
edf = self.new(filename)
|
44
|
-
yield edf if block_given?
|
45
|
-
edf
|
46
|
-
end
|
5
|
+
attr_reader :signals
|
6
|
+
|
7
|
+
HEADER_OFFSET = 256
|
47
8
|
|
48
9
|
def initialize(filename)
|
49
10
|
@filename = filename
|
50
11
|
@signals = []
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
12
|
+
signal_labels
|
13
|
+
transducer_types
|
14
|
+
physical_dimensions
|
15
|
+
physical_minimums
|
16
|
+
physical_maximums
|
17
|
+
digital_minimums
|
18
|
+
digital_maximums
|
19
|
+
prefilterings
|
20
|
+
samples_in_data_records
|
21
|
+
reserved_areas
|
22
|
+
end
|
23
|
+
|
24
|
+
def size
|
25
|
+
File.size(@filename)
|
55
26
|
end
|
56
27
|
|
57
|
-
def
|
58
|
-
|
28
|
+
def print_header
|
29
|
+
puts @filename
|
30
|
+
puts "#{size} bytes (Total File Size)"
|
31
|
+
puts "'#{header_version}' (0)"
|
32
|
+
puts "'#{header_local_patient_identification}' (local patient identification)"
|
33
|
+
puts "'#{header_local_recording_identification}' (local recording indentification)"
|
34
|
+
puts "'#{header_start_date_of_recording}' (dd.mm.yy start date of recording)"
|
35
|
+
puts "'#{header_start_time_of_recording}' (hh.mm.ss start time of recording)"
|
36
|
+
# puts "--- RESERVED"
|
37
|
+
puts "'#{number_of_data_records}' seconds (number of data records, -1 if unknown)"
|
38
|
+
puts "'#{duration_of_a_data_record}' seconds (duration of a data record)"
|
39
|
+
puts "'#{number_of_signals}' number of signals (ns) in data record"
|
40
|
+
signals.each_with_index do |signal, index|
|
41
|
+
puts "'#{signal.label}' (signal[#{index+1}] label)"
|
42
|
+
puts "'#{signal.physical_dimension}' (signal[#{index+1}] physical_dimension)"
|
43
|
+
puts "'#{signal.transducer_type}' (signal[#{index+1}] transducer_type)"
|
44
|
+
puts "'#{signal.physical_minimum}' (signal[#{index+1}] physical_minimum)"
|
45
|
+
puts "'#{signal.physical_maximum}' (signal[#{index+1}] physical_maximum)"
|
46
|
+
puts "'#{signal.digital_minimum}' (signal[#{index+1}] digital_minimum)"
|
47
|
+
puts "'#{signal.digital_maximum}' (signal[#{index+1}] digital_maximum)"
|
48
|
+
puts "'#{signal.prefiltering}' (signal[#{index+1}] prefiltering)"
|
49
|
+
puts "'#{signal.samples_in_data_record}' (signal[#{index+1}] samples_in_data_record)"
|
50
|
+
puts "'#{signal.reserved_area}' (signal[#{index+1}] reserved_area)"
|
51
|
+
end
|
59
52
|
end
|
60
53
|
|
61
|
-
def
|
62
|
-
|
54
|
+
def header_version
|
55
|
+
IO.binread(@filename, 8)
|
63
56
|
end
|
64
57
|
|
65
|
-
|
66
|
-
|
58
|
+
# 80 ascii : local patient identification (mind item 3 of the additional EDF+ specs)
|
59
|
+
def header_local_patient_identification
|
60
|
+
IO.binread(@filename, 80, 8)
|
67
61
|
end
|
68
62
|
|
69
|
-
#
|
70
|
-
def
|
71
|
-
|
63
|
+
# 80 ascii : local recording identification (mind item 4 of the additional EDF+ specs)
|
64
|
+
def header_local_recording_identification
|
65
|
+
IO.binread(@filename, 80, 88)
|
72
66
|
end
|
73
67
|
|
74
|
-
#
|
75
|
-
def
|
76
|
-
|
68
|
+
# 8 ascii : startdate of recording (dd.mm.yy) (mind item 2 of the additional EDF+ specs)
|
69
|
+
def header_start_date_of_recording
|
70
|
+
IO.binread(@filename, 8, 168)
|
77
71
|
end
|
78
72
|
|
79
|
-
|
80
|
-
|
73
|
+
# 8 ascii : starttime of recording (hh.mm.ss)
|
74
|
+
def header_start_time_of_recording
|
75
|
+
IO.binread(@filename, 8, 176)
|
81
76
|
end
|
82
77
|
|
83
|
-
|
84
|
-
|
78
|
+
# 8 ascii : number of bytes in header record
|
79
|
+
def number_of_bytes_in_header
|
80
|
+
IO.binread(@filename, 8, 184)
|
85
81
|
end
|
86
82
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
else
|
92
|
-
" #{units}" + (self.instance_variable_get("@#{section}") == 1 ? '' : 's')
|
93
|
-
end
|
94
|
-
result
|
95
|
-
end
|
83
|
+
# 44 ascii : reserved
|
84
|
+
# def reserved
|
85
|
+
# IO.binread(@filename, 44, 192)
|
86
|
+
# end
|
96
87
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
''
|
101
|
-
else
|
102
|
-
" #{description}"
|
103
|
-
end
|
104
|
-
result
|
88
|
+
# 8 ascii : number of data records (-1 if unknown, obey item 10 of the additional EDF+ specs)
|
89
|
+
def number_of_data_records
|
90
|
+
IO.binread(@filename, 8, 236)
|
105
91
|
end
|
106
92
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
puts "\nHeader Information"
|
111
|
-
HEADER_CONFIG.each do |section, hash|
|
112
|
-
puts "#{hash[:name]}#{' '*(31 - hash[:name].size)}: " + section_value_to_string(section) + section_units(section) + section_description(section)
|
113
|
-
end
|
114
|
-
puts "\nSignal Information"
|
115
|
-
signals.each_with_index do |signal, index|
|
116
|
-
puts "\n Position : #{index + 1}"
|
117
|
-
signal.print_header
|
118
|
-
end
|
119
|
-
puts "\nGeneral Information"
|
120
|
-
puts "Size of Header (bytes) : #{size_of_header}"
|
121
|
-
puts "Size of Data (bytes) : #{data_size}"
|
122
|
-
puts "Total Size (bytes) : #{edf_size}"
|
123
|
-
|
124
|
-
puts "Expected Size of Header (bytes): #{expected_size_of_header}"
|
125
|
-
puts "Expected Size of Data (bytes): #{expected_data_size}"
|
126
|
-
puts "Expected Total Size (bytes): #{expected_edf_size}"
|
93
|
+
# 8 ascii : duration of a data record, in seconds
|
94
|
+
def duration_of_a_data_record
|
95
|
+
IO.binread(@filename, 8, 244)
|
127
96
|
end
|
128
97
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
HEADER_CONFIG.keys.each do |section|
|
133
|
-
read_header_section(section)
|
134
|
-
end
|
98
|
+
# 4 ascii : number of signals (ns) in data record
|
99
|
+
def number_of_signals
|
100
|
+
IO.binread(@filename, 4, 252)
|
135
101
|
end
|
136
102
|
|
137
|
-
def
|
138
|
-
|
139
|
-
result = result.to_s.send(HEADER_CONFIG[section][:after_read]) unless HEADER_CONFIG[section][:after_read].to_s == ''
|
140
|
-
self.instance_variable_set("@#{section}", result)
|
103
|
+
def ns
|
104
|
+
Integer(self.number_of_signals) rescue 0
|
141
105
|
end
|
142
106
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
107
|
+
# ns * 16 ascii : ns * label (e.g. EEG Fpz-Cz or Body temp) (mind item 9 of the additional EDF+ specs)
|
108
|
+
def signal_labels
|
109
|
+
offset = HEADER_OFFSET
|
110
|
+
(0..ns-1).to_a.each do |signal_number|
|
111
|
+
@signals[signal_number] ||= Signal.new()
|
112
|
+
@signals[signal_number].label = IO.binread(@filename, 16, offset+(signal_number*16))
|
148
113
|
end
|
149
|
-
offset
|
150
114
|
end
|
151
115
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
def create_signals
|
116
|
+
# ns * 80 ascii : ns * transducer type (e.g. AgAgCl electrode)
|
117
|
+
def transducer_types
|
118
|
+
offset = HEADER_OFFSET + ns * 16
|
157
119
|
(0..ns-1).to_a.each do |signal_number|
|
158
120
|
@signals[signal_number] ||= Signal.new()
|
121
|
+
@signals[signal_number].transducer_type = IO.binread(@filename, 80, offset+(signal_number*80))
|
159
122
|
end
|
160
123
|
end
|
161
124
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
125
|
+
# ns * 8 ascii : ns * physical dimension (e.g. uV or degreeC)
|
126
|
+
def physical_dimensions
|
127
|
+
offset = HEADER_OFFSET + ns * (16 + 80)
|
128
|
+
(0..ns-1).to_a.each do |signal_number|
|
129
|
+
@signals[signal_number] ||= Signal.new()
|
130
|
+
@signals[signal_number].physical_dimension = IO.binread(@filename, 8, offset+(signal_number*8))
|
166
131
|
end
|
167
132
|
end
|
168
133
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
134
|
+
# ns * 8 ascii : ns * physical minimum (e.g. -500 or 34)
|
135
|
+
def physical_minimums
|
136
|
+
offset = HEADER_OFFSET + ns * (16 + 80 + 8)
|
137
|
+
(0..ns-1).to_a.each do |signal_number|
|
138
|
+
@signals[signal_number] ||= Signal.new()
|
139
|
+
@signals[signal_number].physical_minimum = IO.binread(@filename, 8, offset+(signal_number*8))
|
174
140
|
end
|
175
|
-
offset
|
176
141
|
end
|
177
142
|
|
178
|
-
|
179
|
-
|
143
|
+
# ns * 8 ascii : ns * physical maximum (e.g. 500 or 40)
|
144
|
+
def physical_maximums
|
145
|
+
offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8)
|
180
146
|
(0..ns-1).to_a.each do |signal_number|
|
181
|
-
|
182
|
-
|
183
|
-
result = result.to_s.send(Signal::SIGNAL_CONFIG[section][:after_read]) unless Signal::SIGNAL_CONFIG[section][:after_read].to_s == ''
|
184
|
-
@signals[signal_number].send("#{section}=", result)
|
147
|
+
@signals[signal_number] ||= Signal.new()
|
148
|
+
@signals[signal_number].physical_maximum = IO.binread(@filename, 8, offset+(signal_number*8))
|
185
149
|
end
|
186
150
|
end
|
187
151
|
|
188
|
-
|
189
|
-
|
190
|
-
|
152
|
+
# ns * 8 ascii : ns * digital minimum (e.g. -2048)
|
153
|
+
def digital_minimums
|
154
|
+
offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8)
|
155
|
+
(0..ns-1).to_a.each do |signal_number|
|
156
|
+
@signals[signal_number] ||= Signal.new()
|
157
|
+
@signals[signal_number].digital_minimum = IO.binread(@filename, 8, offset+(signal_number*8))
|
158
|
+
end
|
191
159
|
end
|
192
160
|
|
193
|
-
#
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
all_samples_per_data_record = @signals.collect{|s| s.samples_per_data_record}
|
200
|
-
total_samples_per_data_record = all_samples_per_data_record.inject(:+).to_i
|
201
|
-
|
202
|
-
offset = 0
|
203
|
-
offsets = []
|
204
|
-
all_samples_per_data_record.each do |samples_per_data_record|
|
205
|
-
offsets << offset
|
206
|
-
offset += samples_per_data_record
|
161
|
+
# ns * 8 ascii : ns * digital maximum (e.g. 2047)
|
162
|
+
def digital_maximums
|
163
|
+
offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8)
|
164
|
+
(0..ns-1).to_a.each do |signal_number|
|
165
|
+
@signals[signal_number] ||= Signal.new()
|
166
|
+
@signals[signal_number].digital_maximum = IO.binread(@filename, 8, offset+(signal_number*8))
|
207
167
|
end
|
168
|
+
end
|
208
169
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
end
|
170
|
+
# ns * 80 ascii : ns * prefiltering (e.g. HP:0.1Hz LP:75Hz)
|
171
|
+
def prefilterings
|
172
|
+
offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8 + 8)
|
173
|
+
(0..ns-1).to_a.each do |signal_number|
|
174
|
+
@signals[signal_number] ||= Signal.new()
|
175
|
+
@signals[signal_number].prefiltering = IO.binread(@filename, 80, offset+(signal_number*80))
|
216
176
|
end
|
217
177
|
end
|
218
178
|
|
219
|
-
|
220
|
-
|
179
|
+
# ns * 8 ascii : ns * nr of samples in each data record
|
180
|
+
def samples_in_data_records
|
181
|
+
offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8 + 8 + 80)
|
182
|
+
(0..ns-1).to_a.each do |signal_number|
|
183
|
+
@signals[signal_number] ||= Signal.new()
|
184
|
+
@signals[signal_number].samples_in_data_record = IO.binread(@filename, 8, offset+(signal_number*8))
|
185
|
+
end
|
221
186
|
end
|
222
187
|
|
223
|
-
|
224
|
-
|
188
|
+
# ns * 32 ascii : ns * reserved
|
189
|
+
def reserved_areas
|
190
|
+
offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8 + 8 + 80 + 8)
|
191
|
+
(0..ns-1).to_a.each do |signal_number|
|
192
|
+
@signals[signal_number] ||= Signal.new()
|
193
|
+
@signals[signal_number].reserved_area = IO.binread(@filename, 32, offset+(signal_number*32))
|
194
|
+
end
|
225
195
|
end
|
226
196
|
end
|
227
197
|
end
|
data/lib/edfize/signal.rb
CHANGED
@@ -1,49 +1,19 @@
|
|
1
1
|
module Edfize
|
2
2
|
class Signal
|
3
|
-
attr_accessor :label, :transducer_type, :physical_dimension,
|
4
|
-
:
|
5
|
-
:digital_minimum, :digital_maximum,
|
6
|
-
:prefiltering, :samples_per_data_record,
|
7
|
-
:reserved_area, :digital_values, :physical_values
|
8
|
-
|
9
|
-
SIGNAL_CONFIG = {
|
10
|
-
label: { size: 16, after_read: :strip, name: 'Label' },
|
11
|
-
transducer_type: { size: 80, after_read: :strip, name: 'Transducer Type' },
|
12
|
-
physical_dimension: { size: 8, after_read: :strip, name: 'Physical Dimension' },
|
13
|
-
physical_minimum: { size: 8, after_read: :to_f, name: 'Physical Minimum' },
|
14
|
-
physical_maximum: { size: 8, after_read: :to_f, name: 'Physical Maximum' },
|
15
|
-
digital_minimum: { size: 8, after_read: :to_i, name: 'Digital Minimum' },
|
16
|
-
digital_maximum: { size: 8, after_read: :to_i, name: 'Digital Maximum' },
|
17
|
-
prefiltering: { size: 80, after_read: :strip, name: 'Prefiltering' },
|
18
|
-
samples_per_data_record: { size: 8, after_read: :to_i, name: 'Samples Per Data Record' },
|
19
|
-
reserved_area: { size: 32, name: 'Reserved Area' }
|
20
|
-
}
|
3
|
+
attr_accessor :label, :transducer_type, :physical_dimension, :physical_minimum, :physical_maximum,
|
4
|
+
:digital_minimum, :digital_maximum, :prefiltering, :samples_in_data_record, :reserved_area
|
21
5
|
|
22
6
|
def initialize
|
23
|
-
@
|
24
|
-
@
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def print_header
|
35
|
-
SIGNAL_CONFIG.each do |section, hash|
|
36
|
-
puts " #{hash[:name]}#{' '*(29 - hash[:name].size)}: " + self.send(section).to_s
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Physical value (dimension PhysiDim) = (ASCIIvalue-DigiMin)*(PhysiMax-PhysiMin)/(DigiMax-DigiMin) + PhysiMin.
|
41
|
-
def calculate_physical_values!
|
42
|
-
@physical_values = @digital_values.collect{|sample| ( sample - @digital_minimum ) * ( @physical_maximum - @physical_minimum ) / ( @digital_maximum - @digital_minimum) + @physical_minimum }
|
43
|
-
end
|
44
|
-
|
45
|
-
def samples
|
46
|
-
@physical_values
|
7
|
+
@label = ''
|
8
|
+
@physical_dimension = ''
|
9
|
+
@transducer_type = ''
|
10
|
+
@physical_minimum = ''
|
11
|
+
@physical_maximum = ''
|
12
|
+
@digital_minimum = ''
|
13
|
+
@digital_maximum = ''
|
14
|
+
@prefiltering = ''
|
15
|
+
@samples_in_data_record = ''
|
16
|
+
@reserved_area = ''
|
47
17
|
end
|
48
18
|
|
49
19
|
end
|
data/lib/edfize/version.rb
CHANGED
data/lib/edfize.rb
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
require 'edfize/edf'
|
2
|
-
require 'edfize/tests'
|
3
2
|
require 'edfize/version'
|
4
3
|
|
5
|
-
require 'colorize'
|
6
|
-
|
7
4
|
module Edfize
|
8
5
|
def self.launch(argv)
|
9
6
|
case argv.first.to_s.scan(/\w/).first
|
10
7
|
when 'v'
|
11
8
|
version
|
12
9
|
when 'c', 't'
|
13
|
-
check
|
10
|
+
check
|
14
11
|
when 'r'
|
15
12
|
print_headers
|
16
13
|
else
|
@@ -20,7 +17,7 @@ module Edfize
|
|
20
17
|
|
21
18
|
def self.print_headers
|
22
19
|
puts "----------------"
|
23
|
-
|
20
|
+
edfs_in_current_directory.each do |edf_file_name|
|
24
21
|
edf = Edfize::Edf.new(edf_file_name)
|
25
22
|
edf.print_header
|
26
23
|
puts "----------------"
|
@@ -31,21 +28,9 @@ module Edfize
|
|
31
28
|
puts "Edfize #{Edfize::VERSION::STRING}"
|
32
29
|
end
|
33
30
|
|
34
|
-
def self.check
|
35
|
-
|
36
|
-
edf_count
|
37
|
-
test_count = 0
|
38
|
-
failure_count = 0
|
39
|
-
puts "Started\n"
|
40
|
-
edfs_in_current_directory_and_subdirectories.each do |edf_file_name|
|
41
|
-
edf = Edfize::Edf.new(edf_file_name)
|
42
|
-
runner = Edfize::Tests::Runner.new(edf, argv)
|
43
|
-
runner.run_tests
|
44
|
-
test_count += runner.tests_run
|
45
|
-
failure_count += runner.tests_failed
|
46
|
-
end
|
47
|
-
puts "\nFinished in #{Time.now - test_start_time}s"
|
48
|
-
puts "#{edf_count} EDF#{'s' unless edf_count == 1}, #{test_count} test#{'s' unless test_count == 1}, " + "#{failure_count} failure#{'s' unless failure_count == 1}".colorize( failure_count == 0 ? :green : :red )
|
31
|
+
def self.check
|
32
|
+
edf_count = edfs_in_current_directory.count
|
33
|
+
puts "Checking #{edf_count} EDF#{'s' unless edf_count == 1}"
|
49
34
|
end
|
50
35
|
|
51
36
|
def self.help
|
@@ -53,11 +38,9 @@ module Edfize
|
|
53
38
|
Usage: edfize COMMAND [ARGS]
|
54
39
|
|
55
40
|
The most common edfize commands are:
|
56
|
-
[
|
57
|
-
|
58
|
-
|
59
|
-
[r]un Print EDF header information
|
60
|
-
[h]elp Show edfize command documentation
|
41
|
+
[c]heck Check EDFs in current directory for errors
|
42
|
+
[t]est Same as [c]heck
|
43
|
+
[h]elp Show edfize command-line documentation
|
61
44
|
[v]ersion Returns the version of Edfize
|
62
45
|
|
63
46
|
Commands can be referenced by the first letter:
|
@@ -67,7 +50,7 @@ EOT
|
|
67
50
|
puts help_message
|
68
51
|
end
|
69
52
|
|
70
|
-
def self.
|
71
|
-
Dir.glob('
|
53
|
+
def self.edfs_in_current_directory
|
54
|
+
Dir.glob('*.edf')
|
72
55
|
end
|
73
56
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: edfize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Remo Mueller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: colorize
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.7.2
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.7.2
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,12 +56,6 @@ files:
|
|
70
56
|
- lib/edfize.rb
|
71
57
|
- lib/edfize/edf.rb
|
72
58
|
- lib/edfize/signal.rb
|
73
|
-
- lib/edfize/tests.rb
|
74
|
-
- lib/edfize/tests/check_length.rb
|
75
|
-
- lib/edfize/tests/check_reserved_area.rb
|
76
|
-
- lib/edfize/tests/check_reserved_signal_areas.rb
|
77
|
-
- lib/edfize/tests/result.rb
|
78
|
-
- lib/edfize/tests/runner.rb
|
79
59
|
- lib/edfize/version.rb
|
80
60
|
homepage: https://github.com/sleepepi/edfize
|
81
61
|
licenses:
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Edfize
|
2
|
-
module Tests
|
3
|
-
module CheckLength
|
4
|
-
# This test checks that the length calculated from the EDF header matches
|
5
|
-
# the total length of the file
|
6
|
-
def test_expected_length(runner)
|
7
|
-
result = Result.new
|
8
|
-
result.passes = (runner.edf.expected_edf_size == runner.edf.edf_size)
|
9
|
-
result.pass_fail = " #{result.passes ? 'PASS' : 'FAIL'}".colorize( result.passes ? :green : :red ) + " Expected File Size"
|
10
|
-
result.expected = " Expected : #{runner.edf.expected_edf_size} bytes"
|
11
|
-
result.actual = " Actual : #{runner.edf.edf_size} bytes"
|
12
|
-
result
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Edfize
|
2
|
-
module Tests
|
3
|
-
module CheckReservedArea
|
4
|
-
# This test checks that the reserved area in the header is blank
|
5
|
-
def test_reserved_area_blank(runner)
|
6
|
-
result = Result.new
|
7
|
-
result.passes = (runner.edf.reserved == ' ' * Edf::RESERVED_SIZE)
|
8
|
-
result.pass_fail = " #{result.passes ? 'PASS' : 'FAIL'}".colorize( result.passes ? :green : :red ) + " Reserved Area Blank"
|
9
|
-
result.expected = " Expected : #{(' ' * Edf::RESERVED_SIZE).inspect}"
|
10
|
-
result.actual = " Actual : #{runner.edf.reserved.to_s.inspect}"
|
11
|
-
result
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Edfize
|
2
|
-
module Tests
|
3
|
-
module CheckReservedSignalAreas
|
4
|
-
# This test checks that the reserved areas in the signal headers are blank
|
5
|
-
def test_reserved_signal_areas_blank(runner)
|
6
|
-
reserved_areas = runner.edf.signals.collect(&:reserved_area)
|
7
|
-
|
8
|
-
result = Result.new
|
9
|
-
result.passes = (reserved_areas.reject{|r| r.to_s.strip == ''}.count == 0)
|
10
|
-
result.pass_fail = " #{result.passes ? 'PASS' : 'FAIL'}".colorize( result.passes ? :green : :red ) + " Signal Reserved Area Blank"
|
11
|
-
result.expected = " Expected : #{[''] * runner.edf.signals.count}"
|
12
|
-
result.actual = " Actual : #{reserved_areas}"
|
13
|
-
result
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/edfize/tests/result.rb
DELETED
data/lib/edfize/tests/runner.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module Edfize
|
2
|
-
module Tests
|
3
|
-
class Runner
|
4
|
-
attr_reader :tests_run, :tests_failed, :edf, :verbose, :show_passing
|
5
|
-
|
6
|
-
TESTS = %w( expected_length reserved_area_blank reserved_signal_areas_blank )
|
7
|
-
|
8
|
-
def initialize(edf, argv)
|
9
|
-
@tests_run = 0
|
10
|
-
@tests_failed = 0
|
11
|
-
@edf = edf
|
12
|
-
@verbose = argv.include?('--quiet') ? false : true
|
13
|
-
@show_passing = argv.include?('--failing') ? false : true
|
14
|
-
end
|
15
|
-
|
16
|
-
def run_tests
|
17
|
-
results = []
|
18
|
-
|
19
|
-
TESTS.each do |test_name|
|
20
|
-
result = Edfize::Tests.send("test_#{test_name}", self)
|
21
|
-
@tests_failed += 1 unless result.passes
|
22
|
-
@tests_run += 1
|
23
|
-
results << result
|
24
|
-
end
|
25
|
-
|
26
|
-
puts "\n#{@edf.filename}" if results.reject{|r| r.passes}.count > 0 or @show_passing
|
27
|
-
results.each do |result|
|
28
|
-
print_result(result)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def print_result(result)
|
33
|
-
if self.show_passing or !result.passes
|
34
|
-
puts result.pass_fail
|
35
|
-
unless result.passes or not self.verbose
|
36
|
-
puts result.expected
|
37
|
-
puts result.actual
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/edfize/tests.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'edfize/tests/result'
|
2
|
-
require 'edfize/tests/runner'
|
3
|
-
require 'edfize/tests/check_length'
|
4
|
-
require 'edfize/tests/check_reserved_area'
|
5
|
-
require 'edfize/tests/check_reserved_signal_areas'
|
6
|
-
|
7
|
-
module Edfize
|
8
|
-
module Tests
|
9
|
-
extend CheckLength
|
10
|
-
extend CheckReservedArea
|
11
|
-
extend CheckReservedSignalAreas
|
12
|
-
end
|
13
|
-
end
|