上へ

Subject: スペクトル計算とハイパス&ローパスフィルタ

Date: Wed, 14 Sep 2011 18:55:12 +0900,
X-Mailer: Sylpheed 3.1.0 (GTK+ 2.24.4; x86_64-pc-linux-gnu)

2階研究室の皆さん

玉川です。ほとんど早川くんへ です

2つの時系列データを与えて、コスペクトル&パワースペクトルを計算するサブルーチン
スペクトルデータを対数スケールでみて等間隔の周波数刻みで平均化するサブルーチン
FFTを利用したハイパスフィルター
同      ローパスフィルター

と、それを使うメインプログラムのサンプル を   sample.f90

そこで使用しているFFTルーチンとして fftpack5.f90 を送ります。
(こっちは、WWWには置きません。下記の配布元から取ってください)
あとは見れば分かりますよね。
十分、チェックしてはいないので、気をつけて使って下さいませ
わからなければ聞いてください。


fftpack5 は http://www.cisl.ucar.edu/css/software/fftpack5/ に あるものです ( Fortran 90 版 )
2のべき乗でないデータ数の場合でもFFTしてくれます。
(素数の時は、とても遅い)
--------------------------------------------------------------------------------
〒 501-1193 岐阜市柳戸1-1
岐阜大学 流域圏科学研究センター
玉川一郎 (e-mail: tama@green.gifu-u.ac.jp)
phone : 058-293-2430
WWW : http://tama.green.gifu-u.ac.jp/~tama
--------------------------------------------------------------------------------

sample.f90

! For compile
!  gfortran sample.f90 fftpack5.f90  -o sample -O3
!
!   need fftpack5.f90
!


program sample


 implicit none
 integer, parameter:: n=18000   ! data number
 integer, parameter:: ndiv=50  !   number of points in power&co-spectra after smoothing
 real :: x(n), y(n), dt=0.1
 real :: cospec(n), pow1(n), pow2(n), freq(n), azero1, azero2
 real :: cospec_smooth(ndiv), pow1_smooth(ndiv), pow2_smooth(ndiv), freq_smooth(ndiv)
 real :: x_high(n), cutoff, x_low(n)
 integer :: nh
 integer :: i, j 
 real, parameter :: pi = 3.14159265358979323846


! ****************************************************
! power spetra & co-spectrum

 call random_number(x)
 call random_number(y)

 

! do i=1, n
!  x(i) = 10*sin(2*pi/n*(3*i))
!  y(i) = 8*cos(2*pi/n*(5*i))
! end do

 call cospectrum( x, y, n, dt, cospec, pow1, pow2, freq, nh,  azero1, azero2 )

 open(unit=10, file="spectra_raw")
 do i=1, nh
  write(10,*) freq(i), pow1(i), pow2(i), cospec(i)
 end do
 close(10)

 call logsmooth( pow1, freq, nh, pow1_smooth, freq_smooth, ndiv)
 call logsmooth( pow2, freq, nh, pow2_smooth, freq_smooth, ndiv)
 call logsmooth( cospec, freq, nh, cospec_smooth, freq_smooth, ndiv)

 open(unit=10, file="spectra_smooth")
 do i=1, ndiv
  write(10,*) freq_smooth(i), pow1_smooth(i), pow2_smooth(i), cospec_smooth(i)
 end do
 close(10)


! ****************************************************
!  highpass filter

 cutoff = 0.5
 call random_number(x)
 call highpass(x, n, dt, cutoff, x_high )

 open(unit=10, file="highpass")
 do i=1, n
  write(10,*) x(i), x_high(i), x(i)-x_high(i)
 end do
close(10)


! ****************************************************
!  lowpass filter

 cutoff = 0.5
 ! call random_number(x)
 call lowpass(x, n, dt, cutoff, x_low )

 open(unit=10, file="lowpass")
 do i=1, n
  write(10,*) x(i), x_low(i), x(i)-x_low(i)
 end do
 close(10)

end

subroutine logsmooth( pow, freq, n, pow_smooth, freq_smooth, ndiv)
! smooth pow(n) into pow_smooth(ndiv)
!  same distance in log scale fot freq
!
implicit none
 real, parameter :: MISS = -9999
 integer :: n, ndiv
 real :: pow(n), freq(n)
 real :: pow_smooth(ndiv), freq_smooth(ndiv)
 real :: ldf, fmin, fmax
 integer :: i1, i, j, c
 real(kind=8) :: sf, sp

 !  determin fmin fmax
       ldf = ( log(freq(n)) - log(freq(1)) )/ndiv
       fmin = freq(1); i1=1

 do j=1, ndiv
  fmax = exp( ldf*j+log(freq(1)))
   sf = 0; sp = 0; c = 0; i = i1
!   write(0,*) "Average ", fmin, "-", fmax, "Hz"
   do while( freq(i) >= fmin .AND. freq(i) < fmax)
     sf = sf + freq(i); sp = sp + pow(i); c = c+1
     i = i + 1
   end do
   if( c > 0 ) then
     freq_smooth(j) = sf/dble(c); pow_smooth(j) = sp/dble(c)
   else
     freq_smooth(j) = MISS; pow_smooth(j) = MISS
   end if
  i1 = i; fmin = fmax
