Я использовал один из предложенных алгоритмов, но результаты очень плохие.
Я реализовал алгоритм вики
в Java (код ниже). x(0)
является points.get(0)
, y(0)
является values[points.get(0)]
, α
является alfa
а также μ
является mi
, Остальное такое же, как в псевдокоде вики.
public void createSpline(double[] values, ArrayList<Integer> points){
a = new double[points.size()+1];
for (int i=0; i <points.size();i++)
{
a[i] = values[points.get(i)];
}
b = new double[points.size()];
d = new double[points.size()];
h = new double[points.size()];
for (int i=0; i<points.size()-1; i++){
h[i] = points.get(i+1) - points.get(i);
}
alfa = new double[points.size()];
for (int i=1; i <points.size()-1; i++){
alfa[i] = (double)3 / h[i] * (a[i+1] - a[i]) - (double)3 / h[i-1] *(a[i+1] - a[i]);
}
c = new double[points.size()+1];
l = new double[points.size()+1];
mi = new double[points.size()+1];
z = new double[points.size()+1];
l[0] = 1; mi[0] = z[0] = 0;
for (int i =1; i<points.size()-1;i++){
l[i] = 2 * (points.get(i+1) - points.get(i-1)) - h[i-1]*mi[i-1];
mi[i] = h[i]/l[i];
z[i] = (alfa[i] - h[i-1]*z[i-1])/l[i];
}
l[points.size()] = 1;
z[points.size()] = c[points.size()] = 0;
for (int j=points.size()-1; j >0; j--)
{
c[j] = z[j] - mi[j]*c[j-1];
b[j] = (a[j+1]-a[j]) - (h[j] * (c[j+1] + 2*c[j])/(double)3) ;
d[j] = (c[j+1]-c[j])/((double)3*h[j]);
}for (int i=0; i<points.size()-1;i++){
for (int j = points.get(i); j<points.get(i+1);j++){
// fk[j] = values[points.get(i)];
functionResult[j] = a[i] + b[i] * (j - points.get(i))
+ c[i] * Math.pow((j - points.get(i)),2)
+ d[i] * Math.pow((j - points.get(i)),3);
}
}
}
В результате я получаю следующее:
но это должно быть похоже на это:
Я также пытаюсь реализовать алгоритм по-другому в соответствии с: http://www.geos.ed.ac.uk/~yliu23/docs/lect_spline.pdf
Сначала они показывают, как сделать линейный сплайн, и это довольно просто. Я создаю функции, которые рассчитывают A
а также B
коэффициенты. Затем они расширяют линейный сплайн, добавляя вторую производную. C
а также D
Коэффициенты тоже легко рассчитать.
Но проблемы начинаются, когда я пытаюсь вычислить вторую производную. Я не понимаю, как они их рассчитывают.
Поэтому я реализовал только линейную интерполяцию. Результат:
Кто-нибудь знает, как исправить первый алгоритм или объяснить, как вычислить вторую производную во втором алгоритме?
Кубический b-сплайн был недавно описан в серии статей Unser, Thévenaz и другие., увидеть среди других
М. Унсер, А. Алдруби, М. Иден, «Быстрые B-сплайн-преобразования для непрерывного представления и интерполяции изображений», IEEE Trans. Pattern Анальный. Машина Интелл., том 13, н. 3, с. 277-285, март 1991 г.
М. Унсер, «Сплайны, идеально подходящие для обработки сигналов и изображений», IEEE Signal Proc. Магнето, с. 22- 38, ноябрь 1999 г.
а также
П. Тевеназ, Т. Блу, М. Унсер, «Возвращение к интерполяции» IEEE Trans. по медицинской визуализации, том 19, нет. 7, с. 739-758, июль 2000 г.
Вот несколько рекомендаций.
Что такое сплайны?
Сплайны — это кусочно-полиномы, которые гладко связаны друг с другом. За сплайн степени n
каждый сегмент является полиномом степени n
, Части связаны так, что сплайн непрерывен до его производной степени n-1
на узлы, а именно, точки соединения частей полинома.
Как можно построить сплайны?
Сплайн нулевого порядка следующий
Все остальные сплайны могут быть построены как
где сверток взят n-1
раз.
Кубические сплайны
Самые популярные сплайны — кубические сплайны, чье выражение
Сплайн-интерполяция
Учитывая функцию f(x)
выборка в дискретных целочисленных точках k
, задача сплайн-интерполяции состоит в определении аппроксимации s(x)
в f(x)
выражается следующим образом
где ck
это коэффициенты интерполяции и s(k) = f(k)
,
Сплайн-предварительная фильтрация
К сожалению, начиная с n=3
на,
таким образом ck
это не коэффициенты интерполяции. Их можно определить, решив линейную систему уравнений, полученную путем принуждения s(k) = f(k)
а именно
Такое уравнение может быть преобразовано в форму свертки и решено в преобразованном z
пространство как
где
Соответственно,
Такой путь всегда предпочтительнее, чем решение линейной системы уравнений, например, LU
разложение.
Решение вышеприведенного уравнения можно определить, заметив, что
где
Первая фракция является представителем причинный фильтр, в то время как второй является представителем противоопухолевый фильтр. Оба они показаны на рисунках ниже.
Причинный фильтр
Антикаузальный фильтр
На последнем рисунке
Выходные данные фильтров могут быть выражены следующими рекурсивными уравнениями
Вышеприведенные уравнения могут быть решены путем первого определения «начальных условий» для c-
а также c+
, Предполагая периодическое, зеркальные входная последовательность fk
такой, что
тогда можно показать, что начальное условие для c+
может быть выражено как
в то время как начальное условие для c+
может быть выражено как
Извините, но Ваш исходный код действительно нечитаемый беспорядок для меня, поэтому я придерживаюсь теории. Вот несколько советов:
SPLINE кубики
SPLINE это не интерполяция, а приближение чтобы использовать их, вам не нужно никакого деривации. Если у вас есть десять очков: p0,p1,p2,p3,p4,p5,p6,p7,p8,p9
затем кубический сплайн начинается / заканчивается тройной точкой. Если вы создаете функцию «рисовать» СПЛАЙН Затем исправьте кубическую кривую, чтобы обеспечить непрерывность последовательности вызовов:
spline(p0,p0,p0,p1);
spline(p0,p0,p1,p2);
spline(p0,p1,p2,p3);
spline(p1,p2,p3,p4);
spline(p2,p3,p4,p5);
spline(p3,p4,p5,p6);
spline(p4,p5,p6,p7);
spline(p5,p6,p7,p8);
spline(p6,p7,p8,p9);
spline(p7,p8,p9,p9);
spline(p8,p9,p9,p9);
не забывайте, что кривая SPLINE для p0,p1,p2,p3
нарисовать только кривую «между» p1,p2
!!!
Безье кубики
4-точечный Безье Коэффициенты могут быть вычислены следующим образом:
a0= ( p0);
a1= (3.0*p1)-(3.0*p0);
a2= (3.0*p2)-(6.0*p1)+(3.0*p0);
a3=( p3)-(3.0*p2)+(3.0*p1)-( p0);
интерполирование
чтобы использовать интерполяцию, вы должны использовать интерполяционные полиномы. Есть много, но я предпочитаю использовать кубики … похоже на Безье / СПЛАЙН / NURBS … так
p(t) = a0+a1*t+a2*t*t+a3*t*t*t
где t = <0,1>
Осталось только вычислить a0,a1,a2,a3
, У вас есть 2 уравнения (p(t)
и его вывод по t
) и 4 балла из набора данных. Вы также должны обеспечить непрерывность … Таким образом, первый вывод для точек соединения должен быть одинаковым для соседних кривых (t=0,t=1
). Это приводит к системе 4 линейных уравнений (использование t=0
а также t=1
). Если вы получите его, он создаст простое уравнение, зависящее только от координат входной точки:
double d1,d2;
d1=0.5*(p2-p0);
d2=0.5*(p3-p1);
a0=p1;
a1=d1;
a2=(3.0*(p2-p1))-(2.0*d1)-d2;
a3=d1+d2+(2.0*(-p2+p1));
последовательность вызовов такая же, как для СПЛАЙН
[Заметки]
Разница между интерполяцией и аппроксимацией заключается в том, что:
Кривая интерполяции всегда проходит через контрольные точки, но многочлены высокого порядка имеют тенденцию колебаться, и приближение только приближается к контрольным точкам (в некоторых случаях может пересекать их, но обычно нет).
переменные:
a0,... p0,...
являются векторами (число измерений должно соответствовать входным точкам)t
является скалярнымрисовать кубики из коэффициентов a0,..a3
просто сделайте что-то вроде этого:
MoveTo(a0.x,a0.y);
for (t=0.0;t<=1.0;t+=0.01)
{
tt=t*t;
ttt=tt*t;
p=a0+(a1*t)+(a2*tt)+(a3*ttt);
LineTo(p.x,p.y);
}
Увидеть сплайн-интерполяция, хотя они дают только полезный пример 3х3. Для большего количества точек выборки, скажем, N + 1 перечислил x[0..N]
со значениями y[0..N]
нужно решить следующую систему для неизвестного k[0..N]
2* c[0] * k[0] + c[0] * k[1] == 3* d[0];
c[0] * k[0] + 2*(c[0]+c[1]) * k[1] + c[1] * k[2] == 3*(d[0]+d[1]);
c[1] * k[1] + 2*(c[1]+c[2]) * k[2] + c[2] * k[3] == 3*(d[1]+d[2]);
c[2] * k[2] + 2*(c[2]+c[3]) * k[3] + c[3] * k[4] == 3*(d[2]+d[3]);
...
c[N-2]*k[N-2]+2*(c[N-2]+c[N-1])*k[N-1]+c[N-1]*k[N] == 3*(d[N-2]+d[N-1]);
c[N-2]*k[N-1] + 2*c[N-1] * k[N] == 3* d[N-1];
где
c[k]=1/(x[k+1]-x[k]); d[k]=(y[k+1]-y[k])*c[k]*c[k];
Эту проблему можно решить с помощью итерации Гаусса-Зейделя (не было ли она изобретена именно для этой системы?) Или вашего любимого космического решателя Крылова.