spcore 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -37,6 +37,10 @@ Adjust project documentation.
37
37
 
38
38
  Update to be compatible with hashmake-0.1.6.
39
39
 
40
- === 0.1.7 2013-04-18
40
+ === 0.1.7 / 2013-04-18
41
41
 
42
- Require all sample rate args to be Fixnum.
42
+ Require all sample rate args to be Fixnum.
43
+
44
+ === 0.1.8 / 2013-05-03
45
+
46
+ Add Envelope and Extrema classes, for signal analysis.
@@ -24,6 +24,7 @@ A library of signal processing methods and classes.
24
24
  * Conversion from dB-linear and linear-dB
25
25
  * Oscillator with selectable wave type (sine, square, triangle, sawtooth)
26
26
  * Signal abstraction class
27
+ * Extrema & Envelope measurement
27
28
 
28
29
  == Examples
29
30
 
@@ -4,9 +4,10 @@ require 'spcore/version'
4
4
  require 'spcore/core/circular_buffer'
5
5
  require 'spcore/core/constants'
6
6
  require 'spcore/core/delay_line'
7
- require 'spcore/core/envelope_detector'
8
7
  require 'spcore/core/oscillator'
9
8
  require 'spcore/core/signal'
9
+ require 'spcore/core/extrema'
10
+ require 'spcore/core/envelope'
10
11
 
11
12
  require 'spcore/windows/bartlett_hann_window'
12
13
  require 'spcore/windows/bartlett_window'
@@ -48,3 +49,4 @@ require 'spcore/util/plotter'
48
49
  require 'spcore/util/saturation'
49
50
  require 'spcore/util/scale'
50
51
  require 'spcore/util/signal_generator'
52
+ require 'spcore/util/envelope_detector'
@@ -0,0 +1,58 @@
1
+ module SPCore
2
+ # Determines the envelope of given samples. Unlike the EnvelopeDetector, this
3
+ # operates on a signal (time-series data) after it is recieved, not
4
+ # sample-by-sample. As a result, it provides the envelope as an entire signal.
5
+ #
6
+ # @author James Tunnell
7
+ class Envelope < Signal
8
+
9
+ attr_reader :data
10
+
11
+ def initialize samples
12
+ # combine absolute values of positive maxima and negative minima
13
+ extrema = Extrema.new(samples)
14
+ points = {}
15
+ extrema.minima.each do |idx,val|
16
+ if val <= 0.0
17
+ points[idx] = val.abs
18
+ end
19
+ end
20
+
21
+ extrema.maxima.each do |idx,val|
22
+ if val >= 0.0
23
+ points[idx] = val.abs
24
+ end
25
+ end
26
+
27
+ # add in first and last samples so the envelope follows entire signal
28
+ points[0] = samples[0].abs
29
+ points[samples.count - 1] = samples[samples.count - 1].abs
30
+
31
+ indices = points.keys.sort
32
+ @data = Array.new(samples.count, 0)
33
+
34
+ # interpolate between all the extrema for the rest of the values. We
35
+ # manually added first/last index so the whole signal should be covered
36
+ # by this
37
+ for i in 1...indices.count
38
+ l_idx = indices[i-1]
39
+ r_idx = indices[i]
40
+
41
+ l_val = points[l_idx]
42
+ r_val = points[r_idx]
43
+
44
+ @data[l_idx] = l_val
45
+ @data[r_idx] = r_val
46
+
47
+ idx_span = r_idx - l_idx
48
+
49
+ for j in (l_idx + 1)...(r_idx)
50
+ x = (j - l_idx).to_f / idx_span
51
+ y = Interpolation.linear l_val, r_val, x
52
+ @data[j] = y
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,55 @@
1
+ module SPCore
2
+ # Finds extrema (minima and maxima).
3
+ class Extrema
4
+
5
+ attr_reader :minima, :maxima, :extrema
6
+
7
+ def initialize samples
8
+ @minima = {}
9
+ @maxima = {}
10
+
11
+ global_min_idx = 0
12
+ global_min_val = samples[0]
13
+ global_max_idx = 0
14
+ global_max_val = samples[0]
15
+
16
+ diffs = []
17
+ for i in (1...samples.count)
18
+ diffs.push(samples[i] - samples[i-1])
19
+
20
+ if samples[i] < global_min_val
21
+ global_min_idx = i
22
+ global_min_val = samples[i]
23
+ end
24
+
25
+ if samples[i] > global_max_val
26
+ global_max_idx = i
27
+ global_max_val = samples[i]
28
+ end
29
+ end
30
+ @minima[global_min_idx] = global_min_val
31
+ @maxima[global_max_idx] = global_max_val
32
+
33
+ is_positive = diffs.first > 0.0 # starting off with positive difference?
34
+
35
+ # at zero crossings there is a local maxima/minima
36
+ for i in (1...diffs.count)
37
+ if is_positive
38
+ # at positive-to-negative transition there is a local maxima
39
+ if diffs[i] <= 0.0
40
+ @maxima[i] = samples[i]
41
+ is_positive = false
42
+ end
43
+ else
44
+ # at negative-to-positive transition there is a local minima
45
+ if diffs[i] > 0.0
46
+ @minima[i] = samples[i]
47
+ is_positive = true
48
+ end
49
+ end
50
+ end
51
+
52
+ @extrema = @minima.merge(@maxima)
53
+ end
54
+ end
55
+ end
@@ -89,7 +89,7 @@ class Signal
89
89
  # polynomial interpolation.
