今回はパワースペクトルが,
を定数として,
の形になる,差分方程式で記述される確率過程を考えます.前の記事
chaos-kiyono.hatenablog.com
で,m階積分 (和分)過程のパワースペクトル(もどき)を計算しました.つまり,
ということを書きました.「パワースペクトル(もどき)」と表現したのは,のとき非定常なので,自己共分散 (自己相関)関数のフーリエ変換としてのパワースペクトルが存在しないからです.でも,有限の長さの時系列サンプルがあって,その時系列のフーリエ変換を使ってパワースペクトルを計算すると,上の関数になるはずです.私は数学者ではないので,定常の範囲とか,そんなこと全く気にしません.ですので,今回は
の世界も考えます.
ということで,前の記事では,は整数でした.
が正のとき,
階積分 (和分)過程,負の値のとき,
階差分過程になります.
これらの過程では,
になるので,の形になってます.でも残念なことに,
は,2の倍数の整数しかとれません.
何とか,いろんな実数をとれるようにできないでしょうか
「そんなの簡単だろ,を整数から実数に拡張すれば,
はどんな値でもとれるだろ」と考えたあなたは,枠に収まらない人間です.
問題は,対応する差分方程式がどうなるかです.この問題は既に考えられていて,答えがあります.
という風に,の部分を展開してやることで,
の重み付き和として,
の値を計算することができます.
ARFIMAでは,ここでの
が,
の値で,
の範囲を考えます.これは,定常がどうとかいうことで範囲が決まっています.
しかし私には,こんな範囲の制限を守る気はないので,の値をもっと広い範囲で変えて数値実験してみます.つまり,
を平均0,分散
の白色ノイズとして,次の式を使って
を計算します.
以下は,ARFIMAでは,やってはダメな領域の結果ですので,決して真似しないでください.責任はとれません.
出発点の1階の積分過程を確認
が,1階の積分過程です.やってみた結果が下の図です.図は,左が
の値,中がサンプル時系列,右が200個のサンプル時系列から推定したパワースペクトルの平均です.

問題なく,
になってくれました.積分過程では,上左図のように,和をとる重みは1で一定になります.昔の値を積分 (和分)するので,当然です.
1/fノイズ生成に挑戦
1/fノイズは, (
に相当)とすれば,生成できそうです.やってみた結果が下の図です.

期待通り,
になってくれました.上左図のように,和をとる重みは,単調減少しますが,0には,なかなか,なりません.
失敗例
私の数値実験では,の領域において,期待通り
になりました.しかし.それよりも大きな値を設定すると,うまくいきませんでした.下の図は,
の結果です.明らかにずれています.

の領域では,和をとる重み
が,過去に戻るほど,大きな値になっています.これは,さすがに不自然ですし,値が異常に大きくなると思います.
まとめ
今回は,ARFIMAの説明をしようと思いましたが,やめました.ARFIMA
では想定していない外れの領域の数値実験をしました.
の領域も,非定常ですが,期待通りのパワースペクトルを示してくれました.
おまけ
使用したRスクリプトです.
########################### # 平均をとるサンプル時系列数 N.samps <- 100 ########################## # 時系列の長さ (時系列は奇数長になります) N <- 1001 # 奇数に変換 N <- round(N/2)*2+1 # 半分 M <- (N-1)/2 ######################### # パラメタの設定 m <- 0.5 sig2 <- 1 sig <- sqrt(sig2) ######################### # 数値実験 j.max <- N j <- 0:j.max coef <- exp(lgamma(j+m)-lgamma(j+1)-lgamma(m)) for(i in 1:N.samps){ ######################### # 白色ノイズの生成 w <- rnorm(N+j.max,0,sig) ######################### if(m == 0){ x.sim <- w[1:N] }else{ x.sim <- c() for(k in 1:N){ x.sim[k] <- w[(k+j.max):k] %*% coef } } ######################### # PSDの推定 tmp <- fft(x.sim) PSD <- abs(tmp)^2/N if(i == 1){ PSD.samps <- data.frame(PSD) }else{ PSD.samps <- cbind(PSD.samps,data.frame(PSD)) } } # サンプルの平均 PSD <- rowMeans(PSD.samps) ######################### # 結果の描画 # モデルのパワースペクトルを与える PSD.model <- function(f,m,sig2){ return((f!=0)*sig2/(2*abs(sin(pi*f)))^(2*m)) } ######################### # f = 0を避けて計算 f <- c((1:M)/N,-(M:1)/(N)) # f = 0のとき,パワースペクトルを0に設定 PSD.model <- c(0,PSD.model(f,m,sig2)) f <- c(0,(1:M)/N,-(M:1)/(N)) par(mfrow=c(1,3),cex.lab=1.4) plot(0:j.max,coef,"l",col=4,lwd=2,xlab="j",ylab="Weight",xaxs="i",las=1) abline(h=0,lty=2,col=8) plot(0:(N-1),x.sim,"l",xaxs="i",col=4,xlab="i",ylab="x[i]",main=paste("Synthetic Time Series: m =",m),lwd=2,las=1) # shift.PSD <- mean(PSD[f > 0]/PSD.model[f > 0]) plot(f[f > 0],PSD[f > 0],"l",log="xy",col=4,pch=16,xlim=c(f[2],0.5),xaxs="i",xlab="f",ylab="",main="Power Spectrum",lwd=4,las=1) lines(f[f > 0],PSD.model[f > 0]*shift.PSD,col=2,lwd=2,lty=2) legend("topright", legend=c(paste("Target PSD: beta =",2*m)), col=c(2), lty=c(2),lwd=c(2)) axis(1,at=10^(-15:15)%x%(1:9),label=FALSE,tck=-0.015) axis(2,at=10^(-15:15)%x%(1:9),label=FALSE,tck=-0.015)