edfize 0.1.0.beta2 → 0.1.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 44aeaf1024f15eadb70e994e4f768d7e23e55073
4
- data.tar.gz: a92347e4a34b965c09ba1d751582d0cc0bf56ec4
3
+ metadata.gz: 66faa96463f7845c7d3216c16b6d71dfedaf5a47
4
+ data.tar.gz: 835ab39c4653438fbebeb739b3330e160606b3ff
5
5
  SHA512:
6
- metadata.gz: b809d63028034dc994a9b8dfaeae8cecf37f1195f2a4bef625c3239537ed590dcf96ce0ad80a86b5119748e1db9a2e4c497cfbaf5bdca8f3703b6f007ef40a94
7
- data.tar.gz: c6b392c72163d72bf23082699c4d4020bd1e86973f286a33a79eb9070a192d18a7ce86018be7322815a33f339eb8071e33f0bba26abd29297d573b504eca70e8
6
+ metadata.gz: 4bb06a14848520c8f1245731bee2ddabc66308628b5a7ffcee722afab44b52153fbbb27aa53bf7e8cd5b13781fc0d1d02aed7a3288688d9215d9c770aec98ea2
7
+ data.tar.gz: 0307a0be76a76bce43a328d1c5dd7049db317c09d896d3f3b7731ba62f32932df5c4cb87ea1d7e656f16c9d61fc446c08b44098e7c2845215c9fb324c7802882
data/README.md CHANGED
@@ -8,17 +8,9 @@ Ruby gem used to load, validate, and parse European Data Format files. Used for
8
8
 
9
9
  ## Installation
10
10
 
11
- Add this line to your application's Gemfile:
12
-
13
- gem 'edfize'
14
-
15
- And then execute:
16
-
17
- $ bundle
18
-
19
- Or install it yourself as:
11
+ Use `gem install edfize` to update Edfize to the latest stable
20
12
 
21
- $ gem install edfize
13
+ Use `gem install edfize --pre` to update Edfize to the latest prerelease
22
14
 
23
15
  ## Usage
24
16
 
@@ -58,12 +50,6 @@ Use `edfize version` to check the version of Edfize.
58
50
 
59
51
  edfize version
60
52
 
61
- ### Upgrade Edfize
62
-
63
- Use `gem install edfize` to update Edfize to the latest stable
64
-
65
- Use `gem install edfize --pre` to update Edfize to the latest prerelease
66
-
67
53
  ### Example of how to Load and Analyze EDFs in a Ruby Script
68
54
 
69
55
  The following Ruby file demonstrates how to make use of the Edfize gem to load EDF signals into arrays for analysis.
data/lib/edfize/edf.rb CHANGED
@@ -2,38 +2,49 @@ require 'edfize/signal'
2
2
 
3
3
  module Edfize
4
4
  class Edf
5
+ # EDF File Path
5
6
  attr_reader :filename
6
7
 
7
- attr_reader :reserved # 44 bytes - ASCII
8
- attr_reader :number_of_data_records # 8 bytes - ASCII
8
+ # Header Information
9
+ attr_reader :version
10
+ attr_reader :local_patient_identification
11
+ attr_reader :local_recording_identification
12
+ attr_reader :start_date_of_recording
13
+ attr_reader :start_time_of_recording
14
+ attr_reader :number_of_bytes_in_header
15
+ attr_reader :reserved
16
+ attr_reader :number_of_data_records
17
+ attr_reader :duration_of_a_data_record
18
+ attr_reader :number_of_signals
9
19
 
10
20
  attr_accessor :signals
11
21
 
12
- RESERVED_SIZE = 44
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(:+)
13
36
 
14
-
15
-
16
- HEADER_OFFSET = 256
17
37
  SIZE_OF_SAMPLE_IN_BYTES = 2
18
38
 
39
+ # Used by tests
40
+ RESERVED_SIZE = HEADER_CONFIG[:reserved][:size]
41
+
19
42
  def initialize(filename)
20
43
  @filename = filename
21
44
  @signals = []
22
45
 
23
46
  read_header
24
-
25
- # Other
26
- get_number_of_data_records
27
- signal_labels
28
- transducer_types
29
- physical_dimensions
30
- physical_minimums
31
- physical_maximums
32
- digital_minimums
33
- digital_maximums
34
- prefilterings
35
- samples_per_data_records
36
- reserved_areas
47
+ read_signal_header
37
48
  end
38
49
 
39
50
  def load_signals
@@ -41,11 +52,11 @@ module Edfize
41
52
  end
42
53
 
43
54
  def size_of_header