90
90
  # @param [Fixnum] upsample_factor Increase the sample rate by this factor.
91
91
  def upsample_polynomial upsample_factor
92
- @data = PolynomialResampling.upsample @data, @sample_rate, upsample_factor
92
+ @data = PolynomialResampling.upsample @data, upsample_factor
93
93
  @sample_rate *= upsample_factor
94
94
  return self
95
95
  end
@@ -134,24 +134,14 @@ class Signal
134
134
  return @data.inject(0.0){|sum,x| sum + (x * x)}
135
135
  end
136
136
 
137
- # Return a
138
- def envelope attack_time, release_time
139
- raise ArgumentError, "attack_time #{attack_time } is less than or equal to zero" if attack_time <= 0.0
140
- raise ArgumentError, "release_time #{release_time} is less than or equal to zero" if release_time <= 0.0
141
-
142
- env_detector = EnvelopeDetector.new(:attack_time => attack_time, :release_time => release_time, :sample_rate => @sample_rate)
143
-
144
- envelope = Array.new(@data.count)
145
-
146
- for i in 0...@data.count do
147
- envelope[i] = env_detector.process_sample @data[i]
148
- end
149
-
150
- return envelope
137
+ # Determine the envelope of the current Signal and return the resulting data
138
+ # in a new Signal object.
139
+ def envelope
140
+ return Envelope.new(@data)
151
141
  end
152
142
 
153
143
  # Add data in array or other signal to the beginning of current data.
154
- def prepend other
144
+ def prepend! other
155
145
  if other.is_a?(Array)
156
146
  @data = other.concat @data
157
147
  elsif other.is_a?(Signal)
@@ -161,7 +151,7 @@ class Signal
161
151
  end
162
152
 
163
153
  # Add data in array or other signal to the end of current data.
164
- def append other
154
+ def append! other
165
155
  if other.is_a?(Array)
166
156
  @data = @data.concat other
167
157
  elsif other.is_a?(Signal)
@@ -173,7 +163,7 @@ class Signal
173
163
  # Add value, values in array, or values in other signal to the current
174
164
  # data values, and update the current data with the results.
175
165
  # @param other Can be Numeric (add same value to all data values), Array, or Signal.
176
- def +(other)
166
+ def add!(other)
177
167
  if other.is_a?(Numeric)
178
168
  @data.each_index do |i|
179
169
  @data[i] += other
@@ -193,11 +183,37 @@ class Signal
193
183
  end
194
184
  return self
195
185
  end
186
+
187
+ # Add value, values in array, or values in other signal to the current
188
+ # data values, and return a new Signal object with the results.
189
+ # @param other Can be Numeric (add same value to all data values), Array, or Signal.
190
+ def add(other)
191
+ new_data = Array.new(@data.size)
192
+
193
+ if other.is_a?(Numeric)
194
+ @data.each_index do |i|
195
+ new_data[i] = @data[i] + other
196
+ end
197
+ elsif other.is_a?(Signal)
198
+ raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
199
+ @data.each_index do |i|
200
+ new_data[i] = @data[i] + other.data[i]
201
+ end
202
+ elsif other.is_a?(Array)
203
+ raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
204
+ @data.each_index do |i|
205
+ new_data[i] = @data[i] + other[i]
206
+ end
207
+ else
208
+ raise ArgumentError, "other is not a Numeric, Signal, or Array"
209
+ end
210
+ return Signal.new(:data => new_data, :sample_rate => @sample_rate)
211
+ end
196
212
 
