質問は、時系列が定期的ではあるが異なる間隔でサンプリングされるときに、ある時系列(「拡大」)が別の時系列(「ボリューム」)にどれだけ遅れているかを見つける方法を尋ねます。
この場合、図が示すように、両方のシリーズは適度に連続的な動作を示します。これは、(1)初期スムージングがほとんどまたはまったく必要ない可能性があり、(2)リサンプリングが線形または二次補間と同じくらい簡単である可能性があることを意味します。滑らかさのために、Quadraticはわずかに優れている場合があります。 リサンプリング後、スレッドに示されているように、相互相関を最大化することによって遅延が検出されます。2つのオフセットのサンプリングデータシリーズの場合、それらの間のオフセットの最適な推定値はどれですか。。
を説明するために、質問で提供されたデータを使用R
して、擬似コードに使用できます。基本機能、相互相関、リサンプリングから始めましょう。
cor.cross <- function(x0, y0, i=0) {
#
# Sample autocorrelation at (integral) lag `i`:
# Positive `i` compares future values of `x` to present values of `y`';
# negative `i` compares past values of `x` to present values of `y`.
#
if (i < 0) {x<-y0; y<-x0; i<- -i}
else {x<-x0; y<-y0}
n <- length(x)
cor(x[(i+1):n], y[1:(n-i)], use="complete.obs")
}
これは粗雑なアルゴリズムです。FFTベースの計算の方が高速です。ただし、これらのデータ(約4000の値を含む)については十分です。
resample <- function(x,t) {
#
# Resample time series `x`, assumed to have unit time intervals, at time `t`.
# Uses quadratic interpolation.
#
n <- length(x)
if (n < 3) stop("First argument to resample is too short; need 3 elements.")
i <- median(c(2, floor(t+1/2), n-1)) # Clamp `i` to the range 2..n-1
u <- t-i
x[i-1]*u*(u-1)/2 - x[i]*(u+1)*(u-1) + x[i+1]*u*(u+1)/2
}
データをコンマ区切りのCSVファイルとしてダウンロードし、ヘッダーを削除しました。(ヘッダーが原因でRに問題が発生しましたが、私は診断を気にしませんでした。)
data <- read.table("f:/temp/a.csv", header=FALSE, sep=",",
col.names=c("Sample","Time32Hz","Expansion","Time100Hz","Volume"))
NB このソリューションは、データの各シリーズが一時的な順序であり、どちらにもギャップがないことを前提としています。 これにより、値のインデックスを時間のプロキシとして使用し、一時的なサンプリング周波数でインデックスをスケーリングして時間に変換できます。
これらの機器の一方または両方が時間の経過とともに少しドリフトすることがわかりました。先に進む前に、このような傾向を削除することをお勧めします。また、最後にボリューム信号のテーパーがあるため、クリップアウトする必要があります。
n.clip <- 350 # Number of terminal volume values to eliminate
n <- length(data$Volume) - n.clip
indexes <- 1:n
v <- residuals(lm(data$Volume[indexes] ~ indexes))
expansion <- residuals(lm(data$Expansion[indexes] ~ indexes)
結果から最高の精度を得るために、頻度の少ない系列をリサンプリングします。
e.frequency <- 32 # Herz
v.frequency <- 100 # Herz
e <- sapply(1:length(v), function(t) resample(expansion, e.frequency*t/v.frequency))
相互相関を計算できるようになりました-効率のために、妥当な時間枠のみを検索します-最大値が見つかったラグを特定できます。
lag.max <- 5 # Seconds
lag.min <- -2 # Seconds (use 0 if expansion must lag volume)
time.range <- (lag.min*v.frequency):(lag.max*v.frequency)
data.cor <- sapply(time.range, function(i) cor.cross(e, v, i))
i <- time.range[which.max(data.cor)]
print(paste("Expansion lags volume by", i / v.frequency, "seconds."))
出力から、膨張によりボリュームが1.85秒遅れていることがわかります。(データの最後の3.5秒がクリップされなかった場合、出力は1.84秒になります。)
できれば視覚的に、いくつかの方法ですべてをチェックすることをお勧めします。まず、相互相関関数:
plot(time.range * (1/v.frequency), data.cor, type="l", lwd=2,
xlab="Lag (seconds)", ylab="Correlation")
points(i * (1/v.frequency), max(data.cor), col="Red", cex=2.5)
次に、2つのシリーズを時間的に登録し、同じ軸に一緒にプロットします。
normalize <- function(x) {
#
# Normalize vector `x` to the range 0..1.
#
x.max <- max(x); x.min <- min(x); dx <- x.max - x.min
if (dx==0) dx <- 1
(x-x.min) / dx
}
times <- (1:(n-i))* (1/v.frequency)
plot(times, normalize(e)[(i+1):n], type="l", lwd=2,
xlab="Time of volume measurement, seconds", ylab="Normalized values (volume is red)")
lines(times, normalize(v)[1:(n-i)], col="Red", lwd=2)
それはかなりよさそうです! ただし、scatterplotを使用すると、登録品質のより良い感覚を得ることができます。進行状況を示すために、時間によって色を変えます。
colors <- hsv(1:(n-i)/(n-i+1), .8, .8)
plot(e[(i+1):n], v[1:(n-i)], col=colors, cex = 0.7,
xlab="Expansion (lagged)", ylab="Volume")
線に沿って前後に追跡する点を探しています。それからの変化は、体積に対する膨張の時間遅れ応答の非線形性を反映しています。いくつかのバリエーションがありますが、かなり小さいです。それでも、これらの変動が時間とともにどのように変化するかは、生理学的に興味深いものです。統計、特にその探索的および視覚的側面についてのすばらしいことは、有用な回答とともに良い質問やアイデアを作成する傾向があることです。