module SpectreAnalysisClass use IOClass use MathClass use ArrayClass implicit none type :: SpectreAnalysis_ type(IO_) :: display type(IO_), allocatable :: files(:) integer(int32), allocatable :: num_lines(:, :), BOL(:) real(real32) :: sampling_Hz integer(int32) :: max_file_num = 10000 integer(int32) :: last_file_id real(real64), allocatable :: Freq(:) real(real64) :: in1 = 0.0d0 real(real64) :: in2 = 0.0d0 real(real64) :: out1 = 0.0d0 real(real64) :: out2 = 0.0d0 complex(real64) :: in1_cmplx = 0.0d0 complex(real64) :: in2_cmplx = 0.0d0 complex(real64) :: out1_cmplx = 0.0d0 complex(real64) :: out2_cmplx = 0.0d0 complex(real64), allocatable :: FDD_S(:, :) !(singular-value idx,frequency) complex(real64), allocatable :: FDD_Phi(:, :, :) !(mode-idx, point-idx,frequency) logical :: initialized = .false. contains procedure, public :: init => initSpectreAnalysis procedure, public :: add => addSpectreAnalysis procedure, public :: channel => channelSpectreAnalysis procedure, public :: plot => plotSpectreAnalysis procedure, pass :: FFTSpectreAnalysis procedure, pass :: FFT_for_vector_SpectreAnalysis generic :: FFT => FFTSpectreAnalysis, FFT_for_vector_SpectreAnalysis procedure, public :: PSD => PSDSpectreAnalysis procedure, public :: PowerSpectrum => PowerSpectrumSpectreAnalysis procedure, public :: freq_axis => freq_axisSpectreAnalysis procedure, public :: FDD => FDD_SpectreAnalysis procedure, public :: export => exportSpectreAnalysis procedure, pass :: bandpass_complex64_scalar_SpectreAnalysis procedure, pass :: bandpass_complex64_SpectreAnalysis procedure, pass :: bandpass_real64_scalar_SpectreAnalysis procedure, pass :: bandpass_real64_SpectreAnalysis generic, public :: bandpass => bandpass_complex64_scalar_SpectreAnalysis & , bandpass_complex64_SpectreAnalysis & , bandpass_real64_scalar_SpectreAnalysis & , bandpass_real64_SpectreAnalysis procedure,public :: lowpass => lowpass_vector_SpectreAnalysis procedure, pass :: cutifSpectreAnalysis procedure, pass :: cutif_loggers_SpectreAnalysis generic :: cutif => cutifSpectreAnalysis, cutif_loggers_SpectreAnalysis ! create wave procedure, public :: whiteNoize => whiteNoizeSpectreAnalysis procedure, public :: time => timeSpectreAnalysis ! tools procedure, public :: to_segment => to_segmentSpectreAnalysis procedure, public :: applyTaper => applyTaper_SpectreAnalysis procedure, public :: FourierAmplitude => FourierAmplitude_SpectreAnalysis procedure, public :: FourierPhase => FourierPhase_SpectreAnalysis procedure, public :: masw => masw_SpectreAnalysis procedure, public :: fk => fk_SpectreAnalysis procedure, public :: write => write_SpectreAnalysis end type contains ! ########################################################## subroutine initSpectreAnalysis(this, sampling_Hz, max_file_num) class(SpectreAnalysis_), intent(inout) :: this real(real32), intent(in) :: sampling_Hz integer(int32), optional, intent(in) :: max_file_num this%sampling_Hz = sampling_Hz if (present(max_file_num)) then this%max_file_num = max_file_num end if if (allocated(this%files)) then deallocate (this%files) end if if (allocated(this%num_lines)) then deallocate (this%num_lines) end if if (allocated(this%files)) deallocate (this%files) if (allocated(this%num_lines)) deallocate (this%num_lines) if (allocated(this%BOL)) deallocate (this%BOL) if (allocated(this%FDD_S)) deallocate (this%FDD_S) if (allocated(this%FDD_Phi)) deallocate (this%FDD_Phi) allocate (this%files(this%max_file_num)) allocate (this%num_lines(this%max_file_num, 2)) allocate (this%BOL(this%max_file_num)) this%in1 = 0.0d0 this%in2 = 0.0d0 this%out1 = 0.0d0 this%out2 = 0.0d0 this%in1_cmplx = 0.0d0 this%in2_cmplx = 0.0d0 this%out1_cmplx = 0.0d0 this%out2_cmplx = 0.0d0 this%last_file_id = 0 this%initialized = .true. end subroutine ! ########################################################## ! ########################################################## subroutine addSpectreAnalysis(this, name, lines, BOL) class(SpectreAnalysis_), intent(inout) :: this character(*), intent(in) :: name integer(int32), intent(in) :: lines(1:2), BOL !Beginning of line if (.not. this%initialized) then print *, "[ERROR] Please initialize SpectreAnalysis, by %init(sampling_Hz)" stop end if if (access(name, "r") /= 0) then print *, "[Caution!] File :: ", name, "[404]" return end if this%files(this%last_file_id + 1)%filename = name this%num_lines(this%last_file_id + 1, 1:2) = lines(1:2) this%BOL(this%last_file_id + 1) = BOL this%last_file_id = this%last_file_id + 1 end subroutine ! ########################################################## ! ########################################################## function channelSpectreAnalysis(this, channel) result(vec_data) class(SpectreAnalysis_), intent(inout) :: this integer(int32), intent(in) :: channel integer(int32) :: i, j, numline, n, loc_data_id integer(int32), allocatable :: starts_from(:) real(real64), allocatable :: vec_data(:), row_data(:) character(:), allocatable :: line allocate (row_data(channel)) numline = 0 allocate (starts_from(this%last_file_id)) do i = 1, this%last_file_id numline = numline + this%num_lines(i, 2) - this%num_lines(i, 1) + 1 starts_from(i) = numline - (this%num_lines(i, 2) - this%num_lines(i, 1)) end do if (channel == 0) then vec_data = linspace([1.0d0/dble(this%sampling_Hz), 1.0d0/dble(this%sampling_Hz)*dble(numline)], numline) return end if allocate (vec_data(numline)) vec_data(:) = 0.0d0 !!$OMP parallel do default(shared) private(n, i, loc_data_id, line,row_data) do i = 1, this%last_file_id call this%files(i)%open(this%files(i)%filename) n = 0 loc_data_id = 0 do n = n + 1 if (this%files(i)%EOF) exit line = this%files(i)%readline() if (n < this%num_lines(i, 1) .or. this%num_lines(i, 2) < n) then cycle else loc_data_id = loc_data_id + 1 read (line(this%BOL(i):), *) row_data(1:channel) vec_data(starts_from(i) - 1 + loc_data_id) = row_data(channel) end if end do call this%files(i)%close() end do !!$OMP end parallel do end function ! ########################################################## subroutine plotSpectreAnalysis(this, channels) class(SpectreAnalysis_), intent(inout) :: this integer(int32), intent(in) :: channels(:) end subroutine ! ########################################################## ! ########################################################## function FFTSpectreAnalysis(this, channel, Taper, Stacking, window_size) result(FFT_result) class(SpectreAnalysis_), intent(inout) :: this integer(int32), intent(in) :: channel integer(int32), intent(in) :: Taper ! taper-ratio (0 to 100 ) real(real32), intent(in) :: Stacking(:)! size=number of stacking, i-th dataframes starts from stacking(i) integer(int32), intent(in) :: window_size ! 2^n integer(int32) :: i, j, n, data_id complex(complex64), allocatable :: FFT_result(:), wave(:), total_wave(:), fft_loc(:) if (.not. this%initialized) then print *, "[ERROR] Please initialize SpectreAnalysis, by %init(sampling_Hz)" stop end if ! get all data total_wave = this%channel(channel) if (window_size > size(total_wave)) then print *, "ERROR :: FFTSpectreAnalysis >> window size", window_size, " is too large" print *, "Data size is ", size(total_wave) stop end if if (window_size + int(maxval(stacking)*this%sampling_Hz) > size(total_wave)) then print *, "ERROR :: FFTSpectreAnalysis >> window size", window_size, " is too large" print *, "this operation needs", window_size + int(maxval(stacking)*this%sampling_Hz), " samples" print *, "but you only have", size(total_wave), " data plots" stop end if FFT_result = zeros(window_size) do i = 1, size(stacking) data_id = int(Stacking(i)*this%sampling_Hz) if (data_id <= 0) then data_id = 1 end if wave = total_wave(data_id:data_id + window_size - 1) wave(:) = wave(:) - average(dble(wave)) wave = wave(:)*taper_function(n=size(wave), percent=taper) fft_loc = FFT(wave) FFT_result = FFT_result + sqrt(dble(fft_loc*conjg(fft_loc))) end do FFT_result = FFT_result(1:window_size/2) FFT_result = FFT_result/dble(size(stacking)) end function ! ########################################################## ! ########################################################## function FFT_for_vector_SpectreAnalysis(this, vector, Taper, Stacking, window_size) result(FFT_result) class(SpectreAnalysis_), intent(inout) :: this real(real64), intent(in) :: vector(:) integer(int32), intent(in) :: Taper ! taper-ratio (0 to 100 ) real(real32), intent(in) :: Stacking(:)! size=number of stacking, i-th dataframes starts from stacking(i) integer(int32), intent(in) :: window_size ! 2^n integer(int32) :: i, j, n, data_id complex(complex64), allocatable :: FFT_result(:), wave(:), total_wave(:), fft_loc(:) if (.not. this%initialized) then print *, "[ERROR] Please initialize SpectreAnalysis, by %init(sampling_Hz)" stop end if ! get all data total_wave = vector if (window_size > size(total_wave)) then print *, "ERROR :: FFTSpectreAnalysis >> window size", window_size, " is too large" print *, "Data size is ", size(total_wave) stop end if if (window_size + int(maxval(stacking)*this%sampling_Hz) > size(total_wave)) then print *, "ERROR :: FFTSpectreAnalysis >> window size", window_size, " is too large" print *, "this operation needs", window_size + int(maxval(stacking)*this%sampling_Hz), " samples" print *, "but you only have", size(total_wave), " data plots" stop end if FFT_result = zeros(window_size) do i = 1, size(stacking) data_id = int(Stacking(i)*this%sampling_Hz) if (data_id <= 0) then data_id = 1 end if wave = total_wave(data_id:data_id + window_size - 1) wave(:) = wave(:) - average(dble(wave)) wave = wave(:)*taper_function(n=size(wave), percent=taper) fft_loc = FFT(wave) FFT_result = FFT_result + sqrt(dble(fft_loc*conjg(fft_loc))) end do FFT_result = FFT_result(1:window_size/2) FFT_result = FFT_result/dble(size(stacking)) end function ! ########################################################## function taper_function(n, percent) result(taper_f) integer(int32), intent(in) :: n, percent real(real64), allocatable :: taper_f(:) integer(int32) :: i ! taper window taper_f = eyes(n) do i = 1, int(dble(percent)/100.0d0*dble(n)) taper_f(i) = taper_f(i)*dble(i - 1)/(dble(percent)/100.0d0*dble(n)) taper_f(n - i + 1) = taper_f(n - i + 1)*dble(i - 1)/(dble(percent)/100.0d0*dble(n)) end do end function ! ########################################################## function PowerSpectrumSpectreAnalysis(this, channel, Taper, Stacking, window_size) result(PowerSpectrum) class(SpectreAnalysis_), intent(inout) :: this integer(int32), intent(in) :: channel integer(int32), intent(in) :: Taper ! taper-ratio (0 to 100 ) real(real32), intent(in) :: Stacking(:)! size=number of stacking, i-th dataframes starts from stacking(i) integer(int32), intent(in) :: window_size ! 2^n integer(int32) :: i, j, n, data_id real(real64) :: T complex(complex64), allocatable :: FFT_result(:), wave(:) real(real64), allocatable :: PowerSpectrum(:) if (.not. this%initialized) then print *, "[ERROR] Please initialize SpectreAnalysis, by %init(sampling_Hz)" stop end if FFT_result = this%FFT( & channel=channel, & Taper=Taper, & Stacking=Stacking, & window_size=window_size & ) T = dble(window_size*this%sampling_Hz) PowerSpectrum = dble(FFT_result(:)*conjg(FFT_result(:)))/T end function ! ########################################################## ! ########################################################## function freq_axisSpectreAnalysis(this, window_size) result(freq) class(SpectreAnalysis_), intent(in) :: this integer(int32), intent(in) :: window_size real(real64), allocatable :: freq(:) real(real64) :: df df = 1.0d0/(window_size/this%sampling_Hz) freq = linspace([df, dble(this%sampling_Hz/2)], window_size/2) end function ! ########################################################## ! ########################################################### subroutine FDD_SpectreAnalysis(this, wave_data, window_size, channel, taper, stacking) class(SpectreAnalysis_), intent(inout) :: this type(SpectreAnalysis_), intent(inout) :: wave_data(:) real(real64), allocatable :: freq(:) complex(real64), allocatable :: FourierSpectrum(:, :), PSD(:, :, :) integer(int32), intent(in) :: channel integer(int32), intent(in) :: Taper ! taper-ratio (0 to 100 ) real(real32), intent(in) :: Stacking(:)! size=number of stacking, i-th dataframes starts from stacking(i) integer(int32), intent(in) :: window_size ! 2^n integer(int32) :: i, freq_idx, n_data ! FOR LAPACK INTEGER M, N, LDA, LDU, LDV, LWORK, LRWORK, INFO logical :: INFO2 INTEGER, allocatable :: IWORK(:) REAL(real64), allocatable :: SVA(:), RWORK(:) COMPLEX(real64), allocatable :: A(:, :), U(:, :), V(:, :), CWORK(:) CHARACTER(1) JOBA, JOBU, JOBV, JOBR, JOBT, JOBP real(real64) :: df df = 1.0d0/(window_size/this%sampling_Hz) if (.not. this%initialized) then print *, "[ERROR] Please initialize SpectreAnalysis, by %init(sampling_Hz)" stop end if ! PSD用のFunction作ったほうがよいか? PSD = this%PSD(channel, Taper, Stacking, window_size, wave_data) this%freq = linspace([df, dble(this%sampling_Hz/2)], window_size/2) n_data = size(wave_data) this%FDD_S = zeros(n_data, window_size/2) this%FDD_Phi = zeros(n_data, n_data, window_size/2) do freq_idx = 1, window_size/2 ! 特異値分解 JOBA = "C" JOBU = "U" JOBV = "V" JOBR = "N" JOBT = "N" JOBP = "N" M = size(PSD, 1) N = size(PSD, 2) A = PSD(:, :, freq_idx) LDA = M SVA = zeros(M) U = zeros(M, N) LDU = M V = zeros(N, N) LDV = N LWORK = 6*N + 2*N*N CWORK = zeros(LWORK) LRWORK = N + 2*M RWORK = zeros(LRWORK) IWORK = zeros(M + 3*N) INFO = 0 !call print(real(A) ) !call print(">> ") !call print(imag(A) ) !call print(">> ") call ZGEJSV(JOBA, JOBU, JOBV, JOBR, JOBT, JOBP, M, N, A, LDA, & SVA, U, LDU, V, LDV, CWORK, LWORK, RWORK, LRWORK, & IWORK, INFO) this%FDD_Phi(:, :, freq_idx) = V(:, :) this%FDD_S(:, freq_idx) = SVA end do end subroutine ! ########################################################### ! ########################################################## function PSDSpectreAnalysis(this, channel, Taper, Stacking, window_size, wave_data) result(PSD_result) class(SpectreAnalysis_), intent(inout) :: this type(SpectreAnalysis_), intent(inout) :: wave_data(:) integer(int32), intent(in) :: channel integer(int32), intent(in) :: Taper ! taper-ratio (0 to 100 ) real(real32), intent(in) :: Stacking(:)! size=number of stacking, i-th dataframes starts from stacking(i) integer(int32), intent(in) :: window_size ! 2^n integer(int32) :: i, j, n, data_id, data_idx, data_idx_I, data_idx_J complex(complex64), allocatable :: FFT_result(:), wave(:), total_waves(:, :), fft_loc(:), & PSD_result(:, :, :), wave_I(:), wave_J(:), fft_loc_I(:), fft_loc_J(:) ! get all data total_waves = zeros(size(wave_data(1)%channel(channel)), size(wave_data)) do data_idx = 1, size(wave_data) total_waves(:, data_idx) = wave_data(data_idx)%channel(channel) end do ! check data size if (window_size > size(total_waves, 1)) then print *, "ERROR :: PSDSpectreAnalysis >> window size", window_size, " is too large" print *, "Data size is ", size(total_waves, 1) stop end if if (window_size + int(maxval(stacking)*this%sampling_Hz) > size(total_waves, 1)) then print *, "ERROR :: PSDSpectreAnalysis >> window size", window_size, " is too large" print *, "this operation needs", window_size + int(maxval(stacking)*this%sampling_Hz), " samples" print *, "but you only have", size(total_waves), " data plots" stop end if ! FFT_result = zeros(window_size) ! G_{xx}{f}: PSD PSD_result = zeros(size(wave_data), size(wave_data), window_size) !$OMP parallel private(data_idx_J,data_id,wave_I,wave_J,fft_loc_I,fft_loc_J) !$OMP do do data_idx_I = 1, size(wave_data) do data_idx_J = 1, size(wave_data) do i = 1, size(stacking) data_id = int(Stacking(i)*this%sampling_Hz) if (data_id <= 0) then data_id = 1 end if wave_I = total_waves(data_id:data_id + window_size - 1, data_idx_I) wave_I(:) = wave_I(:) - average(dble(wave_I)) wave_I = wave_I(:)*taper_function(n=size(wave_I), percent=taper) fft_loc_I = FFT(wave_I) wave_J = total_waves(data_id:data_id + window_size - 1, data_idx_J) wave_J(:) = wave_J(:) - average(dble(wave_J)) wave_J = wave_J(:)*taper_function(n=size(wave_J), percent=taper) fft_loc_J = FFT(wave_J) PSD_result(data_idx_I, data_idx_J, :) = PSD_result(data_idx_I, data_idx_J, :) & + fft_loc_I(:)*conjg(fft_loc_J(:)) end do end do end do !$OMP end do !$OMP end parallel PSD_result = PSD_result(:, :, 1:window_size/2) PSD_result = PSD_result/dble(size(stacking)) end function ! ########################################################## subroutine exportSpectreAnalysis(this, name) class(SpectreAnalysis_), intent(in) :: this character(*), intent(in) :: name type(IO_) :: f integer(int32) :: freq_idx, mode_idx if (allocated(this%FDD_S)) then do mode_idx = 1, size(this%FDD_S, 1) call f%open(name + "_FDD_mode_"+zfill(mode_idx, 5), "w") ! first mode do freq_idx = 1, size(this%Freq) write (f%fh, *) this%Freq(freq_idx), real(this%FDD_S(mode_idx, freq_idx)) end do call f%close() end do end if end subroutine ! ########################################################## ! ########################################################## function bandpass_real64_SpectreAnalysis(this, x, freq_range) result(ft) class(SpectreAnalysis_), intent(inout) :: this real(real64), allocatable :: ft(:) real(real32), intent(in) :: freq_range(1:2) real(real64), intent(in) :: x(:) type(Math_) :: math real(real64) :: omega real(real64) :: alpha real(real64) :: a0 real(real64) :: a1 real(real64) :: a2 real(real64) :: b0 real(real64) :: b1 real(real64) :: b2, samplerate, freq, bw integer(int32) :: i freq = minval(freq_range) bw = maxval(freq_range) - minval(freq_range) if (.not. this%initialized) then print *, "ERROR >> bandpassSpectreAnalysis >> please call %init(sampling_Hz)" return end if samplerate = this%sampling_Hz ! それぞれの変数は下記のとおりとする ! float samplerate … サンプリング周波数 ! float freq … カットオフ周波数 ! float bw … 帯域幅 omega = 2.0d0*math%pi*freq/samplerate; alpha = sin(omega)*sinh(log(2.0d0)/2.0d0*bw*omega/sin(omega)); a0 = 1.0d0 + alpha; a1 = -2.0d0*cos(omega); a2 = 1.0d0 - alpha; b0 = alpha; b1 = 0.0d0; b2 = -alpha; ! https://www.utsbox.com/?page_id=523 ! https://www.w3.org/TR/audio-eq-cookbook/ ! それぞれの変数は下記のとおりとする ! float input[] …入力信号の格納されたバッファ。 ! flaot output[] …フィルタ処理した値を書き出す出力信号のバッファ。 ! int size …入力信号・出力信号のバッファのサイズ。 ! float in1, in2, out1, out2 …フィルタ計算用のバッファ変数。初期値は0。 ! float a0, a1, a2, b0, b1, b2 …フィルタの係数。 別途算出する。 !for(int i = 0; i < size; i++) ft = zeros(size(x)) do i = 1, size(x) ! 入力信号にフィルタを適用し、出力信号として書き出す。 ft(i) = b0/a0*x(i) + b1/a0*this%in1 + b2/a0*this%in2 - a1/a0*this%out1 - a2/a0*this%out2 this%in2 = this%in1; ! 2つ前の入力信号を更新 this%in1 = x(i); ! 1つ前の入力信号を更新 this%out2 = this%out1; ! 2つ前の出力信号を更新 this%out1 = ft(i); ! 1つ前の出力信号を更新 end do end function ! ########################################################## function bandpass_complex64_SpectreAnalysis(this, x, freq_range) result(ft) class(SpectreAnalysis_), intent(inout) :: this complex(real64), allocatable :: ft(:) real(real32), intent(in) :: freq_range(1:2) complex(real64), intent(in) :: x(:) type(Math_) :: math real(real64) :: omega real(real64) :: alpha real(real64) :: a0 real(real64) :: a1 real(real64) :: a2 real(real64) :: b0 real(real64) :: b1 real(real64) :: b2, samplerate, freq, bw integer(int32) :: i freq = minval(freq_range) bw = maxval(freq_range) - minval(freq_range) if (.not. this%initialized) then print *, "ERROR >> bandpassSpectreAnalysis >> please call %init(sampling_Hz)" return end if samplerate = this%sampling_Hz ! それぞれの変数は下記のとおりとする ! float samplerate … サンプリング周波数 ! float freq … カットオフ周波数 ! float bw … 帯域幅 omega = 2.0d0*math%pi*freq/samplerate; alpha = sin(omega)*sinh(log(2.0d0)/2.0d0*bw*omega/sin(omega)); a0 = 1.0d0 + alpha; a1 = -2.0d0*cos(omega); a2 = 1.0d0 - alpha; b0 = alpha; b1 = 0.0d0; b2 = -alpha; ! https://www.utsbox.com/?page_id=523 ! それぞれの変数は下記のとおりとする ! float input[] …入力信号の格納されたバッファ。 ! flaot output[] …フィルタ処理した値を書き出す出力信号のバッファ。 ! int size …入力信号・出力信号のバッファのサイズ。 ! float in1, in2, out1, out2 …フィルタ計算用のバッファ変数。初期値は0。 ! float a0, a1, a2, b0, b1, b2 …フィルタの係数。 別途算出する。 !for(int i = 0; i < size; i++) ft = zeros(size(x)) do i = 1, size(x) ! 入力信号にフィルタを適用し、出力信号として書き出す。 ft(i) = b0/a0*x(i) + b1/a0*this%in1_cmplx + b2/a0*this%in2_cmplx - a1/a0*this%out1_cmplx - a2/a0*this%out2_cmplx this%in2_cmplx = this%in1_cmplx; ! 2つ前の入力信号を更新 this%in1_cmplx = x(i); ! 1つ前の入力信号を更新 this%out2_cmplx = this%out1_cmplx; ! 2つ前の出力信号を更新 this%out1_cmplx = ft(i); ! 1つ前の出力信号を更新 end do end function ! ########################################################## ! ########################################################## function bandpass_complex64_scalar_SpectreAnalysis(this, x, freq_range) result(ft) class(SpectreAnalysis_), intent(inout) :: this complex(real64) :: ft real(real32), intent(in) :: freq_range(1:2) complex(real64), intent(in) :: x type(Math_) :: math real(real64) :: omega real(real64) :: alpha real(real64) :: a0 real(real64) :: a1 real(real64) :: a2 real(real64) :: b0 real(real64) :: b1 real(real64) :: b2, samplerate, freq, bw integer(int32) :: i freq = minval(freq_range) bw = maxval(freq_range) - minval(freq_range) if (.not. this%initialized) then print *, "ERROR >> bandpassSpectreAnalysis >> please call %init(sampling_Hz)" return end if samplerate = this%sampling_Hz ! それぞれの変数は下記のとおりとする ! float samplerate … サンプリング周波数 ! float freq … カットオフ周波数 ! float bw … 帯域幅 omega = 2.0d0*math%pi*freq/samplerate; alpha = sin(omega)*sinh(log(2.0d0)/2.0d0*bw*omega/sin(omega)); a0 = 1.0d0 + alpha; a1 = -2.0d0*cos(omega); a2 = 1.0d0 - alpha; b0 = alpha; b1 = 0.0d0; b2 = -alpha; ! https://www.utsbox.com/?page_id=523 ! それぞれの変数は下記のとおりとする ! float input[] …入力信号の格納されたバッファ。 ! flaot output[] …フィルタ処理した値を書き出す出力信号のバッファ。 ! int size …入力信号・出力信号のバッファのサイズ。 ! float in1, in2, out1, out2 …フィルタ計算用のバッファ変数。初期値は0。 ! float a0, a1, a2, b0, b1, b2 …フィルタの係数。 別途算出する。 !for(int i = 0; i < size; i++) ! 入力信号にフィルタを適用し、出力信号として書き出す。 ft = b0/a0*x + b1/a0*this%in1_cmplx + b2/a0*this%in2_cmplx - a1/a0*this%out1_cmplx - a2/a0*this%out2_cmplx this%in2_cmplx = this%in1_cmplx; ! 2つ前の入力信号を更新 this%in1_cmplx = x; ! 1つ前の入力信号を更新 this%out2_cmplx = this%out1_cmplx; ! 2つ前の出力信号を更新 this%out1_cmplx = ft; ! 1つ前の出力信号を更新 end function ! ########################################################## ! ########################################################## function bandpass_real64_scalar_SpectreAnalysis(this, x, freq_range) result(ft) class(SpectreAnalysis_), intent(inout) :: this real(real64) :: ft real(real32), intent(in) :: freq_range(1:2) real(real64), intent(in) :: x type(Math_) :: math real(real64) :: omega real(real64) :: alpha real(real64) :: a0 real(real64) :: a1 real(real64) :: a2 real(real64) :: b0 real(real64) :: b1 real(real64) :: b2, samplerate, freq, bw integer(int32) :: i freq = minval(freq_range) bw = maxval(freq_range) - minval(freq_range) if (.not. this%initialized) then print *, "ERROR >> bandpassSpectreAnalysis >> please call %init(sampling_Hz)" return end if samplerate = this%sampling_Hz ! それぞれの変数は下記のとおりとする ! float samplerate … サンプリング周波数 ! float freq … カットオフ周波数 ! float bw … 帯域幅 omega = 2.0d0*math%pi*freq/samplerate; alpha = sin(omega)*sinh(log(2.0d0)/2.0d0*bw*omega/sin(omega)); a0 = 1.0d0 + alpha; a1 = -2.0d0*cos(omega); a2 = 1.0d0 - alpha; b0 = alpha; b1 = 0.0d0; b2 = -alpha; ! https://www.utsbox.com/?page_id=523 ! それぞれの変数は下記のとおりとする ! float input[] …入力信号の格納されたバッファ。 ! flaot output[] …フィルタ処理した値を書き出す出力信号のバッファ。 ! int size …入力信号・出力信号のバッファのサイズ。 ! float in1, in2, out1, out2 …フィルタ計算用のバッファ変数。初期値は0。 ! float a0, a1, a2, b0, b1, b2 …フィルタの係数。 別途算出する。 !for(int i = 0; i < size; i++) ! 入力信号にフィルタを適用し、出力信号として書き出す。 ft = b0/a0*x + b1/a0*this%in1_cmplx + b2/a0*this%in2_cmplx - a1/a0*this%out1_cmplx - a2/a0*this%out2_cmplx this%in2_cmplx = this%in1_cmplx; ! 2つ前の入力信号を更新 this%in1_cmplx = x; ! 1つ前の入力信号を更新 this%out2_cmplx = this%out1_cmplx; ! 2つ前の出力信号を更新 this%out1_cmplx = ft; ! 1つ前の出力信号を更新 end function ! ########################################################## function whiteNoizeSpectreAnalysis(this, n, t) result(x) class(SpectreAnalysis_), intent(in) :: this real(real64), allocatable, optional, intent(inout) :: t(:) real(real64), allocatable :: x(:) integer(int32), intent(in) :: n integer(int32) :: i type(Random_) :: random if (.not. this%initialized) then print *, "ERROR >> whiteNoizeSpectreAnalysis >> please call %init(sampling_Hz)" return end if x = zeros(n) if (present(t)) then t = linspace([0.0d0, dble(size(x))/dble(this%sampling_Hz)], size(x)) end if do i = 1, size(x) x(i) = random%gauss(mu=0.0d0, sigma=1.0d0) end do end function ! ########################################################## function timeSpectreAnalysis(this, n) result(t) class(SpectreAnalysis_), intent(in) :: this real(real64), allocatable :: t(:) integer(int32), intent(in) :: n integer(int32) :: i type(Random_) :: random if (.not. this%initialized) then print *, "ERROR >> whiteNoizeSpectreAnalysis >> please call %init(sampling_Hz)" return end if t = linspace([0.0d0, dble(n)/dble(this%sampling_Hz)], n) end function ! ########################################################## function cutifSpectreAnalysis(this, x_t, window_size, sigma) result(x_r) class(SpectreAnalysis_), intent(in) :: this real(real64), intent(in) :: x_t(:) real(real64), allocatable :: dummy_x(:), x_r(:) integer(int32), intent(in) :: window_size real(real64), optional, intent(in) :: sigma real(real64) :: sd, ave integer(int32), allocatable :: active_segment(:) integer(int32) :: i, from, to type(Random_) :: random if (present(sigma)) then ! remove if ! 全体のsdをとり, sd = standardDeviation(x_t) ave = average(x_t) ! ホワイトガウスノイズ生成 do i = 1, size(x_t)/window_size from = (i - 1)*window_size + 1 to = i*window_size dummy_x = x_t(from:to) if (standardDeviation(dummy_x) > sigma*sd) then cycle else if (.not. allocated(x_r)) then x_r = dummy_x else x_r = x_r//dummy_x end if end if end do end if end function ! ########################################################## function cutif_loggers_SpectreAnalysis(this, x_t, window_size, sigma, log) result(x_r) class(SpectreAnalysis_), intent(in) :: this real(real64), intent(in) :: x_t(:, :) ! t, channel character(*), optional, intent(in) :: log real(real64), allocatable :: dummy_x(:), x_r(:, :) integer(int32), intent(in) :: window_size real(real64), optional, intent(in) :: sigma integer(int32), allocatable :: active_segment(:), remove_segment_ids(:) integer(int32) :: i, from, to, itr, j type(Random_) :: random real(real64), allocatable :: sd_data(:, :), sd(:), ave(:), sd_vector(:), zero_window(:, :) type(IO_) :: log_original, log_remained if (present(sigma)) then ! remove if ! 全体のsdをとり, remove_segment_ids = int(zeros(size(x_t, 1)/window_size)) sd = zeros(size(x_t, 2)) ave = zeros(size(x_t, 2)) do i = 1, size(x_t, 2) sd(i) = standardDeviation(x_t(:, i)) ave(i) = average(x_t(:, i)) end do sd_data = zeros(size(x_t)/window_size, size(x_t, 2)) do i = 1, size(x_t, 1)/window_size from = (i - 1)*window_size + 1 to = i*window_size do j = 1, size(x_t, 2) dummy_x = x_t(from:to, j) sd_data(i, j) = standardDeviation(dummy_x) end do end do do i = 1, size(x_t, 1)/window_size from = (i - 1)*window_size + 1 to = i*window_size sd_vector = sd_data(i, :) if (maxval(sd_vector - sd*sigma) > 0.0d0) then remove_segment_ids(i) = 1 end if end do if (maxval(remove_segment_ids) == 0) then deallocate (remove_segment_ids) end if if (present(log)) then call log_original%open(log + "_original_wave.csv") call log_remained%open(log + "_remained_wave.csv") end if if (allocated(remove_segment_ids)) then x_r = eyes(size(x_t, 1) - window_size*sum(remove_segment_ids), size(x_t, 2)) zero_window = zeros(window_size, size(x_t, 2)) from = 1 to = 0 do i = 1, size(x_t, 1)/window_size if (remove_segment_ids(i) == 1) then if (present(log)) then call log_remained%write(zero_window, separator=", ") end if cycle else to = from - 1 + window_size x_r(from:to, :) = x_t(window_size*(i - 1) + 1:window_size*i, :) from = from + window_size if (present(log)) then call log_remained%write(x_r(from:to, :), separator=", ") end if end if end do x_r(from:, :) = x_t(window_size*int(size(x_t, 1)/window_size) + 1:, :) if (present(log)) then call log_original%write(x_t, separator=", ") end if else x_r = x_t if (present(log)) then call log_original%write(x_t, separator=", ") call log_remained%write(x_r, separator=", ") end if end if if (present(log)) then call log_original%flush() call log_remained%flush() call log_original%close() call log_remained%close() end if end if end function ! ########################################################## function bandpass_filter(x, freq_range, sampling_Hz, & in1, in2, out1, out2) result(ft) real(real64), intent(in) :: sampling_Hz real(real64):: ft real(real64), intent(in) :: freq_range(1:2) real(real64), intent(in) :: x real(real64), intent(inout) :: in1, in2, out1, out2 type(Math_) :: math real(real64) :: omega real(real64) :: alpha real(real64) :: a0 real(real64) :: a1 real(real64) :: a2 real(real64) :: b0 real(real64) :: b1 real(real64) :: b2, samplerate, freq, bw integer(int32) :: i freq = minval(freq_range) bw = maxval(freq_range) - minval(freq_range) samplerate = sampling_Hz ! それぞれの変数は下記のとおりとする ! float samplerate … サンプリング周波数 ! float freq … カットオフ周波数 ! float bw … 帯域幅 omega = 2.0d0*math%pi*freq/samplerate; alpha = sin(omega)*sinh(log(2.0d0)/2.0d0*bw*omega/sin(omega)); a0 = 1.0d0 + alpha; a1 = -2.0d0*cos(omega); a2 = 1.0d0 - alpha; b0 = alpha; b1 = 0.0d0; b2 = -alpha; ! https://www.utsbox.com/?page_id=523 ! それぞれの変数は下記のとおりとする ! float input[] …入力信号の格納されたバッファ。 ! flaot output[] …フィルタ処理した値を書き出す出力信号のバッファ。 ! int size …入力信号・出力信号のバッファのサイズ。 ! float in1, in2, out1, out2 …フィルタ計算用のバッファ変数。初期値は0。 ! float a0, a1, a2, b0, b1, b2 …フィルタの係数。 別途算出する。 !for(int i = 0; i < size; i++) ! 入力信号にフィルタを適用し、出力信号として書き出す。 ft = b0/a0*x + b1/a0*in1 + b2/a0*in2 - a1/a0*out1 - a2/a0*out2 in2 = in1; ! 2つ前の入力信号を更新 in1 = x; ! 1つ前の入力信号を更新 out2 = out1; ! 2つ前の出力信号を更新 out1 = ft; ! 1つ前の出力信号を更新 end function ! ########################################################## function movingAverage_filter(x, in1, in2) result(ft) real(real64):: ft real(real64), intent(in) :: x real(real64), intent(inout) :: in1, in2 ! 入力信号にフィルタを適用し、出力信号として書き出す。 ft = average([x, in1, in2]) in2 = in1 ! 2つ前の入力信号を更新 in1 = x ! 1つ前の入力信号を更新 end function ! ########################################################## function lowpass_vector_SpectreAnalysis(this,x,cutoff_frequency) result(ret) class(SpectreAnalysis_),intent(in) :: this real(real64),intent(in) :: x(:),cutoff_frequency real(real64),allocatable :: ret(:) real(real64) :: buf,x_n integer(int32) :: i ret = 0.0d0*x buf = x(1) do i=1,size(x) ret(i) = lowpass_filter(x(i),buf=buf,fc=cutoff_frequency,sampling_Hz=dble(this%sampling_Hz)) enddo ret = reverse(ret) do i=1,size(x) ret(i) = lowpass_filter(ret(i),buf=buf,fc=cutoff_frequency,sampling_Hz=dble(this%sampling_Hz)) enddo ret = reverse(ret) end function ! ########################################################## function lowpass_filter(x_n, buf, fc, sampling_Hz) result(x) real(Real64), intent(in) :: x_n, fc, sampling_Hz real(Real64), intent(inout) :: buf real(Real64) :: x, A, fs type(Math_) :: math !https://cognicull.com/ja/888mgpw8 fs = sampling_Hz A = 4.0d0 - 2.0d0*cos(2.0d0*math%pi*fc/fs) & - sqrt((4.0d0 - 2.0d0*cos(2.0d0*math%pi*fc/fs))**2 - 4.0d0) A = A/2.0d0 x = (1.0d0 - A)*x_n + A*buf buf = x end function ! ########################################################## function to_segmentSpectreAnalysis(this, time_and_components, n) result(segments) class(SpectreAnalysis_), intent(in) :: this real(real64), intent(in) :: time_and_components(:, :) real(real64), allocatable :: segments(:, :, :) integer(int32) :: nrow, ncol, nseg, n, i, j, k nrow = n ncol = size(time_and_components, 2) nseg = size(time_and_components, 1)/n allocate (segments(nrow, ncol, nseg)) do i = 1, nseg segments(:, :, i) = time_and_components((i - 1)*n + 1:i*n, :) end do end function ! ########################################################## subroutine applyTaper_SpectreAnalysis(this, segments, percent) class(SpectreAnalysis_), intent(in) :: this real(real64), intent(inout) :: segments(:, :, :) integer(int32), intent(in) :: percent integer(int32) :: i, j, n n = size(segments, 1) do i = 1, size(segments, 3) do j = 2, size(segments, 2) segments(:, j, i) = segments(:, j, i)*taper_function(n=n, percent=percent) end do end do end subroutine ! ########################################################## ! ########################################################## function FourierAmplitude_SpectreAnalysis(this, all_segments) result(all_spectrum) class(SpectreAnalysis_), intent(in) :: this real(real64), intent(in) :: all_segments(:, :, :) real(real64), allocatable :: all_spectrum(:, :, :) real(real64) :: df, T, dt integer(int32) :: i, j, k complex(real64), allocatable :: ft(:), Fw(:) dt = abs(all_segments(2, 1, 1) - all_segments(1, 1, 1)) T = dt*size(all_segments, 1)/2.0d0 df = 1.0d0/T all_spectrum = all_segments(1:size(all_segments, 1)/2, :, :) do i = 1, size(all_segments, 3) do j = 2, size(all_segments, 2) ft = all_segments(:, j, i) Fw = fft(ft) all_spectrum(:, j, i) = abs(Fw(:size(Fw)/2))*T end do end do do i = 1, size(all_segments, 3) j = 1 do k = 1, size(all_segments, 1)/2 all_spectrum(k, j, i) = df*(k - 1) end do end do end function ! ########################################################## ! ########################################################## function FourierPhase_SpectreAnalysis(this, all_segments) result(all_spectrum) class(SpectreAnalysis_), intent(in) :: this real(real64), intent(in) :: all_segments(:, :, :) real(real64), allocatable :: all_spectrum(:, :, :) real(real64) :: df, T, dt integer(int32) :: i, j, k complex(real64), allocatable :: ft(:), Fw(:) dt = abs(all_segments(2, 1, 1) - all_segments(1, 1, 1)) T = dt*size(all_segments, 1)/2.0d0 df = 1.0d0/T all_spectrum = all_segments(1:size(all_segments, 1)/2, :, :) do i = 1, size(all_segments, 3) do j = 2, size(all_segments, 2) ft = all_segments(:, j, i) Fw = fft(ft) all_spectrum(:, j, i) = arg(Fw(:size(Fw)/2)) end do end do do i = 1, size(all_segments, 3) j = 1 do k = 1, size(all_segments, 1)/2 all_spectrum(k, j, i) = df*(k - 1) end do end do end function ! ########################################################## ! ########################################################## subroutine write_SpectreAnalysis(this, name, all_spectrum) class(SpectreAnalysis_), intent(in) :: this character(*), intent(in) :: name real(real64), allocatable :: all_spectrum(:, :, :) type(IO_) :: f integer(int32)::nseg, segemnt_id nseg = size(all_spectrum, 3) do segemnt_id = 1, nseg call f%open(name + "_"+zfill(segemnt_id, 7) + ".tsv", "w") call f%write(all_spectrum(:, :, segemnt_id)) call f%close() end do end subroutine ! ########################################################## ! ########################################################## function masw_SpectreAnalysis(this,t,x,position,c_axis) result(ret) class(SpectreAnalysis_),intent(in) :: this real(real64),intent(in) :: t(:),x(:,:),position(:),c_axis(:) complex(real64),allocatable :: U(:,:),ret(:,:),ave_x(:) real(real64),allocatable :: x_bin(:,:),x_hanning(:,:) real(real64) :: f,w,dt integer(int32) :: num_data,num_fft integer(int32) :: i,j,k type(Math_) :: math ! zero padding and fft num_data = size(x,1) num_fft = 2**(int( log(dble(num_data))/log(2.0d0) ) + 1) U = zeros(num_fft,size(x,2)) ! 3値化 !x_bin = x !do j=1,size(x_bin,2) ! do i=1,size(x_bin,1) ! if(x_bin(i,j)>0.0d0)then ! x_bin(i,j) = 1.0d0 ! elseif(x_bin(i,j)<0.0d0)then ! x_bin(i,j) = -1.0d0 ! else ! x_bin(i,j) = 0.0d0 ! endif ! enddo !enddo x_hanning = zeros(size(x,1),size(x,2)) do i=1,size(x,1) ! time j=1 x_hanning(i,j) = 0.250d0*x(i,j) + 0.50d0*x(i,j+1) + 0.250d0*x(i,j+2) do j=2,size(x,2)-1 ! space x_hanning(i,j) = 0.250d0*x(i,j-1) + 0.50d0*x(i,j) + 0.250d0*x(i,j+1) enddo j = size(x,2) x_hanning(i,j) = 0.250d0*x(i,j-2) + 0.50d0*x(i,j-1) + 0.250d0*x(i,j) enddo ! U(1:num_data,1:size(x,2)) = x_hanning(:,:) !_bin(:,:) dt = t(2)-t(1) ! FFT for all stations ! U(x,w) do i=1,size(U,2) U(:,i) = FFT(U(:,i)) enddo ! V(k,w) ret = zeros(num_fft/2,size(c_axis)) do i=1,size(position) do j=1,size(c_axis) do k=1,num_fft/2 ! V(k,w) = exp(ikx)*U(x,w)/abs(U(x,w)) ! print *, i,j ! print *, ret(j,num_fft) ! print *, c_axis(j),position(i) ! print *, cos(c_axis(j)*position(i)) + math%i*sin(c_axis(j)*position(i)) f = ((1.0d0/dt))/(num_fft)*(k-1) w = 2.0d0*math%PI*f if (c_axis(j)==0.0d0)then cycle else if (abs(U(k,i))==0.0d0)then ret(k,j) = ret(k,j) & + 0.0d0 else ret(k,j) = ret(k,j) & + exp(math%i*w*position(i)/c_axis(j))*U(k,i)/abs(U(k,i)) endif endif enddo enddo enddo end function ! ########################################################## ! ########################################################## function fk_SpectreAnalysis(this,t,x,position,k_axis) result(z) class(SpectreAnalysis_),intent(in) :: this real(real64),intent(in) :: t(:),x(:,:),position(:),k_axis(:) complex(real64),allocatable :: U(:,:),z(:,:),ave_x(:) real(real64),allocatable :: x_hanning(:,:) real(real64) :: f,w,dt integer(int32) :: num_data,num_fft integer(int32) :: m,i,j,k,freq type(Math_) :: math ! Foti 2014 ! Chapter 4, Dispersion analysis ! Eqs. (4.42) ~ (4.44) ! zero padding and fft num_data = size(x,1) num_fft = 2**(int( log(dble(num_data))/log(2.0d0) ) + 1) U = zeros(num_fft,size(x,2)) x_hanning = zeros(size(x,1),size(x,2)) do i=1,size(x,1) ! time j=1 x_hanning(i,j) = 0.250d0*x(i,j) + 0.50d0*x(i,j+1) + 0.250d0*x(i,j+2) do j=2,size(x,2)-1 ! space x_hanning(i,j) = 0.250d0*x(i,j-1) + 0.50d0*x(i,j) + 0.250d0*x(i,j+1) enddo j = size(x,2) x_hanning(i,j) = 0.250d0*x(i,j-2) + 0.50d0*x(i,j-1) + 0.250d0*x(i,j) enddo U(1:num_data,1:size(x,2)) = x_hanning(:,:) dt = t(2)-t(1) ! time-FFT for all stations ! U(w,x) do i=1,size(U,2) U(:,i) = FFT(U(:,i)) enddo ! Z(k,w) Z = zeros(num_fft/2,size(k_axis)) ! m=1,...,M ! weight = 1 for all stations do m=1,size(position) ! summersion over m do k=1,size(k_axis) do freq=1,num_fft/2 f = ((1.0d0/dt))/(num_fft)*(k-1) w = 2.0d0*math%PI*f if (abs(U(freq,m)) ==0.0d0) cycle z(freq,k) = z(freq,k) & + U(freq,m)& *exp(math%i & *2.0d0*math%PI & *k_axis(k)*position(m))& /abs(U(freq,m)) enddo enddo enddo end function ! ########################################################## end module SpectreAnalysisClass