edfize 0.1.0.beta2 → 0.1.0.beta3

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 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