197
213
  # Subtract value, values in array, or values in other signal from the current
198
214
  # data values, and update the current data with the results.
199
215
  # @param other Can be Numeric (subtract same value from all data values), Array, or Signal.
200
- def -(other)
216
+ def subtract!(other)
201
217
  if other.is_a?(Numeric)
202
218
  @data.each_index do |i|
203
219
  @data[i] -= other
@@ -218,11 +234,37 @@ class Signal
218
234
  return self
219
235
  end
220
236
 
237
+ # Subtract value, values in array, or values in other signal from the current
238
+ # data values, and return a new Signal object with the results.
239
+ # @param other Can be Numeric (subtract same value from all data values), Array, or Signal.
240
+ def subtract(other)
241
+ new_data = Array.new(@data.size)
242
+
243
+ if other.is_a?(Numeric)
244
+ @data.each_index do |i|
245
+ new_data[i] = @data[i] - other
246
+ end
247
+ elsif other.is_a?(Signal)
248
+ raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
249
+ @data.each_index do |i|
250
+ new_data[i] = @data[i] - other.data[i]
251
+ end
252
+ elsif other.is_a?(Array)
253
+ raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
254
+ @data.each_index do |i|
255
+ new_data[i] = @data[i] - other[i]
256
+ end
257
+ else
258
+ raise ArgumentError, "other is not a Numeric, Signal, or Array"
259
+ end
260
+ return Signal.new(:data => new_data, :sample_rate => @sample_rate)
261
+ end
262
+
221
263
  # Multiply value, values in array, or values in other signal with the current
222
264
  # data values, and update the current data with the results.
223
265
  # @param other Can be Numeric (multiply all data values by the same value),
224
266
  # Array, or Signal.
225
- def *(other)
267
+ def multiply!(other)
226
268
  if other.is_a?(Numeric)
227
269
  @data.each_index do |i|
228
270
  @data[i] *= other
@@ -243,11 +285,38 @@ class Signal
243
285
  return self
244
286
  end
245
287
 
288
+ # Multiply value, values in array, or values in other signal with the current
289
+ # data values, and return a new Signal object with the results.
290
+ # @param other Can be Numeric (multiply all data values by the same value),
291
+ # Array, or Signal.
292
+ def multiply(other)
293
+ new_data = Array.new(@data.size)
294
+
295
+ if other.is_a?(Numeric)
296
+ @data.each_index do |i|
297
+ new_data[i] = @data[i] * other
298
+ end
299
+ elsif other.is_a?(Signal)
300
+ raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
301
+ @data.each_index do |i|
302
+ new_data[i] = @data[i] * other.data[i]
303
+ end
304
+ elsif other.is_a?(Array)
305
+ raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
306
+ @data.each_index do |i|
307
+ new_data[i] = @data[i] * other[i]
308
+ end
309
+ else
310
+ raise ArgumentError, "other is not a Numeric, Signal, or Array"
311
+ end
312
+ return Signal.new(:data => new_data, :sample_rate => @sample_rate)
313
+ end
314
+
246
315
  # Divide value, values in array, or values in other signal into the current
247
316
  # data values, and update the current data with the results.
248
317
  # @param other Can be Numeric (divide same all data values by the same value),
249
318
  # Array, or Signal.
250
- def /(other)
319
+ def divide!(other)
251
320
  if other.is_a?(Numeric)
252
321
  @data.each_index do |i|
253
322
  @data[i] /= other
@@ -268,10 +337,37 @@ class Signal
268
337
  return self
269
338
  end
270
339
 