44
- HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8 + 8 + 80 + 8 + 32)
55
+ HEADER_OFFSET + ns * Signal::SIGNAL_CONFIG.collect{|k,h| h[:size]}.inject(:+)
45
56
  end
46
57
 
47
58
  def expected_size_of_header
48
- 256 + (ns * 256)
59
+ @number_of_bytes_in_header
49
60
  end
50
61
 
51
62
  # Total File Size In Bytes
@@ -62,32 +73,41 @@ module Edfize
62
73
  expected_data_size + size_of_header
63
74
  end
64
75
 
76
+ def section_value_to_string(section)
77
+ self.instance_variable_get("@#{section}").to_s
78
+ end
79
+
80
+ def section_units(section)
81
+ units = HEADER_CONFIG[section][:units].to_s
82
+ result = if units == ''
83
+ ''
84
+ else
85
+ " #{units}" + (self.instance_variable_get("@#{section}") == 1 ? '' : 's')
86
+ end
87
+ result
88
+ end
89
+
90
+ def section_description(section)
91
+ description = HEADER_CONFIG[section][:description].to_s
92
+ result = if description == ''
93
+ ''
94
+ else
95
+ " #{description}"
96
+ end
97
+ result
98
+ end
99
+
65
100
  def print_header
66
101
  puts "\nEDF : #{@filename}"
67
102
  puts "Total File Size : #{edf_size} bytes"
68
103
  puts "\nHeader Information"
69
- puts "Version : #{header_version}"
70
- puts "Local Patient Identification : #{header_local_patient_identification}"
71
- puts "Local Recording Identification : #{header_local_recording_identification}"
72
- puts "Start Date of Recording : #{header_start_date_of_recording} (dd.mm.yy)"
73
- puts "Start Time of Recording : #{header_start_time_of_recording} (hh.mm.ss)"
74
- puts "Reserved : '#{@reserved}'"
75
- puts "Number of Data Records : #{number_of_data_records}"
76
- puts "Duration of a Data Record : #{duration_of_a_data_record.to_i} second#{'s' unless duration_of_a_data_record.to_i == 1}"
77
- puts "Number of Signals (NS) : #{number_of_signals}"
104
+ HEADER_CONFIG.each do |section, hash|
105
+ puts "#{hash[:name]}#{' '*(31 - hash[:name].size)}: " + section_value_to_string(section) + section_units(section) + section_description(section)
106
+ end
78
107
  puts "\nSignal Information"
79
108
  signals.each_with_index do |signal, index|
80
109
  puts "\n Position : #{index + 1}"
81
- puts " Label : #{signal.label}"
82
- puts " Physical Dimension : #{signal.physical_dimension}"
83
- puts " Transducer Type : #{signal.transducer_type}"
84
- puts " Physical Minimum : #{signal.physical_minimum}"
85
- puts " Physical Maximum : #{signal.physical_maximum}"
86
- puts " Digital Minimum : #{signal.digital_minimum}"
87
- puts " Digital Maximum : #{signal.digital_maximum}"
88
- puts " Prefiltering : #{signal.prefiltering}"
89
- puts " Samples Per Data Record : #{signal.samples_per_data_record}"
90
- puts " Reserved Area : '#{signal.reserved_area}'"
110
+ signal.print_header
91
111
  end
92
112
  puts "\nGeneral Information"
93
113
  puts "Size of Header (bytes) : #{size_of_header}"
@@ -102,158 +122,65 @@ module Edfize
102
122
  protected
103
123
 
104
124
  def read_header
