I'm reading this amazing book at the moment, http://www.dspguide.com/ and thought it would be fun to code some stuff in Ruby.
The code...
#!/usr/bin/ruby
require 'complex'
class DFT
def initialize( size )
@freq = Array.new( size, Complex(0,0) )
end
# set data
def data( data )
@data = data
end
# get frequency table
def freq
@freq
end
# reset the frequency table
def reset
@freq.map! do |d|
Complex( 0,0 )
end
end
# transform data and return the frequency table
def transform
raise "No input data" unless @data
(0..@freq.size-1).each do |k|
@data.each_with_index do |d,i|
@freq[k] = Complex(
@freq[k].real + d * Math.cos( 2 * Math::PI * k * i / @data.size ),
@freq[k].imag - d * Math.sin( 2 * Math::PI * k * i / @data.size )
)
end
end
return @freq
end
end
And a test...
#!/usr/bin/ruby
require 'dft.rb'
require 'test/unit'
class TestDFT < Test::Unit::TestCase
def setup
# Compose a data set containing two frequencies, f1 & f2
# Assume the data set contains 1 second worth of samples so
# f1 & f2 are in Hz and should be less than half the number of samples (Nyquist)
@data = Array.new(64)
f1 =10
f2 =25
amplitude = 1
i=-1
@data.map! do |d|
i=i+1
Math.sin( 2 * Math::PI * f1 * i / @data.size ) + Math.sin( 2 * Math::PI * f2 * i / @data.size )
end
end
def test_dft_throws_exception_with_no_input
dft = DFT.new( 32 )
assert_raise RuntimeError do
freq = dft.transform
end
end
def test_dft_has_correct_output_size
dft = DFT.new( 32 )
dft.data( @data )
freq = dft.transform
assert_equal( 32, freq.size )
assert_equal( 32, dft.freq.size )
end
def test_dft_has_correct_output
dft = DFT.new( 32 )
dft.data( @data )
dft.transform
assert dft.freq.at(10).abs > 1
assert dft.freq.at(25).abs > 1
end
def test_display
dft = DFT.new( 32 )
dft.data( @data )
dft.transform
puts "\nFrequencies found:\n"
dft.freq.each_with_index do |f,i|
if (f.abs > 1)
printf( "%d %.30f %.30f %.30f\n", i, f.real, f.imag, f.abs )
end
end
end
end