!   write(0,*) j,  freq_smooth(j),  pow_smooth(j)
 end do
end

 

 




subroutine lowpass(x, n, dt, cutoff, x_low )
implicit none
 integer:: n
 real :: x(n), x_low(n)
 real :: dt, cutoff

 real :: r(n)
 real ::  wsave(n+int(log(real(n)))+4), work(n)
 integer :: lenr, lensav, lenwork, i, j, nh, ier
 real :: freq

  lenr = n
  lensav = (n+int(log(real(n)))+4)
  lenwork = n


 call rfft1i( n, wsave, lensav, ier )
       if(ier /= 0) then
         write(0,*) 'ERR in rfft1i'
         stop
       end if

  r = x
  call rfft1f( n, 1, r, lenr, wsave, lensav, work, lenwork, ier )

! write(*,*) 'rfft1f'
         if( mod(n,2) == 0) then
             nh = n/2 -1
         else
             nh = (n-1)/2
         end if
!   write(*,*) 'n=', n, 'nh=', nh
 
         do i=1, nh
          freq = i/(n*dt)
!          write(*,*) "freq=", freq, "cutoff=", cutoff
          if( freq > cutoff ) then
              r(2*i-1+1) = 0   ! a
              r(2*i+1)   = 0   ! b
          end if
         end do
  
! write(*,*) 'go to rfft1b'
  call rfft1b( n, 1, r, lenr, wsave, lensav, work, lenwork, ier )
  x_low = r


end

subroutine highpass(x, n, dt, cutoff, x_high )
implicit none
 integer:: n
 real :: x(n), x_high(n)
 real :: dt, cutoff

 real :: r(n)
 real ::  wsave(n+int(log(real(n)))+4), work(n)
 integer :: lenr, lensav, lenwork, i, j, nh, ier
 real :: freq

  lenr = n
  lensav = (n+int(log(real(n)))+4)
  lenwork = n


 call rfft1i( n, wsave, lensav, ier )
       if(ier /= 0) then
         write(0,*) 'ERR in rfft1i'
         stop
       end if

  r = x
  call rfft1f( n, 1, r, lenr, wsave, lensav, work, lenwork, ier )

! write(*,*) 'rfft1f'
         if( mod(n,2) == 0) then
             nh = n/2 -1
         else
             nh = (n-1)/2
         end if
!   write(*,*) 'n=', n, 'nh=', nh
 
        r(1) = 0
         do i=1, nh
          freq = i/(n*dt)
!          write(*,*) "freq=", freq, "cutoff=", cutoff
          if( freq < cutoff ) then
              r(2*i-1+1) = 0   ! a
              r(2*i+1)   = 0   ! b
          end if
         end do
  
! write(*,*) 'go to rfft1b'
  call rfft1b( n, 1, r, lenr, wsave, lensav, work, lenwork, ier )
  x_high = r


end

subroutine  cospectrum( x, y, n, dt, cospec, pow1, pow2, freq, nh, azero1, azero2  )
implicit none

 integer:: n
 real :: x(n), y(n), cospec(n), pow1(n), pow2(n), freq(n), dt
 real :: azero1, azero2

 real :: r1(n), a1(n), b1(n)
 real :: r2(n), a2(n), b2(n)
 real :: wsave(n+int(log(real(n)))+4), work(n)
 integer :: lenr, lensav, lenwork, i, j, nh, ier

  lenr = n
  lensav = (n+int(log(real(n)))+4)
  lenwork = n


 call rfft1i( n, wsave, lensav, ier )
       if(ier /= 0) then
         write(0,*) 'ERR in rfft1i'
         stop
       end if

  r1 = x
 call rfft1f( n, 1, r1, lenr, wsave, lensav, work, lenwork, ier )
            if( ier /= 0 ) then
              write(0,*) 'ERROR in rfft1f', ier
              stop
             end if
 r2 = y;
 call rfft1f( n, 1, r2, lenr, wsave, lensav, work, lenwork, ier )
             if( ier /= 0 ) then
               write(0,*) 'ERROR in rfft1f', ier
               stop
              end if
	 azero1 = r1(1); azero2 = r2(1)
        if( mod(n,2) == 0) then
            nh = n/2 -1
        else
            nh = (n-1)/2
        end if

        do j=1,nh
         a1(j) = r1(2*j-1+1); a2(j) = r2(2*j-1+1)
         b1(j) = r1(2*j+1)  ; b2(j) = r2(2*j+1)
        end do

        cospec = (a1*a2+b1*b2)*(n*dt)
        pow1   = (a1*a1+b1*b1)*(n*dt)
        pow2   = (a2*a2+b2*b2)*(n*dt)
!   below just amplitude
!        cospec = (a1*a2+b1*b2)
!        pow1   = a1*a1+b1*b1
!        pow2   = a2*a2+b2*b2

        do i=1, nh
         freq(i) = i/(n*dt)
        end do
end
玉川一郎