./math/fourierseries/fourieranalysis.rb

download original
#!/usr/bin/ruby

# see: Andrew Tanenbaum, "Computer networks", 3rd edition, p. 78ff

include Math

module Enumerable
  def sum
    inject(0) {|x,y|x+y}
  end
end

# in:
#   f:  Float->Float
#   t0,t1: Float
#   ns: [n1,n2,...nx] (list of Fixnum)
#   nsteps: Fixnum
#
# out: [as,bs,c] where
#   as == [a_n1,a_n2,...a_nx]
#   bs == [b_n1,b_n2,...b_nx]
#   c  == c
#
# s.t.
#   \forall t \in [t0,t1]:
#      f(t) == 0.5c + \sum{n=1}{\inf}{a_n*sin(2*PI*n*(t-t0)/(t1-t0))} + \sum{n=1}{\inf}{b_n*cos(2*PI*n*(t-t0)/(t1-t0))}
#
# nsteps == number of steps for internal numerical integrations
def fourier_analysis(f, t0, t1, ns, nsteps=10000)
  t=t1-t0
  c=2.0/t*numint(f,t0,t1)
  as = ns.map{|n|
    2.0/t * numint(proc{|x|f.call(x)*sin(2*PI*n*(x-t0)/(t1-t0))},
                   t0,t1,nsteps)
  }
  bs = ns.map{|n|
    2.0/t * numint(proc{|x|f.call(x)*cos(2*PI*n*(x-t0)/(t1-t0))},
                   t0,t1,nsteps)
  }
  [as,bs,c]
end


def numint(f,x0,x1,nsteps=10000)
  res=0.0; x=x0; dx=(x1-x0)/nsteps
  nsteps.times{
    res += f.call(x)*dx
    x += dx
  }
  res
end



# reverse of "fourier_analysis", i.e. take some coefficients
#  (c, and a_n, b_n for some n's) and an interval [t0,t1], and
#  return the corresponding function (fourier sum), which
#  will be a more or less good approximation of the original
#  function submitted to fourier_analysis to obtain the (as,bs,c).
def fourier_analysis_reverse(ns,as,bs,c, t0, t1)
  proc{|x|
    0.5*c + ns.map{|n| as[n-1]*sin(2*PI*n*(x-t0)/(t1-t0)) +
                       bs[n-1]*cos(2*PI*n*(x-t0)/(t1-t0))
                  }.sum
  }
end


if __FILE__ == $0

  # 01100010
  f=proc{|x|
    xi=x.to_i
    if (xi==1 or xi==2 or xi==6)
      1.0
    else
      0.0
    end
  }

  as,bs,c = fourier_analysis(f, 0.0, 8.0, (1...40))

  fapprox8 = fourier_analysis_reverse((1...8),as,bs,c, 0.0, 8.0)
  fapprox20 = fourier_analysis_reverse((1...20),as,bs,c, 0.0, 8.0)
  fapprox40 = fourier_analysis_reverse((1...40),as,bs,c, 0.0, 8.0)

  require "gplotutils"
  plot = Plot.new(ARGV[0] || nil)
  plot.title("fourier analysis")
  plot.xlabel("time")
  plot.ylabel("signal")
  plot.draw(RealFunction.new(f,0.0,8.0,"title"=>"f"),
            RealFunction.new(fapprox8,0.0,8.0,"title"=>"fapprox8"),
            RealFunction.new(fapprox20,0.0,8.0,"title"=>"fapprox20"),
            RealFunction.new(fapprox40,0.0,8.0,"title"=>"fapprox40"))
  readline
end

  
back to fourierseries

(C) 1998-2017 Olaf Klischat <olaf.klischat@gmail.com>