271
- alias_method :add, :+
272
- alias_method :subtract, :-
273
- alias_method :multiply, :*
274
- alias_method :divide, :/
340
+ # Divide value, values in array, or values in other signal into the current
341
+ # data values, and return a new Signal object with the results.
342
+ # @param other Can be Numeric (divide same all data values by the same value),
343
+ # Array, or Signal.
344
+ def divide(other)
345
+ new_data = Array.new(@data.size)
346
+
347
+ if other.is_a?(Numeric)
348
+ @data.each_index do |i|
349
+ new_data[i] = @data[i] / other
350
+ end
351
+ elsif other.is_a?(Signal)
352
+ raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
353
+ @data.each_index do |i|
354
+ new_data[i] = @data[i] / other.data[i]
355
+ end
356
+ elsif other.is_a?(Array)
357
+ raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
358
+ @data.each_index do |i|
359
+ new_data[i] = @data[i] / other[i]
360
+ end
361
+ else
362
+ raise ArgumentError, "other is not a Numeric, Signal, or Array"
363
+ end
364
+ return Signal.new(:data => new_data, :sample_rate => @sample_rate)
365
+ end
366
+
367
+ alias_method :+, :add
368
+ alias_method :-, :subtract
369
+ alias_method :*, :multiply
370
+ alias_method :/, :divide
275
371
 
276
372
  # Determine how well the another signal (g) correlates to the current signal (f).
277
373
  # Correlation is determined at every point in f. The signal g must not be
@@ -1,17 +1,17 @@
1
1
  module SPCore
2
2
  # Provide interpolation methods, including linear and polynomial.
3
3
  class Interpolation
4
- # Linear Interpolation Equation:
5
- #
6
- # (x3 - x1)(y2 - y1)
7
- # y3 = ------------------ + y1
8
- # (x2 - x1)
9
- #
10
- def self.linear x1, y1, x2, y2, x3
11
- y3 = ((x3 - x1) * (y2 - y1)) / (x2 - x1);
12
- y3 += y1;
13
- return y3;
14
- end
4
+ ## Linear Interpolation Equation:
5
+ ##
6
+ ## (x3 - x1)(y2 - y1)
7
+ ## y3 = ------------------ + y1
8
+ ## (x2 - x1)
9
+ ##
10
+ #def self.linear x1, y1, x2, y2, x3
11
+ # y3 = ((x3 - x1) * (y2 - y1)) / (x2 - x1);
12
+ # y3 += y1;
13
+ # return y3;
14
+ #end
15
15
 
16
16
  # Linear interpolator
17
17
  # Given 2 sample points, interpolates a value anywhere between the two points.
@@ -9,7 +9,7 @@ class HybridResampling
9
9
  raise ArgumentError, "downsample_factor is not greater than 1" unless downsample_factor > 1
10
10
  raise ArgumentError, "sample_rate is not greater than 0" unless sample_rate > 0
11
11
 
12
- upsampled = PolynomialResampling.upsample input, sample_rate, upsample_factor
12
+ upsampled = PolynomialResampling.upsample input, upsample_factor
13
13
 
14
14
  needed_samples = upsampled.size % downsample_factor
15
15
  if needed_samples == 0
@@ -3,10 +3,9 @@ module SPCore
3
3
  # polynomial interpolation.
4
4
  class PolynomialResampling
5
5
 
6
- def self.upsample input, sample_rate, upsample_factor
6
+ def self.upsample input, upsample_factor
7
7
  raise ArgumentError, "input.size is less than four" unless input.size >= 4
8
8
  raise ArgumentError, "upsample_factor is not greater than 1" unless upsample_factor > 1
9
- raise ArgumentError, "sample_rate is not greater than 0" unless sample_rate > 0
10
9
 
11
10
  output = Array.new((upsample_factor * input.size).to_i)
12
11
 
@@ -33,7 +33,14 @@ class Plotter
33
33
  def plot_2d titled_hashes
34
34
  datasets = []
35
35
  titled_hashes.each do |title, hash|
