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,48 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Provides methods for generating a Signal that contains test waveforms or noise.
|
3
|
+
class SignalGenerator
|
4
|
+
include Hashmake::HashMakeable
|
5
|
+
|
6
|
+
# used to process hashed args in #initialize.
|
7
|
+
ARG_SPECS = [
|
8
|
+
Hashmake::ArgSpec.new(:key => :size, :reqd => true, :type => Fixnum, :validator => ->(a){ a > 0 }),
|
9
|
+
Hashmake::ArgSpec.new(:key => :sample_rate, :reqd => true, :type => Float, :validator => ->(a){ a > 0.0 })
|
10
|
+
]
|
11
|
+
|
12
|
+
attr_reader :sample_rate, :size
|
13
|
+
|
14
|
+
# A new instance of SignalGenerator.
|
15
|
+
# @param [Hash] args Required keys are :sample_rate and :size.
|
16
|
+
def initialize args
|
17
|
+
hash_make ARG_SPECS, args
|
18
|
+
end
|
19
|
+
|
20
|
+
# Generate a Signal object with noise data.
|
21
|
+
def make_noise amplitude = 1.0
|
22
|
+
output = Array.new(@size)
|
23
|
+
output.each_index do |i|
|
24
|
+
output[i] = rand * amplitude
|
25
|
+
end
|
26
|
+
|
27
|
+
return Signal.new(:sample_rate => @sample_rate, :data => output)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Generate a Signal object with waveform data at the given frequencies.
|
31
|
+
def make_signal freqs, extra_osc_args = {}
|
32
|
+
args = { :sample_rate => @sample_rate }.merge! extra_osc_args
|
33
|
+
oscs = []
|
34
|
+
freqs.each do |freq|
|
35
|
+
oscs.push Oscillator.new args.merge(:frequency => freq)
|
36
|
+
end
|
37
|
+
|
38
|
+
output = Array.new(size, 0.0)
|
39
|
+
size.times do |n|
|
40
|
+
oscs.each do |osc|
|
41
|
+
output[n] += osc.sample
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
return Signal.new(:sample_rate => @sample_rate, :data => output)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/spcore/version.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Bartlett-Hann window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Bartlett.E2.80.93Hann_window.
|
4
|
+
class BartlettHannWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new(size)
|
8
|
+
a0, a1, a2 = 0.62, 0.48, 0.38
|
9
|
+
|
10
|
+
size.times do |n|
|
11
|
+
@data[n] = a0 - (a1 * ((n.to_f / (size - 1)) - 0.5).abs) - (a2 * Math::cos((TWO_PI * n)/(size - 1)))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a triangular window of a given size (number of samples).
|
3
|
+
# Endpoints are zero. Midpoint is one. There is a linear slope between endpoints and midpoint.
|
4
|
+
class BartlettWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new(size)
|
8
|
+
size.times do |n|
|
9
|
+
@data[n] = (2.0 / (size - 1)) * (((size - 1) / 2.0) - (n - ((size - 1) / 2.0)).abs)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Blackman-Harris window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Blackman.E2.80.93Harris_window.
|
4
|
+
class BlackmanHarrisWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new(size)
|
8
|
+
a0, a1, a2, a3 = 0.35875, 0.48829, 0.14128, 0.01168
|
9
|
+
size.times do |n|
|
10
|
+
@data[n] = a0 - a1 * Math::cos((TWO_PI * n)/(size - 1)) + a2 * Math::cos((FOUR_PI * n)/(size - 1)) - a3 * Math::cos((SIX_PI * n)/(size - 1))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Blackman-Nuttall window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Blackman.E2.80.93Nuttall_window.
|
4
|
+
class BlackmanNuttallWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new(size)
|
8
|
+
a0, a1, a2, a3 = 0.3635819, 0.4891775, 0.1365995, 0.0106411
|
9
|
+
size.times do |n|
|
10
|
+
@data[n] = a0 - a1 * Math::cos((TWO_PI * n)/(size - 1)) + a2 * Math::cos((FOUR_PI * n)/(size - 1)) - a3 * Math::cos((SIX_PI * n)/(size - 1))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Blackman window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Blackman_windows.
|
4
|
+
class BlackmanWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new size
|
8
|
+
alpha = 0.16
|
9
|
+
a0 = (1 - alpha) / 2.0
|
10
|
+
a1 = 0.5
|
11
|
+
a2 = alpha / 2.0
|
12
|
+
|
13
|
+
size.times do |n|
|
14
|
+
@data[n] = a0 - (a1 * Math::cos((TWO_PI * n)/(size - 1))) + (a2 * Math::cos((FOUR_PI * n)/(size - 1)))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Cosine window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Cosine_window.
|
4
|
+
class CosineWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new size
|
8
|
+
size.times do |n|
|
9
|
+
@data[n] = Math::sin((Math::PI * n)/(size - 1))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a flat top window of a given size (number of samples).
|
3
|
+
# A flat top window is a partially negative-valued window that has a flat top in
|
4
|
+
# the frequency domain. They are designed to have a broader bandwidth and so have
|
5
|
+
# a poorer frequency resolution, leading to low amplitude measurement error suitable
|
6
|
+
# for use in in spectrum analyzers for the measurement of amplitudes of sinusoidal
|
7
|
+
# frequency components
|
8
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Flat_top_window.
|
9
|
+
class FlatTopWindow
|
10
|
+
attr_reader :data
|
11
|
+
def initialize size
|
12
|
+
@data = Array.new(size)
|
13
|
+
a0, a1, a2, a3, a4 = 1.0, 1.93, 1.29, 0.388, 0.032
|
14
|
+
|
15
|
+
size.times do |n|
|
16
|
+
@data[n] = a0 - a1 * Math::cos((TWO_PI * n)/(size - 1)) + a2 * Math::cos((FOUR_PI * n)/(size - 1)) - a3 * Math::cos((SIX_PI * n)/(size - 1)) + a4 * Math::cos((EIGHT_PI * n)/(size - 1))
|
17
|
+
end
|
18
|
+
|
19
|
+
max = @data.max
|
20
|
+
|
21
|
+
# normalize to max of 1.0
|
22
|
+
@data.each_index do |i|
|
23
|
+
@data[i] /= max
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Gaussian window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Gaussian_windows.
|
4
|
+
class GaussianWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new size
|
8
|
+
sigma = 0.4 # must be <= 0.5
|
9
|
+
size.times do |n|
|
10
|
+
a = (n - (size - 1) / 2) / (sigma * (size - 1) / 2)
|
11
|
+
@data[n] = Math::exp(-0.5 * a**2)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Hamming window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Hamming_window.
|
4
|
+
class HammingWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new size
|
8
|
+
alpha = 0.54
|
9
|
+
beta = 1.0 - alpha
|
10
|
+
|
11
|
+
size.times do |n|
|
12
|
+
@data[n] = alpha - (beta * Math::cos((TWO_PI * n) / (size - 1)))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Hann window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Hann_.28Hanning.29_window.
|
4
|
+
class HannWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new(size)
|
8
|
+
size.times do |n|
|
9
|
+
@data[n] = 0.5 * (1 - Math::cos((TWO_PI * n)/(size - 1)))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Lanczos window of a given size (number of samples).
|
3
|
+
# The Lanczos window is used in Lanczos resampling.
|
4
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Lanczos_window.
|
5
|
+
class LanczosWindow
|
6
|
+
attr_reader :data
|
7
|
+
def initialize size
|
8
|
+
@data = Array.new size
|
9
|
+
sinc = lambda {|x| (Math::sin(Math::PI * x))/(Math::PI * x) }
|
10
|
+
size.times do |n|
|
11
|
+
@data[n] = sinc.call(((2.0*n)/(size-1)) - 1)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a Nuttall window of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Nuttall_window.2C_continuous_first_derivative.
|
4
|
+
class NuttallWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new(size)
|
8
|
+
a0, a1, a2, a3 = 0.355768, 0.487396, 0.144232, 0.012604
|
9
|
+
size.times do |n|
|
10
|
+
@data[n] = a0 - a1 * Math::cos((TWO_PI * n)/(size - 1)) + a2 * Math::cos((FOUR_PI * n)/(size - 1)) - a3 * Math::cos((SIX_PI * n)/(size - 1))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a rectangular window (all ones) of a given size (number of samples).
|
3
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Rectangular_window.
|
4
|
+
class RectangularWindow
|
5
|
+
attr_reader :data
|
6
|
+
def initialize size
|
7
|
+
@data = Array.new(size, 1.0)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SPCore
|
2
|
+
# Produces a triangular window of a given size (number of samples).
|
3
|
+
# Endpoints are near zero. Midpoint is one. There is a linear slope between endpoints and midpoint.
|
4
|
+
# For more info, see https://en.wikipedia.org/wiki/Window_function#Triangular_window
|
5
|
+
class TriangularWindow
|
6
|
+
attr_reader :data
|
7
|
+
def initialize size
|
8
|
+
@data = Array.new(size)
|
9
|
+
size.times do |n|
|
10
|
+
@data[n] = (2.0 / (size + 1)) * (((size + 1) / 2.0) - (n - ((size - 1) / 2.0)).abs)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/spcore.gemspec
CHANGED
@@ -5,15 +5,23 @@ require File.expand_path('../lib/spcore/version', __FILE__)
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "spcore"
|
7
7
|
gem.version = SPCore::VERSION
|
8
|
-
gem.summary = %q{
|
8
|
+
gem.summary = %q{A library of signal processing methods and classes.}
|
9
9
|
gem.description = <<DESCRIPTION
|
10
|
-
Contains core signal processing
|
10
|
+
Contains core signal processing methods and classes, including:
|
11
|
+
Resampling (discrete up, down and up/down, polynomial up, and hybrid up/down)
|
12
|
+
FFT transform (forward and inverse)
|
13
|
+
DFT transform (forward and inverse)
|
14
|
+
Windows (Blackman, Hamming, etc.)
|
15
|
+
Windowed sinc filter for lowpass and highpass.
|
16
|
+
Dual windowed sinc filter for bandpass and bandstop.
|
17
|
+
Interpolation (linear and polynomial)
|
18
|
+
Data plotting via gnuplot (must be installed to use).
|
11
19
|
Delay line
|
12
20
|
Biquad filters
|
13
21
|
Envelope detector
|
14
22
|
Conversion from dB-linear and linear-dB
|
15
|
-
Linear interpolation
|
16
23
|
Oscillator with selectable wave type (sine, square, triangle, sawtooth)
|
24
|
+
Signal abstraction class.
|
17
25
|
|
18
26
|
DESCRIPTION
|
19
27
|
gem.license = "MIT"
|
File without changes
|
@@ -3,8 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
3
3
|
describe SPCore::EnvelopeDetector do
|
4
4
|
describe '#process_sample' do
|
5
5
|
it 'should produce an output that follows the amplitude of the input' do
|
6
|
-
sample_rate =
|
7
|
-
freqs = [20.0,
|
6
|
+
sample_rate = 400.0
|
7
|
+
freqs = [20.0, 60.0]
|
8
8
|
|
9
9
|
envelope_start = 1.0
|
10
10
|
envelope_end = 0.0
|
@@ -26,7 +26,7 @@ describe SPCore::EnvelopeDetector do
|
|
26
26
|
sample_count = (5.0 * sample_rate / freq).to_i
|
27
27
|
sample_count.times do |n|
|
28
28
|
percent = n.to_f / sample_count
|
29
|
-
amplitude = SPCore::Interpolation.linear
|
29
|
+
amplitude = SPCore::Interpolation.linear envelope_start, envelope_end, percent
|
30
30
|
osc.amplitude = amplitude
|
31
31
|
|
32
32
|
sample = osc.sample
|
File without changes
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
3
|
+
|
4
|
+
describe SPCore::SincFilter do
|
5
|
+
before :all do
|
6
|
+
@sample_rate = 4000.0
|
7
|
+
@orders = [62]
|
8
|
+
@left_cutoffs = Scale.exponential 300.0..1500.0, 3
|
9
|
+
@right_cutoffs = Scale.exponential 400.0..1600.0, 3
|
10
|
+
end
|
11
|
+
|
12
|
+
context '.bandpass' do
|
13
|
+
it 'should keep magnitude below -20 dB below left cutoff and above right cutoff, and close to 0 dB between' do
|
14
|
+
@orders.each do |order|
|
15
|
+
@left_cutoffs.each_index do |i|
|
16
|
+
left_cutoff = @left_cutoffs[i]
|
17
|
+
right_cutoff = @right_cutoffs[i]
|
18
|
+
|
19
|
+
if order % 2 == 1
|
20
|
+
order += 1
|
21
|
+
end
|
22
|
+
filter = DualSincFilter.new :order => order, :left_cutoff_freq => left_cutoff, :right_cutoff_freq => right_cutoff, :sample_rate => @sample_rate, :window_class => BlackmanWindow
|
23
|
+
#filter.bandpass_fir.plot_freq_response false
|
24
|
+
freq_response = filter.bandpass_fir.freq_response true
|
25
|
+
|
26
|
+
freq_response.each do |freq, magnitude|
|
27
|
+
if freq <= (0.8 * left_cutoff) || freq >= (1.2 * right_cutoff)
|
28
|
+
magnitude.should be < -20.0 # using dB
|
29
|
+
elsif freq.between?(1.2 * left_cutoff, 0.8 * right_cutoff)
|
30
|
+
magnitude.should be_within(1.0).of(0.0) # using dB
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context '.bandstop' do
|
39
|
+
it 'should keep magnitude close to 0 dB below left cutoff and above right cutoff, and below -20 dB between' do
|
40
|
+
@orders.each do |order|
|
41
|
+
@left_cutoffs.each_index do |i|
|
42
|
+
left_cutoff = @left_cutoffs[i]
|
43
|
+
right_cutoff = @right_cutoffs[i]
|
44
|
+
|
45
|
+
if order % 2 == 1
|
46
|
+
order += 1
|
47
|
+
end
|
48
|
+
filter = DualSincFilter.new :order => order, :left_cutoff_freq => left_cutoff, :right_cutoff_freq => right_cutoff, :sample_rate => @sample_rate, :window_class => BlackmanWindow
|
49
|
+
#filter.bandstop_fir.plot_freq_response false
|
50
|
+
freq_response = filter.bandstop_fir.freq_response true
|
51
|
+
|
52
|
+
freq_response.each do |freq, magnitude|
|
53
|
+
if freq <= (0.8 * left_cutoff) || freq >= (1.2 * right_cutoff)
|
54
|
+
magnitude.should be_within(1.0).of(0.0) # using dB
|
55
|
+
elsif freq.between?(1.2 * left_cutoff, 0.8 * right_cutoff)
|
56
|
+
magnitude.should be < -20.0 # using dB
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
3
|
+
|
4
|
+
describe SPCore::SincFilter do
|
5
|
+
before :all do
|
6
|
+
@sample_rate = 4000.0
|
7
|
+
@orders = [62]
|
8
|
+
@cutoffs = Scale.exponential 400.0..1600.0, 3
|
9
|
+
end
|
10
|
+
|
11
|
+
context '.highpass' do
|
12
|
+
it 'should keep magnitude below-20 dB below cutoff and close to 0 dB above cutoff' do
|
13
|
+
@orders.each do |order|
|
14
|
+
@cutoffs.each do |cutoff|
|
15
|
+
if order % 2 == 1
|
16
|
+
order += 1
|
17
|
+
end
|
18
|
+
filter = SincFilter.new :order => order, :cutoff_freq => cutoff, :sample_rate => @sample_rate, :window_class => BlackmanWindow
|
19
|
+
#filter.highpass_fir.plot_freq_response false
|
20
|
+
freq_response = filter.highpass_fir.freq_response true
|
21
|
+
|
22
|
+
freq_response.each do |freq, magnitude|
|
23
|
+
if freq <= (0.8 * cutoff)
|
24
|
+
magnitude.should be < -20.0 # using dB
|
25
|
+
elsif freq >= (1.2 * cutoff)
|
26
|
+
magnitude.should be_within(1.0).of(0.0) # using dB
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context '.lowpass' do
|
35
|
+
it 'should keep magnitude close to 0 dB below cutoff and below-20 dB above cutoff' do
|
36
|
+
@orders.each do |order|
|
37
|
+
@cutoffs.each do |cutoff|
|
38
|
+
if order % 2 == 1
|
39
|
+
order += 1
|
40
|
+
end
|
41
|
+
filter = SincFilter.new :order => order, :cutoff_freq => cutoff, :sample_rate => @sample_rate, :window_class => BlackmanWindow
|
42
|
+
#filter.lowpass_fir.plot_freq_response false
|
43
|
+
freq_response = filter.lowpass_fir.freq_response true
|
44
|
+
|
45
|
+
freq_response.each do |freq, magnitude|
|
46
|
+
if freq <= (0.8 * cutoff)
|
47
|
+
magnitude.should be_within(1.0).of(0.0) # using dB
|
48
|
+
elsif freq >= (1.2 * cutoff)
|
49
|
+
magnitude.should be < -20.0 # using dB
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|