Поиск кривизны из шумного набора точек данных с использованием 2d/3dsplines? (С++)
Я пытаюсь извлечь кривизну импульса вдоль его профиля (см. рисунок ниже). Импульс рассчитывается по сетке длины и высоты: 150 x 100 ячеек с использованием Finite Differences, реализованных на С++.
![Pulse profile with varying curvature]()
Я извлек все точки с тем же значением (набор контуров/уровней) и отметил их как красную сплошную линию на рисунке ниже. Другие цвета незначительны.
![red line = dataset of points with the same value]()
Затем я попытался найти кривизну из этой уже шумной (из-за решетки) контурной линии следующими способами:
(уже скорректированная скользящая средняя)
1) Кривизна через тангенсы
![Curvature Approximation from two Points P and N]()
Кривизна линии в точке P определяется следующим образом:
![tangents of 2 points = curvature at one point]()
Таким образом, кривизна - это лаймы угла треугольника по длине дуги между P и N. Поскольку мои точки имеют определенное расстояние между ними, я не мог достаточно приблизить лаймы, чтобы кривизна не была рассчитана правильно. Я проверил его с кругом, который, естественно, имеет постоянную кривизну. Но я не смог воспроизвести это (только 1 значащая цифра была правильной).
2) Вторая производная от строки, параметризованной arclength
Я вычислил первую производную линии по длине дуги, сглаженную скользящим средним, а затем снова взял производную (2-я производная). Но здесь я также получил только 1 значащую цифру.
К сожалению, взятие производной умножает уже присущий шум на более крупные уровни.
3) Приближение линии локально с кружком
Поскольку обратный радиус окружности - это кривизна, я использовал следующий подход:
![Approximating the curvature with a circle]()
Это работало лучше всего (2 правильных значащих цифры), но мне нужно уточнить еще больше. Итак, моя новая идея такова:
Вместо того, чтобы использовать значения в дискретных точках для определения кривизны, я хочу аппроксимировать профиль импульса трехмерной поверхностью сплайна. Затем я извлекаю из него набор уровней определенного значения, чтобы получить гладкую линию точек, из которой я могу найти хорошую кривизну.
До сих пор я не мог найти библиотеку С++, которая может генерировать такую поверхность сплайна Безье. Могли бы вы, возможно, указать мне на кого-нибудь?
И как вы думаете, этот подход стоит сделать, или я потеряю слишком большую точность в своей кривизне?
Знаете ли вы какой-либо другой подход?
С очень любезными пожеланиями,
Ян
edit: Кажется, я не могу опубликовать фотографии как новый пользователь, поэтому я удалил их все из своего вопроса, хотя я считаю их важными для объяснения моей проблемы. Есть ли способ показать их?
edit2: ok, done:)
Ответы
Ответ 1
Существует ALGLIB, который поддерживает различные варианты интерполяции:
- Полиномиальная интерполяция
- Рациональная интерполяция
- Сплийн-интерполяция
- Фиксация наименьших квадратов (линейная/нелинейная)
- Билинейная и бикубическая сплайн-интерполяция
- Быстрая интерполяция/подстановка RBF
Я не знаю, соответствует ли он всем вашим требованиям. Я лично еще не работал с этой библиотекой, но я считаю, что кубическая сплайн-интерполяция может быть тем, что вы ищете (два раза дифференцируемы).
Чтобы предотвратить перенасыщение ваших шумовых входных точек, вы должны применить какой-то механизм сглаживания, например. вы можете попробовать, если применимы такие вещи, как Moving Window Average/Gaussian/FIR. Также посмотрите на (Cubic) сглаживающие сплайны.