edfize 0.1.0.beta8 → 0.1.0.pre

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: dea20df7bcf2794b479e5ad5265a88ccb7e9bcca
4
- data.tar.gz: 08d7115da77547f4363d16c345932713ffd95eb8
3
+ metadata.gz: 2067540b9f8f67b1f56d3b14932dd5941aaa8c5e
4
+ data.tar.gz: 78bd7d36d221cd07a77a9ecefb9b6f67b68d0f1c
5
5
  SHA512:
6
- metadata.gz: 22e2281613deed44e59b4ca6f7c489165583561b340420794ea79376def894bcf423a0d4f4ad1605182355cb707c418168a5897efa45a3101e2c55a388c6a390
7
- data.tar.gz: 95394c3fc72cee59a507325539d96a2a3caef54d21a3140015e8b858f68778154c4659df787dc97f4b4284a069d492aaf6af80b9eb6a36c45ca7a8c0a08328e4
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
- - `test`: Validates EDFs in the current directory and subdirectories for errors
5
- - To only show failing tests, add the flag `--failing`
6
- - `edfize test --failing`
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
- Use `gem install edfize` to update Edfize to the latest stable
11
+ Add this line to your application's Gemfile:
12
12
 
13
- Use `gem install edfize --pre` to update Edfize to the latest prerelease
13
+ gem 'edfize'
14
14
 
15
- ## Usage
15
+ And then execute:
16
16
 
17
- ### Validate EDFs
17
+ $ bundle
18
18
 
19
- Use `edfize test` to test that EDFs stored in the current directory have a valid format.
19
+ Or install it yourself as:
20
20
 
21
- cd <edf-directory>
22
- edfize test
21
+ $ gem install edfize
23
22
 
24
- A list of validations performed is:
23
+ ## Usage
25
24
 
26
- - **Expected Length Check**: Compares the calculated size of the file based on signal sizes defined in the header with the actual file size. A failure may indicate corruption in the header (if the expected is less than the actual file size), or a partial/truncated file (if the expected is more than the actual file size).
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
- Flags that can be added to the `test` command include:
27
+ Use `edfize check` to check that EDFs stored in the current directory have a valid format.
30
28
 
31
- - `--failing`: Only display EDFs with failing tests
32
- - `--quiet`: Suppress detailed failure descriptions that show the expected versus the actual result of the test
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 run
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
- ### Example of how to Load and Analyze EDFs in a Ruby Script
54
-
55
- The following Ruby file demonstrates how to make use of the Edfize gem to load EDF signals into arrays for analysis.
56
-
57
- `tutorial_01_load_edf_and_signals.rb`
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
- # EDF File Path
6
- attr_reader :filename
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
- read_header
53
- read_signal_header
54
- self
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 load_signals
58
- get_data_records
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 size_of_header
62
- HEADER_OFFSET + ns * Signal::SIGNAL_CONFIG.collect{|k,h| h[:size]}.inject(:+)
54
+ def header_version
55
+ IO.binread(@filename, 8)
63
56
  end
64
57
 
65
- def expected_size_of_header
66
- @number_of_bytes_in_header
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
- # Total File Size In Bytes
70
- def edf_size
71
- File.size(@filename)
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
- # Data Section Size In Bytes
75
- def expected_data_size
76
- @signals.collect(&:samples_per_data_record).inject(:+).to_i * @number_of_data_records * SIZE_OF_SAMPLE_IN_BYTES
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
- def expected_edf_size
80
- expected_data_size + size_of_header
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
- def section_value_to_string(section)
84
- self.instance_variable_get("@#{section}").to_s
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
- def section_units(section)
88
- units = HEADER_CONFIG[section][:units].to_s
89
- result = if units == ''
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
- def section_description(section)
98
- description = HEADER_CONFIG[section][:description].to_s
99
- result = if description == ''
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
- def print_header
108
- puts "\nEDF : #{@filename}"
109
- puts "Total File Size : #{edf_size} bytes"
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
- protected
130
-
131
- def read_header
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 read_header_section(section)
138
- result = IO.binread(@filename, HEADER_CONFIG[section][:size], compute_offset(section) )
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
- def compute_offset(section)
144
- offset = 0
145
- HEADER_CONFIG.each do |key, hash|
146
- break if key == section
147
- offset += hash[:size]
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
- def ns
153
- @number_of_signals
154
- end
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
- def read_signal_header
163
- create_signals
164
- Signal::SIGNAL_CONFIG.keys.each do |section|
165
- read_signal_header_section(section)
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
- def compute_signal_offset(section)
170
- offset = 0
171
- Signal::SIGNAL_CONFIG.each do |key, hash|
172
- break if key == section
173
- offset += hash[:size]
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
- def read_signal_header_section(section)
179
- offset = HEADER_OFFSET + ns * compute_signal_offset(section)
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
- section_size = Signal::SIGNAL_CONFIG[section][:size]
182
- result = IO.binread(@filename, section_size, offset+(signal_number*section_size))
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
- def get_data_records
189
- load_digital_signals()
190
- calculate_physical_values!()
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
- # 16-bit signed integer size = 2 Bytes = 2 ASCII characters
194
- # 16-bit signed integer in "Little Endian" format (least significant byte first)
195
- # unpack: s< 16-bit signed, (little-endian) byte order
196
- def load_digital_signals
197
- @all_signal_data = IO.binread(@filename, nil, size_of_header).unpack('s<*')
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
- (0..@number_of_data_records-1).to_a.each do |data_record_index|
210
- @signals.each_with_index do |signal, signal_index|
211
- read_start = data_record_index * total_samples_per_data_record + offsets[signal_index]
212
- (0..signal.samples_per_data_record - 1).to_a.each do |value_index|
213
- signal.digital_values << @all_signal_data[read_start+value_index]
214
- end
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
- def calculate_physical_values!
220
- @signals.each{|signal| signal.calculate_physical_values!}
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
- def data_size
224
- IO.binread(@filename, nil, size_of_header).size
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
- :physical_minimum, :physical_maximum,
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
- @digital_values = []
24
- @physical_values = []
25
- self
26
- end
27
-
28
- def self.create(&block)
29
- signal = self.new
30
- yield signal if block_given?
31
- signal
32
- end
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
@@ -3,7 +3,7 @@ module Edfize
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
5
  TINY = 0
6
- BUILD = "beta8"
6
+ BUILD = "pre"
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, BUILD].compact.join('.')
9
9
  end
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(argv[1..-1])
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
- edfs_in_current_directory_and_subdirectories.each do |edf_file_name|
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(argv)
35
- test_start_time = Time.now
36
- edf_count = edfs_in_current_directory_and_subdirectories.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
- [t]est Check EDFs in directory and subdirectories
57
- --failing Only display failing tests
58
- --quiet Suppress failing test descriptions
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.edfs_in_current_directory_and_subdirectories
71
- Dir.glob('**/*.edf')
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.beta8
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-05-07 00:00:00.000000000 Z
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
@@ -1,7 +0,0 @@
1
- module Edfize
2
- module Tests
3
- class Result
4
- attr_accessor :passes, :pass_fail, :expected, :actual
5
- end
6
- end
7
- end
@@ -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