Як я можу вирівняти / синхронізувати два сигнали?


21

Я займаюся деякими дослідженнями, але застряг на етапі аналізу (варто було б приділити більше уваги моїм лекціям із статистики).

Я зібрав два одночасні сигнали: витрата інтегрований для гучності і зміни розширення грудної клітки. Я хотів би порівняти сигнали і, зрештою, сподіваюся отримати гучність від сигналу розширення грудної клітки. Але спочатку я повинен вирівняти / синхронізувати свої дані.

Оскільки запис не починається точно в той самий час, і розширення грудної клітки фіксується протягом більш тривалих періодів, мені потрібно знайти дані, які відповідають моїм даних про об'єм, у межах набору даних про розширення грудної клітки, і визначити, наскільки вони вирівняні. Я не зовсім впевнений, як це зробити, якщо два сигнали не починаються точно в один і той же час або між даними в різних масштабах і з різною роздільною здатністю.

Я додав приклад двох сигналів ( https://docs.google.com/spreadsheet/ccc?key=0As4oZTKp4RZ3dFRKaktYWEhZLXlFbFVKNmllbGVXNHc ), будь ласка, повідомте мене, чи можу я надати щось далі.


Я не знаю цього досить добре, щоб дати відповідь, і я не впевнений, що це вирішує питання, але один підхід синхронізує сигнали називається "реєстрація", що є підмножиною функціонального аналізу даних. Ця тема обговорюється в книзі Рамзі та Сільвермена про FDA. Основна ідея полягає в тому, що спостережувані сигнали можуть бути "викривленими" (наприклад, якщо нас цікавила механіка того, як люди жують, але у нас є дані про людей, що жують з різною швидкістю - ось часу в цьому випадку "викривляється") і спроби реєстрації визначити базовий сигнал у загальній, "непідвладній" шкалі.
Макрос

1
Ви вже зібрали всі свої дані? Це один експериментальний предмет? Якщо ви тільки починаєте роботу, я б розглядав, як відключити сигнал від вашого пояса і використовувати його як тригер (або навіть просто для позначення часової позначки) вашого потокового запису. Зазвичай системи придбання мають таку можливість за допомогою допоміжного або тригерного порту. Я впевнений, що існують способи розрізнити це лише за допомогою даних, як макрос запропонував, але додавання цього додаткового кроку забирає багато здогадок.
jonsca

1
Я думаю, ви хочете оцінити лише фіксовану затримку. Ви можете використовувати перехресну кореляцію, як описано тут: stats.stackexchange.com/questions/16121/…
thias

1
Ви можете задати це питання на dsp.SE, де вони також думають про синхронізацію сигналів.
Діліп Сарват

1
@Thias є правильним, але, здається, спочатку одну серію слід переупорядкувати, щоб вони мали загальні інтервали.
whuber

Відповіді:


24

Питання задає питання, як знайти суму, на яку один часовий ряд ("розширення") відстає інший ("об'єм"), коли рядки відбираються через регулярні, але різні інтервали.

У цьому випадку обидві серії демонструють досить постійну поведінку, як це показують фігури. Це означає, що (1) початкове згладжування може бути мало або взагалі не потрібно, і (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"))

Примітка. Це рішення передбачає, що кожна серія даних знаходиться у часовому порядку, без жодних прогалин в жодній. Це дозволяє йому використовувати індекси у значеннях як проксі-сервери за часом та масштабувати ці індекси за тимчасовими частотами вибірки, щоб перетворити їх у рази.

Виявляється, один чи обидва ці інструменти з часом трохи дрейфують. Добре усунути такі тенденції, перш ніж продовжувати. Крім того, оскільки в кінці звужується сигнал гучності, ми повинні вирізати його.

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)

перехресний кореляційний сюжет

Далі реєструємо два ряди в часі та будуємо їх разом на одних осях .

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)

Зареєстровані ділянки

Це виглядає досить добре! Однак ми можемо краще зрозуміти якість реєстрації за допомогою розсіювача . Я змінюю кольори за часом, щоб показати прогресію.

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")

Діаграма розкиду

Ми шукаємо точки, які слід відслідковувати вперед і назад по лінії: відхилення від цього відображають нелінійності в часовій відповіді розширення на об'єм. Хоча існують деякі варіанти, вони досить малі. Тим не менш, те , як ці зміни змінюються з часом, може представляти певний фізіологічний інтерес. Чудова річ у статистиці, особливо її дослідницькому та візуальному аспекті, - це те, як вона має тенденцію створювати хороші запитання та ідеї разом із корисними відповідями.


1
Боже пекло, ти дивовижна. Перехресна кореляція - це саме те, що я собі уявляв (я знав, що має бути ім’я для цього), але ваша відповідь / пояснення виходила вище та далі. Дуже дякую!
person157

Зараз я не маю часу на повне пояснення, але в книгах "Числові рецепти" з'являється чудова історія. Наприклад, подивіться на главу 13.2, «кореляції і автокореляції з допомогою ШПФ," в Numerical Recipes в C . Ви також можете вивчити acfфункцію R.
whuber

Нове в 'r', будь ласка, будь ласка: Функція 'нормалізувати', яка використовується в комбінованому сюжеті (другий останній графік), не працюватиме для мене, чи є оновлення цієї функції з моменту опублікування цієї відповіді?
CmKndy

1
@CmKndy Я теж був новаком R, коли я опублікував цю відповідь і просто забув надати визначення для цієї функції. Ось оригінал:normalize <- function(x) { x.max <- max(x); x.min <- min(x); dx <- x.max - x.min; if (dx==0) dx <- 1; (x-x.min) / dx }
whuber

Ідеально, дякую @whuber. Якщо ви зможете опублікувати таку відповідь, коли ви були
новачками
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.