jphastings-PLW-Parse 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/plw.rb +151 -0
  2. metadata +53 -0
data/plw.rb ADDED
@@ -0,0 +1,151 @@
1
+ # A hacked up class for parsing the PLW data format from PicoTech (for their Oscilloscope data). Its not meant for speed but (constructive :P) criticism and ideas are welcome!
2
+ class PLW
3
+ attr_reader :signature,:version,:params,:PLS
4
+ attr_reader :sample_num,:no_samples,:max_samples,:interval,:trigger_sample,:triggered,:first_sample,:sample_length,:setting_byte,:start_date,:start_time,:min_time,:max_time,:notes,:current_time
5
+ attr_accessor :current_sample
6
+
7
+ # Will take a filename or a file handle (eg. <tt>"filename.plw"</tt> or <tt>open("filename.plw")</tt>)
8
+ def initialize(filename_or_handle)
9
+ if filename_or_handle.is_a?(File)
10
+ @file = filename_or_handle
11
+ elsif filename_or_handle.is_a?(String)
12
+ if File.exists? filename_or_handle
13
+ @file = open(filename_or_handle)
14
+ else
15
+ raise "File does not exist: #{filename_or_handle}"
16
+ end
17
+ else
18
+ raise "You need to pass a filename or a File object"
19
+ end
20
+
21
+ parseHeader
22
+ end
23
+
24
+ # Spins the file on to the byte position immediately after the given sample number
25
+ def current_sample=(sample_num)
26
+ if sample_num > @no_samples or sample_num < 0
27
+ return false
28
+ end
29
+ # 4 bytes for each paramter, 4 for the time. This bundle sample_num times,
30
+ # plus the header length is the byte position of the end of that sample
31
+ position = (@no_params * 4 + 4) * sample_num + @header_length
32
+
33
+ @file.seek(position)
34
+ @current_sample = sample_num
35
+ end
36
+
37
+ # Reconstructs the PLS data file used when measuring this data. Parses into a multi-level hash.
38
+ def PLS
39
+ if @pls.nil?
40
+ wasat = @file.pos
41
+ self.current_sample = @no_samples
42
+ @pls = {}
43
+ section = nil
44
+ @file.read.split(/\r\n/).each do |line|
45
+ if line =~ /^\[(.+?)\]$/
46
+ section = {}
47
+ @pls[$1] = section
48
+ elsif line =~ /^(.+)=(.+)$/
49
+ section[$1] = $2
50
+ else
51
+ # Unknown Data format
52
+ end
53
+ end
54
+ @file.seek(wasat)
55
+ @pls
56
+ else
57
+ @pls
58
+ end
59
+ end
60
+
61
+ # Returns <tt>n</tt> samples as Hashes, each hash containing:
62
+ # * :time : The time offset of this sample, in seconds
63
+ # * :data : The data for each channel as a hash
64
+ def getSamples(n=1)
65
+ if (@current_sample + n > @no_samples)
66
+ n = @no_samples - @current_sample
67
+ if n < 1
68
+ return false
69
+ end
70
+ end
71
+
72
+ Hash[*(@current_sample+1).upto(@current_sample += n).collect{ |sample_num| [sample_num,{:time => getuint32*@interval_units,:data => @no_params.times.collect { |param_index| getFloat() } }]}.flatten]
73
+ end
74
+
75
+ # A convenience method that just gives the next sample only
76
+ def getSample
77
+ getSamples(1).to_a[0][1]
78
+ end
79
+
80
+ private
81
+
82
+ def getbytes(numbytes)
83
+ data = ""
84
+ numbytes.times do |time|
85
+ data<<@file.getbyte
86
+ end
87
+ data
88
+ end
89
+
90
+ def getFloat
91
+ getbytes(4).unpack("e4")[0]
92
+ end
93
+
94
+ def getuint16
95
+ getbytes(2).unpack("v")[0]
96
+ end
97
+
98
+ def getuint32
99
+ getbytes(4).unpack("V")[0]
100
+ end
101
+
102
+ def parseHeader
103
+ @header_length = getuint16()
104
+ @signature = getbytes(40).strip
105
+ @version = getuint32()
106
+ @no_params = getuint32()
107
+ @params = {}
108
+ @no_params.times do |param_index|
109
+ @params[param_index] = getuint16
110
+ end
111
+ getbytes(2*(250 - @no_params)) # The remaining params aren't used
112
+ @sample_num = getuint32() # Same as @no_samples unless wraparound occured
113
+ @no_samples = getuint32() + 415 # Why?! Its not reporting the right length for some reason...
114
+ @max_samples = getuint32()
115
+ @interval = getuint32()
116
+ case getuint16() # next 16 bits are the 'interval unit'
117
+ when 0 # Femtoseconds
118
+ @interval_units = 1e-15
119
+ when 1 # ASSUMED Picosecond
120
+ @interval_units = 1e-12
121
+ when 2 # ASSUMED Nanosecond
122
+ @interval_units = 1e-9
123
+ when 3 # ASSUMED Millisecond
124
+ @interval_units = 1e-6
125
+ when 4 # Milliseconds
126
+ @interval_units = 1e-3
127
+ when 5 # Seconds
128
+ # We're in seconds
129
+ when 6 # Minutes
130
+ @interval_units = 60
131
+ when 7
132
+ @interval_units = 3600
133
+ else
134
+ raise "The units weren't specified correctly in the header file"
135
+ end
136
+ @interval *= @interval_units
137
+ @trigger_sample = getuint32()
138
+ @triggered = getuint16()
139
+ @first_sample = getuint32()
140
+ @sample_length = getuint32()
141
+ @setting_byte = getuint32()
142
+ @start_date = getuint32()
143
+ @start_time = getuint32()
144
+ @min_time = getuint32()
145
+ @max_time = getuint32()
146
+ @notes = getbytes(1000)
147
+ @current_time = getuint32()
148
+ getbytes(78) # Spare
149
+ @current_sample = 0 # We're currently after sample number 0. ie. the first sample is sample '1'
150
+ end
151
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jphastings-PLW-Parse
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - JP Hastings-Spital
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-11 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: contact@projects.kedakai.co.uk
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - plw.rb
26
+ has_rdoc: true
27
+ homepage: http://wiki.github.com/jphastings/plw-parse
28
+ post_install_message:
29
+ rdoc_options: []
30
+
31
+ require_paths:
32
+ - .
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: "0"
38
+ version:
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ requirements: []
46
+
47
+ rubyforge_project:
48
+ rubygems_version: 1.2.0
49
+ signing_key:
50
+ specification_version: 2
51
+ summary: ""
52
+ test_files: []
53
+