105
- read_reserved
106
- end
107
-
108
- def header_version
109
- IO.binread(@filename, 8)
110
- end
111
-
112
- # 80 ascii : local patient identification (mind item 3 of the additional EDF+ specs)
113
- def header_local_patient_identification
114
- IO.binread(@filename, 80, 8)
115
- end
116
-
117
- # 80 ascii : local recording identification (mind item 4 of the additional EDF+ specs)
118
- def header_local_recording_identification
119
- IO.binread(@filename, 80, 88)
120
- end
121
-
122
- # 8 ascii : startdate of recording (dd.mm.yy) (mind item 2 of the additional EDF+ specs)
123
- def header_start_date_of_recording
124
- IO.binread(@filename, 8, 168)
125
- end
126
-
127
- # 8 ascii : starttime of recording (hh.mm.ss)
128
- def header_start_time_of_recording
129
- IO.binread(@filename, 8, 176)
130
- end
131
-
132
- # 8 ascii : number of bytes in header record
133
- def number_of_bytes_in_header
134
- IO.binread(@filename, 8, 184)
135
- end
136
-
137
- # 44 ascii : reserved
138
- def read_reserved
139
- @reserved = IO.binread(@filename, RESERVED_SIZE, 192)
140
- end
141
-
142
- # 8 ascii : number of data records (-1 if unknown, obey item 10 of the additional EDF+ specs)
143
- def get_number_of_data_records
144
- @number_of_data_records = IO.binread(@filename, 8, RESERVED_SIZE + 192).to_i
145
- end
146
-
147
- # 8 ascii : duration of a data record, in seconds
148
- def duration_of_a_data_record
149
- IO.binread(@filename, 8, 244)
150
- end
151
-
152
- # 4 ascii : number of signals (ns) in data record
153
- def number_of_signals
154
- IO.binread(@filename, 4, 252)
155
- end
156
-
157
- def ns
158
- Integer(self.number_of_signals) rescue 0
159
- end
160
-
161
- # ns * 16 ascii : ns * label (e.g. EEG Fpz-Cz or Body temp) (mind item 9 of the additional EDF+ specs)
162
- def signal_labels
163
- offset = HEADER_OFFSET
164
- (0..ns-1).to_a.each do |signal_number|
165
- @signals[signal_number] ||= Signal.new()
166
- @signals[signal_number].label = IO.binread(@filename, 16, offset+(signal_number*16))
167
- end
168
- end
169
-
170
- # ns * 80 ascii : ns * transducer type (e.g. AgAgCl electrode)
171
- def transducer_types
172
- offset = HEADER_OFFSET + ns * 16
173
- (0..ns-1).to_a.each do |signal_number|
174
- @signals[signal_number] ||= Signal.new()
175
- @signals[signal_number].transducer_type = IO.binread(@filename, 80, offset+(signal_number*80))
176
- end
177
- end
178
-
179
- # ns * 8 ascii : ns * physical dimension (e.g. uV or degreeC)
180
- def physical_dimensions
181
- offset = HEADER_OFFSET + ns * (16 + 80)
182
- (0..ns-1).to_a.each do |signal_number|
183
- @signals[signal_number] ||= Signal.new()
184
- @signals[signal_number].physical_dimension = IO.binread(@filename, 8, offset+(signal_number*8))
125
+ HEADER_CONFIG.keys.each do |section|
126
+ read_header_section(section)
185
127
  end
186
128
  end
187
129
 
188
- # ns * 8 ascii : ns * physical minimum (e.g. -500 or 34)
189
- def physical_minimums
190
- offset = HEADER_OFFSET + ns * (16 + 80 + 8)
191
- (0..ns-1).to_a.each do |signal_number|
192
- @signals[signal_number] ||= Signal.new()
193
- @signals[signal_number].physical_minimum = IO.binread(@filename, 8, offset+(signal_number*8))
194
- end
130
+ def read_header_section(section)
131
+ result = IO.binread(@filename, HEADER_CONFIG[section][:size], compute_offset(section) )
132
+ result = result.to_s.send(HEADER_CONFIG[section][:after_read]) unless HEADER_CONFIG[section][:after_read].to_s == ''
133
+ self.instance_variable_set("@#{section}", result)
195
134
  end
196
135
 
197
- # ns * 8 ascii : ns * physical maximum (e.g. 500 or 40)
198
- def physical_maximums
199
- offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8)
200
- (0..ns-1).to_a.each do |signal_number|
201
- @signals[signal_number] ||= Signal.new()
202
- @signals[signal_number].physical_maximum = IO.binread(@filename, 8, offset+(signal_number*8))
136
+ def compute_offset(section)
137
+ offset = 0
138
+ HEADER_CONFIG.each do |key, hash|
139
+ break if key == section
140
+ offset += hash[:size]
203
141
  end
142
+ offset
204
143
  end
205
144
 
206
- # ns * 8 ascii : ns * digital minimum (e.g. -2048)
207
- def digital_minimums
208
- offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8)
209
- (0..ns-1).to_a.each do |signal_number|
210
- @signals[signal_number] ||= Signal.new()
211
- @signals[signal_number].digital_minimum = IO.binread(@filename, 8, offset+(signal_number*8))
212
- end
145
+ def ns
146
+ @number_of_signals
213
147
  end
214
148
 
215
- # ns * 8 ascii : ns * digital maximum (e.g. 2047)
216
- def digital_maximums
217
- offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8)
149
+ def create_signals
218
150
  (0..ns-1).to_a.each do |signal_number|
219
151
  @signals[signal_number] ||= Signal.new()