36
- dataset = Gnuplot::DataSet.new( [hash.keys, hash.values] ){ |ds|
36
+ # sort the data
37
+
38
+ sorted = {}
39
+ hash.keys.sort.each do |key|
40
+ sorted[key] = hash[key]
41
+ end
42
+
43
+ dataset = Gnuplot::DataSet.new( [sorted.keys, sorted.values] ){ |ds|
37
44
  ds.with = @linestyle
38
45
  ds.title = title
39
46
  ds.linewidth = @linewidth
@@ -35,8 +35,8 @@ class SignalGenerator
35
35
  oscs.push Oscillator.new args.merge(:frequency => freq)
36
36
  end
37
37
 
38
- output = Array.new(size, 0.0)
39
- size.times do |n|
38
+ output = Array.new(@size, 0.0)
39
+ @size.times do |n|
40
40
  oscs.each do |osc|
41
41
  output[n] += osc.sample
42
42
  end
@@ -1,5 +1,5 @@
1
1
  # A library of signal processing methods and classes.
2
2
  module SPCore
3
3
  # spcore version
4
- VERSION = "0.1.7"
4
+ VERSION = "0.1.8"
5
5
  end
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe SPCore::Envelope do
4
+ it 'should produce an output that follows the amplitude of the input' do
5
+ sample_rate = 400
6
+ sample_count = sample_rate
7
+ generator = SignalGenerator.new(:size => sample_count, :sample_rate => sample_rate)
8
+ base_signal = generator.make_signal [sample_rate / 5.0]
9
+ modulation_signal = generator.make_signal [sample_rate / 80.0]
10
+ base_signal.multiply! modulation_signal
11
+
12
+ envelope = base_signal.envelope
13
+
14
+ Plotter.new(
15
+ :title => "signal and envelope",
16
+ :xlabel => "sample",
17
+ :ylabel => "values",
18
+ ).plot_1d(
19
+ "signal" => base_signal.data,
20
+ "modulation" => modulation_signal.data,
21
+ "envelope" => envelope.data,
22
+ )
23
+
24
+ max_diff = 0.1
25
+ sample_count.times do |n|
26
+ envelope.data[n].should be_within(max_diff).of(modulation_signal.data[n].abs)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe SPCore::Extrema do
4
+ context '#minima' do
5
+ it 'should return points where local and global minima occur' do
6
+ cases = {
7
+ [3.8, 3.0, 2.9, 2.95, 3.6, 3.4, 2.8, 2.3, 2.1, 2.0, 2.5] => { 2 => 2.9, 9 => 2.0 },
8
+ [3.2, 3.5, 2.9, 2.7, 2.8, 2.7, 2.5, 2.2, 2.4, 2.3, 2.0] => { 3 => 2.7, 7 => 2.2, 10 => 2.0 },
9
+ }
10
+
11
+ cases.each do |samples, minima|
12
+ Extrema.new(samples).minima.should eq minima
13
+ end
14
+ end
15
+ end
16
+
17
+ context '#maxima' do
18
+ it 'should return points where local and global maxima occur' do
19
+ cases = {
20
+ [3.8, 3.0, 2.9, 2.95, 3.6, 3.4, 2.8, 2.3, 2.1, 2.0, 2.5] => { 0 => 3.8, 4 => 3.6 },
21
+ [3.2, 3.5, 2.9, 2.7, 2.8, 2.7, 2.5, 2.2, 2.4, 2.3, 2.0] => { 1 => 3.5, 4 => 2.8, 8 => 2.4},
22
+ }
23
+
24
+ cases.each do |samples, maxima|
25
+ Extrema.new(samples).maxima.should eq maxima
26
+ end
27
+ end
28
+ end
29
+
30
+ context '#extrema' do
31
+ it 'should return points where local and global extrema occur' do
32
+ cases = {
33
+ [3.8, 3.0, 2.9, 2.95, 3.6, 3.4, 2.8, 2.3, 2.1, 2.0, 2.5] => { 0 => 3.8, 2 => 2.9, 4 => 3.6, 9 => 2.0},
34
+ [3.2, 3.5, 2.9, 2.7, 2.8, 2.7, 2.5, 2.2, 2.4, 2.3, 2.0] => { 1 => 3.5, 3 => 2.7, 4 => 2.8, 7 => 2.2, 8 => 2.4, 10 => 2.0},
35
+ }
36
+
37
+ cases.each do |samples, extrema|
38
+ Extrema.new(samples).extrema.should eq extrema
39
+ end
40
+ end
41
+ end
42
+ end
@@ -8,7 +8,7 @@ describe SPCore::HybridResampling do
8
8
  sample_rate = 400
9
9
  test_freq = 10.0
10
10
  size = 64
11
- upsample_factor = 4
11
+ upsample_factor = 10
12
12
  downsample_factor = 4
13
13
  order = (sample_rate / test_freq).to_i
14
14
 
@@ -16,7 +16,7 @@ describe SPCore::HybridResampling do
16
16
  signal1 *= BlackmanWindow.new(size).data
17
17
  signal2 = signal1.clone.resample_hybrid upsample_factor, downsample_factor, order
18
18
 
19
- #plotter = Plotter.new(:title => "Discrete resampling, up by #{upsampling_factor}, down by #{downsample_factor}")
19
+ #plotter = Plotter.new(:title => "Discrete resampling, up by #{upsample_factor}, down by #{downsample_factor}")
20
20
  #plotter.plot_1d("original signal" => signal1.data, "resampled signal" => signal2.data)
21
21
 
22
22
  signal2.size.should eq(signal1.size * upsample_factor / downsample_factor)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spcore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-18 00:00:00.000000000 Z
12
+ date: 2013-05-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hashmake
@@ -147,7 +147,8 @@ files:
147
147
  - lib/spcore/core/circular_buffer.rb
148
148
  - lib/spcore/core/constants.rb
149
149
  - lib/spcore/core/delay_line.rb
150
- - lib/spcore/core/envelope_detector.rb
150
+ - lib/spcore/core/envelope.rb
151
+ - lib/spcore/core/extrema.rb
151
152
  - lib/spcore/core/oscillator.rb
152
153
  - lib/spcore/core/signal.rb
153
154
  - lib/spcore/filters/fir/dual_sinc_filter.rb
@@ -165,6 +166,7 @@ files:
165
166
  - lib/spcore/resampling/polynomial_resampling.rb
166
167
  - lib/spcore/transforms/dft.rb
167
168
  - lib/spcore/transforms/fft.rb
169
+ - lib/spcore/util/envelope_detector.rb
168
170
  - lib/spcore/util/gain.rb
169
171
  - lib/spcore/util/limiters.rb
170
172
  - lib/spcore/util/plotter.rb
@@ -189,7 +191,8 @@ files:
189
191
  - spcore.gemspec
190
192
  - spec/core/circular_buffer_spec.rb
191
193
  - spec/core/delay_line_spec.rb
192
- - spec/core/envelope_detector_spec.rb
194
+ - spec/core/envelope_spec.rb
195
+ - spec/core/extrema_spec.rb
193
196
  - spec/core/oscillator_spec.rb
194
197
  - spec/filters/fir/dual_sinc_filter_spec.rb
195
198
  - spec/filters/fir/sinc_filter_spec.rb
@@ -202,6 +205,7 @@ files:
202
205
  - spec/spec_helper.rb
203
206
  - spec/transforms/dft_spec.rb
204
207
  - spec/transforms/fft_spec.rb
208
+ - spec/util/envelope_detector_spec.rb
205
209
  - spec/util/gain_spec.rb
206
210
  - spec/util/limiters_spec.rb
207
211
  - spec/util/saturate_spec.rb
@@ -222,7 +226,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
222
226
  version: '0'
223
227
  segments:
224
228
  - 0
225
- hash: 407745007
229
+ hash: -1351761362878137001
226
230
  required_rubygems_version: !ruby/object:Gem::Requirement
227
231
  none: false
228
232
  requirements:
@@ -231,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
235
  version: '0'
232
236
  segments:
233
237
  - 0
234
- hash: 407745007
238
+ hash: -1351761362878137001
235
239
  requirements: []
236
240
  rubyforge_project:
237
241
  rubygems_version: 1.8.23
@@ -241,7 +245,8 @@ summary: A library of signal processing methods and classes.
241
245
  test_files:
242
246
  - spec/core/circular_buffer_spec.rb
243
247
  - spec/core/delay_line_spec.rb
244
- - spec/core/envelope_detector_spec.rb
248
+ - spec/core/envelope_spec.rb
249
+ - spec/core/extrema_spec.rb
245
250
  - spec/core/oscillator_spec.rb
246
251
  - spec/filters/fir/dual_sinc_filter_spec.rb
247
252
  - spec/filters/fir/sinc_filter_spec.rb
@@ -254,6 +259,7 @@ test_files:
254
259
  - spec/spec_helper.rb
255
260
  - spec/transforms/dft_spec.rb
256
261
  - spec/transforms/fft_spec.rb
262
+ - spec/util/envelope_detector_spec.rb
257
263
  - spec/util/gain_spec.rb
258
264
  - spec/util/limiters_spec.rb
259
265
  - spec/util/saturate_spec.rb