spcore 0.1.2 → 0.1.3
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.
- data/ChangeLog.rdoc +14 -1
- data/README.rdoc +10 -2
- data/lib/spcore.rb +45 -14
- data/lib/spcore/{lib → core}/circular_buffer.rb +28 -1
- data/lib/spcore/core/constants.rb +7 -1
- data/lib/spcore/{lib → core}/delay_line.rb +15 -5
- data/lib/spcore/{lib → core}/envelope_detector.rb +13 -1
- data/lib/spcore/{lib → core}/oscillator.rb +33 -3
- data/lib/spcore/core/signal.rb +350 -0
- data/lib/spcore/filters/fir/dual_sinc_filter.rb +84 -0
- data/lib/spcore/filters/fir/fir.rb +87 -0
- data/lib/spcore/filters/fir/sinc_filter.rb +68 -0
- data/lib/spcore/{lib → filters/iir}/biquad_filter.rb +7 -0
- data/lib/spcore/{lib → filters/iir}/cookbook_allpass_filter.rb +2 -0
- data/lib/spcore/{lib → filters/iir}/cookbook_bandpass_filter.rb +2 -0
- data/lib/spcore/{lib → filters/iir}/cookbook_highpass_filter.rb +2 -0
- data/lib/spcore/{lib → filters/iir}/cookbook_lowpass_filter.rb +2 -0
- data/lib/spcore/{lib → filters/iir}/cookbook_notch_filter.rb +2 -0
- data/lib/spcore/interpolation/interpolation.rb +64 -0
- data/lib/spcore/resampling/discrete_resampling.rb +78 -0
- data/lib/spcore/resampling/hybrid_resampling.rb +30 -0
- data/lib/spcore/resampling/polynomial_resampling.rb +56 -0
- data/lib/spcore/transforms/dft.rb +47 -0
- data/lib/spcore/transforms/fft.rb +125 -0
- data/lib/spcore/{lib → util}/gain.rb +3 -0
- data/lib/spcore/{core → util}/limiters.rb +10 -1
- data/lib/spcore/util/plotter.rb +91 -0
- data/lib/spcore/{lib → util}/saturation.rb +2 -9
- data/lib/spcore/util/scale.rb +41 -0
- data/lib/spcore/util/signal_generator.rb +48 -0
- data/lib/spcore/version.rb +2 -1
- data/lib/spcore/windows/bartlett_hann_window.rb +15 -0
- data/lib/spcore/windows/bartlett_window.rb +13 -0
- data/lib/spcore/windows/blackman_harris_window.rb +14 -0
- data/lib/spcore/windows/blackman_nuttall_window.rb +14 -0
- data/lib/spcore/windows/blackman_window.rb +18 -0
- data/lib/spcore/windows/cosine_window.rb +13 -0
- data/lib/spcore/windows/flat_top_window.rb +27 -0
- data/lib/spcore/windows/gaussian_window.rb +15 -0
- data/lib/spcore/windows/hamming_window.rb +16 -0
- data/lib/spcore/windows/hann_window.rb +13 -0
- data/lib/spcore/windows/lanczos_window.rb +15 -0
- data/lib/spcore/windows/nuttall_window.rb +14 -0
- data/lib/spcore/windows/rectangular_window.rb +10 -0
- data/lib/spcore/windows/triangular_window.rb +14 -0
- data/spcore.gemspec +11 -3
- data/spec/{lib → core}/circular_buffer_spec.rb +0 -0
- data/spec/{lib → core}/delay_line_spec.rb +1 -1
- data/spec/{lib → core}/envelope_detector_spec.rb +3 -3
- data/spec/{lib → core}/oscillator_spec.rb +0 -0
- data/spec/filters/fir/dual_sinc_filter_spec.rb +64 -0
- data/spec/filters/fir/sinc_filter_spec.rb +57 -0
- data/spec/filters/iir/cookbook_filter_spec.rb +30 -0
- data/spec/interpolation/interpolation_spec.rb +49 -0
- data/spec/resampling/discrete_resampling_spec.rb +81 -0
- data/spec/resampling/hybrid_resampling_spec.rb +31 -0
- data/spec/resampling/polynomial_resampling_spec.rb +30 -0
- data/spec/transforms/dft_spec.rb +71 -0
- data/spec/transforms/fft_spec.rb +84 -0
- data/spec/{lib → util}/gain_spec.rb +2 -2
- data/spec/{core → util}/limiters_spec.rb +0 -0
- data/spec/{lib → util}/saturate_spec.rb +0 -0
- data/spec/util/signal_generator_spec.rb +54 -0
- data/spec/windows/window_spec.rb +33 -0
- metadata +90 -42
- data/lib/spcore/lib/interpolation.rb +0 -15
- data/spec/lib/cookbook_filter_spec.rb +0 -44
- data/spec/lib/interpolation_spec.rb +0 -21
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
require 'gnuplot'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
describe 'cookbook filter' do
|
6
|
+
it 'should produce a nice frequency response graph' do
|
7
|
+
#sample_rate = 4000.0
|
8
|
+
#crit_freq = 400.0
|
9
|
+
#min_test_freq = 10.0
|
10
|
+
#max_test_freq = (sample_rate / 2.0) - 1.0
|
11
|
+
#bw = 0.3
|
12
|
+
#
|
13
|
+
#[SPCore::CookbookLowpassFilter, SPCore::CookbookHighpassFilter, SPCore::CookbookBandpassFilter].each do |filter_class|
|
14
|
+
# filter = filter_class.new sample_rate
|
15
|
+
# filter.set_critical_freq_and_bw crit_freq, bw
|
16
|
+
#
|
17
|
+
# freq_response = {}
|
18
|
+
# Scale.exponential(min_test_freq..max_test_freq, 200).each do |freq|
|
19
|
+
# mag = filter.get_freq_magnitude_response freq
|
20
|
+
# freq_response[freq] = SPCore::Gain.linear_to_db(mag)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# plotter = Plotter.new(
|
24
|
+
# :title => "Frequency Magnitude Response for #{filter_class} with critical freq of #{crit_freq}",
|
25
|
+
# :logscale => "x"
|
26
|
+
# )
|
27
|
+
# plotter.plot_2d "magnitude (dB)" => freq_response
|
28
|
+
#end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'benchmark'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
describe SPCore::Interpolation do
|
6
|
+
context '.linear' do
|
7
|
+
it 'should interpolate floating-point values' do
|
8
|
+
result = SPCore::Interpolation.linear 2.0, 4.0, 0.5
|
9
|
+
result.should eq(3.0)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should interpolate integer values' do
|
13
|
+
result = SPCore::Interpolation.linear 20, 40, 0.5
|
14
|
+
result.should eq(30)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context '.cubic_hermite' do
|
19
|
+
it 'should look like...' do
|
20
|
+
y0, y1, y2, y3 = 1.75, 1, 0.75, -1.5
|
21
|
+
|
22
|
+
x_ary = []
|
23
|
+
y_ary = []
|
24
|
+
|
25
|
+
(0.0..1.0).step(0.05) do |x|
|
26
|
+
y = SPCore::Interpolation.cubic_hermite y0, y1, y2, y3, x
|
27
|
+
x_ary << x
|
28
|
+
y_ary << y
|
29
|
+
end
|
30
|
+
|
31
|
+
#Gnuplot.open do |gp|
|
32
|
+
# Gnuplot::Plot.new(gp) do |plot|
|
33
|
+
# plot.title "interpolated values"
|
34
|
+
# plot.xlabel "x"
|
35
|
+
# plot.ylabel "f(x)"
|
36
|
+
#
|
37
|
+
# plot.data = [
|
38
|
+
# Gnuplot::DataSet.new( [ x_ary, y_ary ] ) { |ds|
|
39
|
+
# ds.with = "linespoints"
|
40
|
+
# ds.title = "cubic hermite"
|
41
|
+
# ds.linewidth = 1
|
42
|
+
# }
|
43
|
+
# ]
|
44
|
+
# end
|
45
|
+
#end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'gnuplot'
|
3
|
+
|
4
|
+
describe SPCore::DiscreteResampling do
|
5
|
+
|
6
|
+
context '.upsample' do
|
7
|
+
it 'should produce output signal with the same max frequency (put through forward FFT)' do
|
8
|
+
sample_rate = 400.0
|
9
|
+
test_freq = 10.0
|
10
|
+
size = 64
|
11
|
+
upsample_factor = 4
|
12
|
+
order = (sample_rate / test_freq).to_i
|
13
|
+
|
14
|
+
signal1 = SignalGenerator.new(:sample_rate => sample_rate, :size => size).make_signal [test_freq]
|
15
|
+
signal1 *= BlackmanWindow.new(size).data
|
16
|
+
signal2 = signal1.clone.upsample_discrete upsample_factor, order
|
17
|
+
|
18
|
+
#plotter = Plotter.new(:title => "Discrete upsampling by #{upsample_factor}")
|
19
|
+
#plotter.plot_1d("original signal" => signal1.data, "upsampled signal" => signal2.data)
|
20
|
+
|
21
|
+
signal2.size.should eq(signal1.size * upsample_factor)
|
22
|
+
|
23
|
+
max_freq1 = signal1.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
24
|
+
max_freq2 = signal2.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
25
|
+
|
26
|
+
percent_error = (max_freq1 - max_freq2).abs / max_freq1
|
27
|
+
percent_error.should be_within(0.1).of(0.0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '.downsample' do
|
32
|
+
it 'should produce output signal with the same max frequency (put through forward FFT)' do
|
33
|
+
sample_rate = 400.0
|
34
|
+
test_freq = 10.0
|
35
|
+
size = 128
|
36
|
+
downsample_factor = 4
|
37
|
+
order = (sample_rate / test_freq).to_i
|
38
|
+
|
39
|
+
signal1 = SignalGenerator.new(:sample_rate => sample_rate, :size => size).make_signal [test_freq]
|
40
|
+
signal1 *= BlackmanWindow.new(size).data
|
41
|
+
signal2 = signal1.clone.downsample_discrete downsample_factor, order
|
42
|
+
|
43
|
+
#plotter = Plotter.new(:title => "Discrete downsampling by #{downsample_factor}")
|
44
|
+
#plotter.plot_1d("original signal" => signal1.data, "downsampled signal" => signal2.data)
|
45
|
+
|
46
|
+
signal2.size.should eq(signal1.size / downsample_factor)
|
47
|
+
|
48
|
+
max_freq1 = signal1.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
49
|
+
max_freq2 = signal2.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
50
|
+
|
51
|
+
percent_error = (max_freq1 - max_freq2).abs / max_freq1
|
52
|
+
percent_error.should be_within(0.1).of(0.0)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context '.resample' do
|
57
|
+
it 'should produce output signal with the same max frequency (put through forward FFT)' do
|
58
|
+
sample_rate = 400.0
|
59
|
+
test_freq = 10.0
|
60
|
+
size = 64
|
61
|
+
upsample_factor = 4
|
62
|
+
downsample_factor = 4
|
63
|
+
order = (sample_rate / test_freq).to_i
|
64
|
+
|
65
|
+
signal1 = SignalGenerator.new(:sample_rate => sample_rate, :size => size).make_signal [test_freq]
|
66
|
+
signal1 *= BlackmanWindow.new(size).data
|
67
|
+
signal2 = signal1.clone.resample_discrete upsample_factor, downsample_factor, order
|
68
|
+
|
69
|
+
#plotter = Plotter.new(:title => "Discrete resampling, up by #{upsampling_factor}, down by #{downsample_factor}")
|
70
|
+
#plotter.plot_1d("original signal" => signal1.data, "resampled signal" => signal2.data)
|
71
|
+
|
72
|
+
signal2.size.should eq(signal1.size * upsample_factor / downsample_factor)
|
73
|
+
|
74
|
+
max_freq1 = signal1.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
75
|
+
max_freq2 = signal2.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
76
|
+
|
77
|
+
percent_error = (max_freq1 - max_freq2).abs / max_freq1
|
78
|
+
percent_error.should be_within(0.1).of(0.0)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'gnuplot'
|
3
|
+
|
4
|
+
describe SPCore::HybridResampling do
|
5
|
+
|
6
|
+
context '.resample' do
|
7
|
+
it 'should produce output signal with the same max frequency (put through forward FFT)' do
|
8
|
+
sample_rate = 400.0
|
9
|
+
test_freq = 10.0
|
10
|
+
size = 64
|
11
|
+
upsample_factor = 4
|
12
|
+
downsample_factor = 4
|
13
|
+
order = (sample_rate / test_freq).to_i
|
14
|
+
|
15
|
+
signal1 = SignalGenerator.new(:sample_rate => sample_rate, :size => size).make_signal [test_freq]
|
16
|
+
signal1 *= BlackmanWindow.new(size).data
|
17
|
+
signal2 = signal1.clone.resample_hybrid upsample_factor, downsample_factor, order
|
18
|
+
|
19
|
+
#plotter = Plotter.new(:title => "Discrete resampling, up by #{upsampling_factor}, down by #{downsample_factor}")
|
20
|
+
#plotter.plot_1d("original signal" => signal1.data, "resampled signal" => signal2.data)
|
21
|
+
|
22
|
+
signal2.size.should eq(signal1.size * upsample_factor / downsample_factor)
|
23
|
+
|
24
|
+
max_freq1 = signal1.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
25
|
+
max_freq2 = signal2.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
26
|
+
|
27
|
+
percent_error = (max_freq1 - max_freq2).abs / max_freq1
|
28
|
+
percent_error.should be_within(0.1).of(0.0)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'gnuplot'
|
3
|
+
|
4
|
+
describe SPCore::PolynomialResampling do
|
5
|
+
|
6
|
+
context '.upsample' do
|
7
|
+
it 'should produce output signal with the same max frequency (put through forward DFT)' do
|
8
|
+
sample_rate = 400.0
|
9
|
+
test_freq = 10.0
|
10
|
+
size = (sample_rate * 5.0 / test_freq).to_i
|
11
|
+
upsample_factor = 2.5
|
12
|
+
|
13
|
+
generator = SignalGenerator.new :sample_rate => sample_rate, :size => size
|
14
|
+
signal1 = generator.make_signal [test_freq]
|
15
|
+
signal2 = signal1.clone.upsample_polynomial upsample_factor
|
16
|
+
|
17
|
+
#plotter = Plotter.new(:title => "Polynomial upsampling by #{upsample_factor}")
|
18
|
+
#plotter.plot_1d("original signal" => signal1.data, "upsampled signal" => signal2.data)
|
19
|
+
|
20
|
+
signal2.size.should eq(signal1.size * upsample_factor)
|
21
|
+
|
22
|
+
max_freq1 = signal1.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
23
|
+
max_freq2 = signal2.freq_magnitudes.max_by{|freq, mag| mag }[0]
|
24
|
+
|
25
|
+
percent_error = (max_freq1 - max_freq2).abs / max_freq1
|
26
|
+
percent_error.should be_within(0.1).of(0.0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'pry'
|
3
|
+
require 'gnuplot'
|
4
|
+
|
5
|
+
describe SPCore::DFT do
|
6
|
+
context '.forward' do
|
7
|
+
|
8
|
+
it 'should produce a freq magnitude response peak that is within 10 percent of the test freq' do
|
9
|
+
dft_size = 64
|
10
|
+
sample_rate = 400.0
|
11
|
+
|
12
|
+
test_freqs = [
|
13
|
+
20.0,
|
14
|
+
40.0,
|
15
|
+
]
|
16
|
+
|
17
|
+
test_freqs.each do |freq|
|
18
|
+
signal = SignalGenerator.new(:sample_rate => sample_rate, :size => dft_size).make_signal([freq])
|
19
|
+
signal *= BlackmanHarrisWindow.new(dft_size).data
|
20
|
+
|
21
|
+
output = DFT.forward signal.data
|
22
|
+
output = output[0...(output.size / 2)] # skip second half
|
23
|
+
output = output.map { |x| x.magnitude } # map complex values to magnitude
|
24
|
+
|
25
|
+
freq_magnitudes = {}
|
26
|
+
output.each_index do |i|
|
27
|
+
f = (sample_rate * i) / dft_size
|
28
|
+
freq_magnitudes[f] = output[i]
|
29
|
+
end
|
30
|
+
|
31
|
+
max_freq = freq_magnitudes.max_by {|f,mag| mag}[0]
|
32
|
+
percent_err = (max_freq - freq).abs / freq
|
33
|
+
percent_err.should be_within(0.10).of(0.0)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context '.inverse' do
|
39
|
+
|
40
|
+
it 'should produce a near-identical signal to the original sent into the forward DFT (with energy that is within 10 percent error of original signal)' do
|
41
|
+
dft_size = 32
|
42
|
+
sample_rate = 400.0
|
43
|
+
|
44
|
+
test_freqs = [
|
45
|
+
20.0,
|
46
|
+
40.0,
|
47
|
+
]
|
48
|
+
|
49
|
+
test_freqs.each do |freq|
|
50
|
+
input = SignalGenerator.new(:sample_rate => sample_rate, :size => dft_size).make_signal([freq])
|
51
|
+
input *= BlackmanHarrisWindow.new(dft_size).data
|
52
|
+
|
53
|
+
output = DFT.forward input.data
|
54
|
+
input2 = DFT.inverse output
|
55
|
+
|
56
|
+
energy1 = input.energy
|
57
|
+
energy2 = input2.inject(0.0){|sum,x| sum + (x * x)}
|
58
|
+
|
59
|
+
percent_err = (energy2 - energy1).abs / energy1
|
60
|
+
percent_err.should be_within(0.10).of(0.0)
|
61
|
+
|
62
|
+
#Plotter.new(
|
63
|
+
# :title => "#{dft_size}-point DFT on #{freq} Hz sine wave signal",
|
64
|
+
# :xlabel => "frequency (Hz)",
|
65
|
+
# :ylabel => "magnitude response",
|
66
|
+
#).plot_1d("input1" => input.data, "input2" => input2)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'pry'
|
3
|
+
require 'gnuplot'
|
4
|
+
|
5
|
+
describe SPCore::FFT do
|
6
|
+
context '.forward' do
|
7
|
+
it 'should produce a freq magnitude response peak that is within 10 percent of the test freq' do
|
8
|
+
fft_size = 64
|
9
|
+
sample_rate = 400.0
|
10
|
+
|
11
|
+
test_freqs = [
|
12
|
+
20.0,
|
13
|
+
40.0,
|
14
|
+
]
|
15
|
+
|
16
|
+
test_freqs.each do |freq|
|
17
|
+
osc = Oscillator.new(:frequency => freq, :sample_rate => sample_rate)
|
18
|
+
|
19
|
+
input_size = fft_size
|
20
|
+
|
21
|
+
input = Array.new(input_size)
|
22
|
+
window = BlackmanHarrisWindow.new(input_size)
|
23
|
+
|
24
|
+
input_size.times do |i|
|
25
|
+
input[i] = osc.sample * window.data[i]
|
26
|
+
end
|
27
|
+
|
28
|
+
output = FFT.forward input
|
29
|
+
output = output[0...(output.size / 2)]
|
30
|
+
output = output.map { |x| x.magnitude } # map complex values to magnitude
|
31
|
+
|
32
|
+
magn_response = {}
|
33
|
+
output.each_index do |n|
|
34
|
+
f = (sample_rate * n) / (output.size * 2)
|
35
|
+
magn_response[f] = output[n]
|
36
|
+
end
|
37
|
+
|
38
|
+
max_freq = magn_response.max_by {|f,magn| magn }[0]
|
39
|
+
percent_err = (max_freq - freq).abs / freq
|
40
|
+
percent_err.should be_within(0.10).of(0.0)
|
41
|
+
|
42
|
+
#Plotter.new(
|
43
|
+
# :title => "#{input_size}-point FFT on #{freq} Hz sine wave signal",
|
44
|
+
# :xlabel => "frequency (Hz)",
|
45
|
+
# :ylabel => "magnitude response",
|
46
|
+
#).plot_2d("magnitude response" => magn_response)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context '.inverse' do
|
52
|
+
|
53
|
+
it 'should produce a near-identical signal to the original sent into the forward DFT (with energy that is within 10 percent error of original signal)' do
|
54
|
+
fft_size = 32
|
55
|
+
sample_rate = 400.0
|
56
|
+
|
57
|
+
test_freqs = [
|
58
|
+
20.0,
|
59
|
+
40.0,
|
60
|
+
]
|
61
|
+
|
62
|
+
test_freqs.each do |freq|
|
63
|
+
input = SignalGenerator.new(:sample_rate => sample_rate, :size => fft_size).make_signal([freq])
|
64
|
+
input *= BlackmanHarrisWindow.new(fft_size).data
|
65
|
+
|
66
|
+
output = FFT.forward input.data
|
67
|
+
input2 = FFT.inverse output
|
68
|
+
|
69
|
+
energy1 = input.energy
|
70
|
+
energy2 = input2.inject(0.0){|sum,x| sum + (x * x)}
|
71
|
+
|
72
|
+
percent_err = (energy2 - energy1).abs / energy1
|
73
|
+
percent_err.should be_within(0.10).of(0.0)
|
74
|
+
|
75
|
+
#Plotter.new(
|
76
|
+
# :title => "#{fft_size}-point FFT on #{freq} Hz sine wave signal",
|
77
|
+
# :xlabel => "frequency (Hz)",
|
78
|
+
# :ylabel => "magnitude response",
|
79
|
+
#).plot_1d("input1" => input.data, "input2" => input2)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -19,7 +19,7 @@ describe SPCore::Gain do
|
|
19
19
|
|
20
20
|
it 'should prove to be the inverse of .db_to_linear' do
|
21
21
|
20.times do
|
22
|
-
x = SPCore::Interpolation.linear(
|
22
|
+
x = SPCore::Interpolation.linear(-SPCore::Gain::MAX_DB_ABS, SPCore::Gain::MAX_DB_ABS, rand)
|
23
23
|
y = SPCore::Gain::db_to_linear(x)
|
24
24
|
z = SPCore::Gain::linear_to_db(y)
|
25
25
|
((z - x).abs / x).should be_within(1e-5).of(0.0)
|
@@ -38,7 +38,7 @@ describe SPCore::Gain do
|
|
38
38
|
20.times do
|
39
39
|
max_gain_linear = SPCore::Gain::db_to_linear(SPCore::Gain::MAX_DB_ABS)
|
40
40
|
min_gain_linear = SPCore::Gain::db_to_linear(-SPCore::Gain::MAX_DB_ABS)
|
41
|
-
x = SPCore::Interpolation.linear(
|
41
|
+
x = SPCore::Interpolation.linear(min_gain_linear, max_gain_linear, rand)
|
42
42
|
y = SPCore::Gain::linear_to_db(x)
|
43
43
|
z = SPCore::Gain::db_to_linear(y)
|
44
44
|
((z - x).abs / x).should be_within(1e-5).of(0.0)
|
File without changes
|
File without changes
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe SPCore::SignalGenerator do
|
4
|
+
before :all do
|
5
|
+
@sample_rate = 600.0
|
6
|
+
@test_freqs = [
|
7
|
+
65.0, 100.0, 250.0
|
8
|
+
]
|
9
|
+
end
|
10
|
+
|
11
|
+
context '.make_signal' do
|
12
|
+
context 'one freq at a time' do
|
13
|
+
it 'should produce the same output as a plain Oscillator' do
|
14
|
+
size = 60
|
15
|
+
generator = SignalGenerator.new :sample_rate => @sample_rate, :size => size
|
16
|
+
|
17
|
+
@test_freqs.each do |freq|
|
18
|
+
signal = generator.make_signal [freq]
|
19
|
+
|
20
|
+
osc = Oscillator.new(:sample_rate => @sample_rate, :frequency => freq)
|
21
|
+
osc_output = Array.new(size)
|
22
|
+
size.times do |i|
|
23
|
+
osc_output[i] = osc.sample
|
24
|
+
end
|
25
|
+
|
26
|
+
signal.data.should eq(osc_output)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'many freqs at a time' do
|
32
|
+
it 'should produce the same output as equivalent plain Oscillators' do
|
33
|
+
size = 60
|
34
|
+
generator = SignalGenerator.new :sample_rate => @sample_rate, :size => size
|
35
|
+
|
36
|
+
oscs = []
|
37
|
+
@test_freqs.each do |freq|
|
38
|
+
oscs.push Oscillator.new(:sample_rate => @sample_rate, :frequency => freq)
|
39
|
+
end
|
40
|
+
|
41
|
+
signal = generator.make_signal @test_freqs
|
42
|
+
|
43
|
+
osc_output = Array.new(size, 0.0)
|
44
|
+
size.times do |i|
|
45
|
+
oscs.each do |osc|
|
46
|
+
osc_output[i] += osc.sample
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
signal.data.should eq(osc_output)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|