алгоритм — Нахождение кривизны из зашумленного набора точек данных, используя 2d / 3dsplines? (C ++)

Я пытаюсь извлечь кривизну импульса вдоль его профиля (см. Рисунок ниже). Импульс рассчитывается по сетке длины и высоты: 150 х 100 ячеек с использованием метода конечных разностей, реализованного в C ++.

Импульсный профиль с различной кривизной

Я извлек все точки с одинаковым значением (контур / уровень) и пометил их красной непрерывной линией на рисунке ниже. Другие цвета незначительны.

красная линия = набор данных точек с одинаковым значением

Затем я попытался найти кривизну по этой уже зашумленной (из-за дискретности сетки) контурной линии следующими способами:

(скользящее среднее уже применено)

1) Кривизна через касательные
Аппроксимация кривизны из двух точек P и N

Кривизна линии в точке P определяется как:

касательные 2 точек = кривизна в одной точке

Таким образом, кривизна представляет собой кривые дельты угла по длине дуги между P и N. Поскольку мои точки имеют определенное расстояние между ними, я не смог бы достаточно приблизить изгибы, чтобы кривизна не была рассчитана правильно. Я проверил это с помощью круга, который, естественно, имеет постоянную кривизну. Но я не мог воспроизвести это (только 1 значащая цифра была правильной).

2) Вторая производная линии, параметризованная по длине дуги

Я рассчитал первую производную линии по длине дуги, сглаженную с помощью скользящего среднего, а затем снова взял производную (2-я производная). Но здесь я также получил только 1 значащую правильную цифру.
К сожалению, взятие производной умножает уже свойственный шум на более высокие уровни.

3) Локальное приближение линии кружком

Поскольку обратная величина радиуса окружности является кривизной, я использовал следующий подход:

Приближение кривизны с помощью круга

Это сработало лучше всего (2 правильные значащие цифры), но мне нужно уточнить еще дальше. Итак, моя новая идея заключается в следующем:

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

До сих пор я не мог найти библиотеку C ++, которая может генерировать такую ​​поверхность сплайна Безье. Не могли бы вы указать мне на кого-нибудь?

Кроме того, вы думаете, что этот подход стоит попробовать, или я потеряю слишком много точности в своей кривизне?

Знаете ли вы какой-либо другой подход?

С наилучшими пожеланиями,
январь

редактировать: кажется, что я не могу публиковать фотографии как новый пользователь, поэтому я удалил их все из своего вопроса, хотя я считаю, что они важны для объяснения моей проблемы. Есть ли способ, которым я все еще могу показать их?

edit2: хорошо, готово 🙂

22

Решение

Есть ALGLIB поддерживает разные виды интерполяции:

  • Полиномиальная интерполяция
  • Рациональная интерполяция
  • Сплайн-интерполяция
  • Подбор наименьших квадратов (линейный / нелинейный)
  • Билинейная и бикубическая сплайн-интерполяция
  • Быстрая RBF интерполяция / подгонка

Я не знаю, отвечает ли он всем вашим требованиям. Лично я еще не работал с этой библиотекой, но я полагаю, что кубическая сплайн-интерполяция может быть тем, что вы ищете (два раза дифференцируемо).

Чтобы предотвратить наложение на ваши шумные входные точки, вы должны применить какой-то механизм сглаживания, например, Вы можете попробовать, если применимы такие вещи, как фильтры скользящего окна, фильтры Гаусса / FIR. Также взгляните на (Кубические) сглаживающие сплайны.

1

Другие решения

Других решений пока нет …