戻る

エラーデータを線形内挿で埋める

(Fortran90) プログラムのダウンロード
研究室の皆さん

玉川です。エラーデータの処理をするサブルーチンを作ってみました。
特に、豊吉君にお勧めです。

以下につけたようなもので
最初の program 〜 end までは、テスト用のメインプログラムです。
その下以降を自分のソフトに組み込んで使って下さい。

使い方は、
データの入った配列 x1      ( real  x1(n) )
不良データを埋めたデータをいれる配列 x2   ( real x2(n) )
データ数   n                integer
不良データ数 errnum         integer
を用意し、
call interpol( x1, x2, n, errnum )
と呼ぶだけです。
埋める処理は、ごく簡単に、不良データの前後のデータ1つだけを見て
線形内挿しています。 (端データが不良の場合は、残った側の2つを見て)
全部不良データだったらギブアップして、何もしません。

参考にして下さい。30分と時間を掛けてないので、間違っているかも知れません。
********************************************************
間違っていました。訂正しておきます。2007.12.5 夜
間違っていました。訂正しておきます。2008.1.7 夜
********************************************************
一応動いているところを書いておきます。左の出力が元データです。
--- 動作例 -----
tama@tama[139] !./a
./a.out < SAMPLEDATA
 number of error data  =            3
  -9999.000       1.000000    
   2.000000       2.000000    
   3.000000       3.000000    
   4.000000       4.000000    
  -9999.000       5.000000    
  -9999.000       6.000000    
   7.000000       7.000000    
   8.000000       8.000000    
   9.000000       9.000000    
   10.00000       10.00000    
--- その2 (2回目の修正までだめだったパターン) ----
tama@tama[107] ./a.out < SAMPLEDATA
 number of error data  =            8
  -9999.000       1.000000    
   2.000000       2.000000    
  -9999.000       3.000000    
   4.000000       4.000000    
  -9999.000       5.000000    
  -9999.000       6.000000    
   7.000000       7.000000    
  -9999.000       8.000000    
   9.000000       9.000000    
  -9999.000       10.00000    


--------------------------------------------------------------------------------
玉川一郎 (e-mail: tama@green.gifu-u.ac.jp)
--------------------------------------------------------------------------------

! 
! 2008.1.7  debuged   I. Tamagawa
!
program test
implicit none

  integer, parameter :: n=10
  real :: x1(n), x2(n)
  integer :: i, errnum
  
  do i=1, n
    read(*,*) x1(i)
  end do

  call interpol( x1, x2, n, errnum )

  write(*,*) 'number of error data  = ', errnum
  do i=1, n
  	write(*,*) x1(i), x2(i)
  end do
end






logical function ok( x, count )
implicit none
  real :: x
  integer :: count

  if( x < -9900 ) then
  	ok = (5<0)
	count = count + 1
  else
        ok = (5>0)
  endif
end function


subroutine interpol( x1, x2, n, errnum )
implicit none
 real, intent(in)   :: x1(n)
 real, intent(out)  :: x2(n)
 integer, intent(in) :: n
 integer, intent(out) :: errnum

!  x1  ==> x2   (error data are linearly interpoleted)

 integer :: i, err1st, errlast, i1, i2
 integer :: count
 logical, external :: ok

 count = 0
 errnum = 0

 do i=1, n
	if( ok(x1(i), count) )  then
	  x2(i) = x1(i)
	  if( count > 0 ) then
	       errlast = i - 1
	       call linear_interpol( x1, x2, err1st, errlast, n )
	       errnum = errnum + (errlast-err1st+1)
	       count = 0
	  end if
	else
	  if( count == 1 ) then
	  	err1st = i
	  end if
	end if
 end do
 if( count > 0 ) then
    errlast = n
    call linear_interpol( x1, x2, err1st, errlast, n )
    errnum = errnum + count
 end if

end subroutine



subroutine find_next_ok( x, n, errlast, i2 )
! find next good data in x(i)   i > errlast+1

  implicit none
  integer, intent(in) :: n
  real, intent(in) :: x(n)
  integer :: errlast, i2
  integer :: i, dum
  logical, external :: ok

  !write(*,*) 'find next ok data'
  dum=0
  i = errlast+2
  do while( (.NOT. ok(x(i), dum)) .AND. (i<=n) )
  !write(*,*) 'i in while loop', i 
   i=i+1
  end do

  if( i == n ) then
    if( ok(x(i), dum) ) then
    	i2 = i
    else
        i2 = errlast + 1
    end if

  else
      i2 = i
  end if

  !write(*,*) ' i2 = ', i2
end


subroutine find_last_ok( x, n, err1st, i1 )
! find last good data in x(i)   i < err1st-1


  implicit none
  integer, intent(in) :: n
  real, intent(in) :: x(n)
  integer :: err1st, i1
  integer :: i, dum
  logical, external :: ok

  !write(*,*) 'find before  ok data'
  dum=0
  i = err1st-2
  do while( (.NOT. ok(x(i), dum)) .AND. (i>0) )
  !write(*,*) 'i in while loop', i 
   i=i-1
  end do

  if( i <= 0  ) then
        i1 = err1st - 1
  else
        i1 = i
  end if

  !write(*,*) ' i1 = ', i1
end











subroutine linear_interpol( x1, x2, err1st, errlast, n )
implicit none
  integer, intent(in) :: n
  real, intent(in) :: x1(n)
  real             :: x2(n)
  integer          :: err1st, errlast
  integer          :: i1, i2, i

  real ::  a, b


! write(*,*) ' interpol (err1st and errlast)', err1st, errlast

  if( err1st == 1 .AND. errlast == n ) then    ! NO GOOD DATA
    write(0,*) 'Give up to interporate error data, because all', &
      'data are error data'
    do i=1,n
     x2(i)=x1(i)
    end do

    return
  end if

  if( err1st > 1 .AND. errlast < n) then
     i1 = err1st - 1;  i2 =errlast +1

  else if( err1st == 1 .AND. errlast < n-1 ) then
        i1 = errlast +1 
	call find_next_ok( x1, n, errlast, i2 )
	errlast = i2 - 1


  else if( errlast == n .AND. err1st > 2 ) then
	i2 = err1st -1  	
  	call find_last_ok( x1, n, err1st, i1 )
	err1st = i1+1
  end if

  if( i2 > i1 ) then
    a = (x1(i2)-x1(i1))/(i2-i1)
    do i=err1st, errlast
	   x2(i) =  x1(i1) + a*(i-i1)
    end do
  else		!  only one datum is ok (maybe)
    write(0,*) 'Only one datum is OK.  Number of error data is wrong!'
    do i=1, n
    	x2(i) = x1(i1)
    end do
  end if
    	   

end subroutine