220
- @signals[signal_number].digital_maximum = IO.binread(@filename, 8, offset+(signal_number*8))
221
152
  end
222
153
  end
223
154
 
224
- # ns * 80 ascii : ns * prefiltering (e.g. HP:0.1Hz LP:75Hz)
225
- def prefilterings
226
- offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8 + 8)
227
- (0..ns-1).to_a.each do |signal_number|
228
- @signals[signal_number] ||= Signal.new()
229
- @signals[signal_number].prefiltering = IO.binread(@filename, 80, offset+(signal_number*80))
155
+ def read_signal_header
156
+ create_signals
157
+ Signal::SIGNAL_CONFIG.keys.each do |section|
158
+ read_signal_header_section(section)
230
159
  end
231
160
  end
232
161
 
233
- # ns * 8 ascii : ns * nr of samples in each data record
234
- def samples_per_data_records
235
- offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8 + 8 + 80)
236
- (0..ns-1).to_a.each do |signal_number|
237
- @signals[signal_number] ||= Signal.new()
238
- @signals[signal_number].samples_per_data_record = IO.binread(@filename, 8, offset+(signal_number*8)).to_i
239
- @signals[signal_number].samples = Array.new(@signals[signal_number].samples_per_data_record, 0)
162
+ def compute_signal_offset(section)
163
+ offset = 0
164
+ Signal::SIGNAL_CONFIG.each do |key, hash|
165
+ break if key == section
166
+ offset += hash[:size]
240
167
  end
168
+ offset
241
169
  end
242
170
 
243
- # ns * 32 ascii : ns * reserved
244
- def reserved_areas
245
- offset = HEADER_OFFSET + ns * (16 + 80 + 8 + 8 + 8 + 8 + 8 + 80 + 8)
171
+ def read_signal_header_section(section)
172
+ offset = HEADER_OFFSET + ns * compute_signal_offset(section)
246
173
  (0..ns-1).to_a.each do |signal_number|
247
- @signals[signal_number] ||= Signal.new()
248
- @signals[signal_number].reserved_area = IO.binread(@filename, 32, offset+(signal_number*32))
174
+ section_size = Signal::SIGNAL_CONFIG[section][:size]
175
+ result = IO.binread(@filename, section_size, offset+(signal_number*section_size))
176
+ result = result.to_s.send(Signal::SIGNAL_CONFIG[section][:after_read]) unless Signal::SIGNAL_CONFIG[section][:after_read].to_s == ''
177
+ @signals[signal_number].send("#{section}=", result)
249
178
  end
250
179
  end
251
180
 
252
-
253
- #
254
181
  def get_data_records
255
182
  current_read_offset = size_of_header
256
- (0..@number_of_data_records-1).to_a.each do |data_record_index|
183
+ (0..ns-1).to_a.each do |data_record_index|
257
184
  @signals.each do |signal|
258
185
  # 16-bit signed integer size = 2 Bytes = 2 ASCII characters
259
186
  read_size = signal.samples_per_data_record * SIZE_OF_SAMPLE_IN_BYTES
data/lib/edfize/signal.rb CHANGED
@@ -5,5 +5,29 @@ module Edfize
5
5
  :digital_minimum, :digital_maximum,
6
6
  :prefiltering, :samples_per_data_record,
7
7
  :reserved_area, :samples
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
+ }
21
+
22
+ def initialize
23
+ @samples = []
24
+ end
25
+
26
+ def print_header
27
+ SIGNAL_CONFIG.each do |section, hash|
28
+ puts " #{hash[:name]}#{' '*(29 - hash[:name].size)}: " + self.send(section).to_s
29
+ end
30
+ end
31
+
8
32
  end
9
33
  end
@@ -27,17 +27,6 @@ module Edfize
27
27
  results.each do |result|
28
28
  print_result(result)
29
29
  end
30
-
31
- # test_expected_length(edf) ? nil : failure_count += 1
32
- # test_count += 1
33
-
34
- # test_reserved_area_blank(edf) ? nil : failure_count += 1
35
- # test_count += 1
36
-
37
- # test_reserved_signal_areas_blank(edf) ? nil : failure_count += 1
38
- # test_count += 1
39
-
40
- # [test_count, failure_count]
41
30
  end
42
31
 
43
32
  def print_result(result)
@@ -3,7 +3,7 @@ module Edfize
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
5
  TINY = 0
6
- BUILD = "beta2"
6
+ BUILD = "beta3"
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, BUILD].compact.join('.')
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: edfize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta2
4
+ version: 0.1.0.beta3
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-05-01 00:00:00.000000000 Z
11
+ date: 2014-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize