2026, Jan 07 01:00

Find Corner Points in Noisy Time-Series Data Using Derivatives, Second Derivative Peaks, and Curvature

Learn how to detect curve corners in time-series and signal processing with derivatives, second derivative peaks, and curvature in SciPy. Robust code.

Detecting the “corner” points of a curve is a common need in time-series analysis and signal processing. Visually, это те места, где кривая резко меняет направление — те самые оранжевые точки из иллюстрации. Простая проверка равенства соседних значений не сработает, если между разрывами значения плавают. Ниже разберем, почему так происходит и как решается задача через производные и кривизну.

The failing approach in a nutshell

Попытка поймать поворот через сравнение соседних y оборачивается лавиной ложных срабатываний. Логика выбора строится на том, что элементы до и после “поворота” будут равны, но в реальных данных между ними обычно есть вариации, и равенств нет. В результате возвращается слишком много индексов.

out_rows = []
for k in range(len(frame)):
    if k == 0 or frame['val'].iloc[k] != frame['val'].iloc[k - 1]:
        out_rows.append(frame.iloc[k])
        continue
    if k < len(frame) - 1 and frame['val'].iloc[k] != frame['val'].iloc[k + 1]:
        out_rows.append(frame.iloc[k])

Такой подход опирается на точные совпадения и обрывается там, где данные не дискретны или “ступенчатость” отсутствует.

What actually defines a corner

Смысловым признаком “угла” является смена поведения производной. Вблизи поворота градиент меняется, а вторая производная фиксирует экстремальные изменения кривизны. Это согласуется с двумя практичными ориентирами: “Look for a change of gradient.” и “Compute the second derivative, then run a peak finder. Scipy should have you covered”.

Compute the second derivative, then run a peak finder. Scipy should have you covered

Look for a change of gradient.

Отсюда простой рецепт: перейти от сравнения самих значений к анализу производных и кривизны, а затем выделить индексы, где кривизна заметно возрастает.

A practical solution with derivatives and curvature

Ниже — рабочий пример, который интерполирует ряд до равномерной сетки, вычисляет первую и вторую производные, оценивает кривизну, применяет порог и минимальный зазор между выбранными точками. Итогом становятся те самые “углы”.

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import argrelextrema
# Base samples
t_base = np.arange(0, 2200, 100)
v_base = np.array([
    -0.1, 0, 0.13, 0.27, 0.27, 0.4, 0.27, 0.27, 0.13, 0.13,
     0.01, 0.01, -0.13, -0.13, -0.27, -0.4, -0.4, -0.27, -0.13, -0.13, 0, 0
])
# Dense grid via interpolation
t_dense = np.arange(0, 2200, 1)
v_dense = np.interp(t_dense, t_base, v_base)
# First and second derivatives
dv = np.gradient(v_dense)
d2v = np.gradient(dv)
# Curvature estimate
kappa = np.abs(d2v) / (1 + dv**2)**1.5
# Thresholding and simple spacing filter
tau = 0.0005
knot_idx = np.where(kappa > tau)[0]
selected_idx = [knot_idx[0]]
for j in knot_idx[1:]:
    if j - selected_idx[-1] > 10:
        selected_idx.append(j)
# Include boundaries and finalize
selected_idx = [0] + selected_idx + [len(t_dense) - 1]
selected_idx = sorted(set(selected_idx))
# Visualization
plt.figure(figsize=(12, 6))
plt.plot(t_dense, v_dense, label='Interpolated Curve')
plt.plot(t_dense[selected_idx], v_dense[selected_idx], 'o', color='orange', label='Corners')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

Алгоритм делает то, что требуется: отмечает индексы, где кривизна превышает порог, а затем отбрасывает слишком близкие кандидаты, чтобы избежать плотной россыпи точек. Включение начала и конца массива фиксирует крайние точки кривой.

Why knowing this matters

В задачах выделения событий в данных критично ориентироваться не на “случайные” совпадения, а на динамику сигнала. Производные и кривизна позволяют переводить визуальные повороты во вполне формальные критерии. Такой подход устойчив к вариативности между точками и не завязан на искусственную равенство значений.

Conclusion

Идея проста: равенство соседних значений не отражает геометрию кривой. Чтобы найти “углы”, ориентируйтесь на производные. Интерполируйте ряд для равномерной сетки, посчитайте первую и вторую производные, оцените кривизну и выделите индексы, где она велика, с минимальным зазором между попаданиями. Этот путь повторяем, стабилен и хорошо переносится на реальные наборы данных.