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