Самый эффективный и / или самый простой метод интерполяции нескольких массивов numpy таймсерий в один массив? - PullRequest
1 голос
/ 13 июля 2020

У меня есть три массива numpy, где один столбец - это отметка времени (Unix время с точностью до миллисекунды в виде целого числа), а другой столбец - это показание датчика (целое число). Каждый из этих трех массивов возникает одновременно во времени (ie, интервал временного столбца примерно одинаков), однако они дискретизируются на разных частотах (один - 500 Гц, другой - 125 Гц). Конечный массив должен быть (n,4) со столбцами [time, array1,array2,array3].

500.0 Hz Example (only the head, these are multiple minutes long)
array([[1463505325032,           196],
       [1463505325034,           197],
       [1463505325036,           197],
       [1463505325038,           195]])

125.0 Hz Example (only the head, these are multiple minutes long)
array([[1463505287912,         -5796],
       [1463505287920,         -5858],
       [1463505287928,         -5920],
       [1463505287936,         -5968]]) 

В настоящее время мой первоначальный план был следующим, но производительность не впечатляет:

  • Найдите самое раннее время начала (b / c разных частот и системных проблем, они не совсем все запускаются в одну и ту же миллисекунду)
  • Создайте новый массив со столбцом времени, который начинается в самое раннее время и работает как самый длинный из трех массивов. Заполните столбец времени до желаемой общей частоты, используя np.linspace / np.arange
  • L oop по трем массивам, используя np.interp или аналогичный для преобразования в общую частоту, а затем сложите выходной сигнал на общий массив numpy, созданный выше

У меня есть десятки тысяч этих интервалов, и они могут длиться несколько дней, поэтому я надеюсь на что-то достаточно быстрое и эффективное с точки зрения памяти. Спасибо!

1 Ответ

1 голос
/ 13 июля 2020

Вам нужно будет интерполировать сигнал 125 Гц, чтобы получить 500 Гц. Это зависит от того, какое качество интерполяции вам нужно. Для линейной интерполяции scipy.signal.interp1d в режиме линейной интерполяции немного медленнее, O (log n) для n точек данных, потому что он выполняет поиск пополам для каждой оценки. Время вычисления резко возрастает, если вы попросите его выполнить плавную интерполяцию на большом наборе данных, потому что это включает решение системы из 3n уравнений с 3n неизвестными.

Если ваши частоты дискретизации имеют целочисленное отношение ваш пример), вы можете выполнять линейную интерполяцию более эффективно следующим образом:

# interpolate a125 to a500
n = len(a125)
a500 = np.zeros((n-1)*4+1)
a500[0::4] = a125
a500[1::4] = 0.75*a125[:-1] + 0.25*a125[1:]
a500[2::4] = 0.5*a125[:-1] + 0.5*a125[1:]
a500[3::4] = 0.25*a125[:-1] + 0.75*a125[1:]

Если вам нужна плавная интерполяция, используйте scipy.signal.resample. Этот метод Фурье потребует тщательной обработки конечных точек вашего временного ряда; вам нужно дополнить его данными, которые делают постепенный переход от конечной точки обратно к начальной точке:

from scipy.signal import resample
m = n//8
padding = np.linspace(a125[-1], a125[0], m)
a125_pad = np.concatenate([a125, padding])
a500b = resample(a125_pad, (n+m)*4)[:4*n]

В зависимости от характера ваших данных, может быть лучше иметь непрерывную производную в конечные точки.

Обратите внимание, что БПФ, которое используется для повторной выборки, предпочитает иметь размер массива, который является произведением небольших простых чисел (2, 3, 5, 7). Выбирайте размер отступа (m) с умом.

...