Кубический сплайн: различия между версиями
[непроверенная версия] | [непроверенная версия] |
отмена правки 93009475 участника 93.185.19.104 (обс.), было правильно Метка: отмена |
Ksvsvk (обсуждение | вклад) →Построение: изменены индексы интервалов |
||
(не показано 46 промежуточных версий 21 участника) | |||
Строка 1: | Строка 1: | ||
'''Кубический сплайн''' — гладкая функция, область определения которой разбита на конечное число отрезков, на каждом из которых она совпадает с некоторым кубическим многочленом (полиномом). |
|||
Некоторая функция ''f''(''x'') задана на отрезке <math>[a,b]</math>, разбитом на части <math>[x_{i-1},x_i]</math>, <math>a=x_0< x_1< ... <x_N=b</math>. [[Куб (алгебра)|Кубическим]] [[сплайн]]ом дефекта 1 называется [[Функция (математика)|функция]] <math>S(x)</math>, которая: |
|||
== Описание == |
|||
Функция <math>f(x)</math>задана на отрезке <math>[a,b]</math>, разбитом на части <math>[x_{i-1},x_i]</math>, <math>a=x_0< x_1< ... <x_N=b</math>. [[Куб (алгебра)|Кубическим]] [[сплайн]]ом дефекта 1 (разность между степенью многочлена и порядком его производной) называется [[Функция (математика)|функция]] <math>S(x)</math>, которая: |
|||
* на каждом отрезке <math>[x_{i-1},x_i]</math> является [[многочлен]]ом степени не выше третьей; |
* на каждом отрезке <math>[x_{i-1},x_i]</math> является [[многочлен]]ом степени не выше третьей; |
||
* имеет непрерывные первую и вторую [[Производная функции|производные]] на всём отрезке <math>[a,b]</math>; |
* имеет непрерывные первую и вторую [[Производная функции|производные]] на всём отрезке <math>[a,b]</math>; |
||
* в точках <math>x_i</math> выполняется равенство <math>S(x_i) = f(x_i)</math>, т. е. сплайн <math>S(x)</math> [[Интерполяция|интерполирует]] функцию |
* в точках <math>x_i</math> выполняется равенство <math>S(x_i) = f(x_i)</math>, т. е. сплайн <math>S(x)</math> [[Интерполяция|интерполирует]] функцию <math>f</math>в точках <math>x_i</math>. |
||
Для однозначного задания сплайна перечисленных условий недостаточно, для построения сплайна необходимо наложить |
Для однозначного задания сплайна перечисленных условий недостаточно, для построения сплайна необходимо наложить дополнительные требования — граничные условия: |
||
# "Естественный сплайн" — граничные условия вида: <math>S''(a) = S''(b) = 0</math>; |
|||
Естественным кубическим сплайном называется кубический сплайн, удовлетворяющий также граничным условиям вида: |
|||
: <math>S''(a) = S''(b) = 0 |
# Непрерывность второй производной — граничные условия вида: <math>S'''(a) = S'''(b) = 0</math>; |
||
# Периодический сплайн — граничные условия вида: <math>S'(a) = S'(b)</math>и <math>S''(a) = S''(b)</math>. |
|||
'''Теорема:''' Для любой функции <math>f</math> и любого разбиения отрезка <math>[a,b]</math> существует ровно один естественный сплайн |
'''Теорема:''' Для любой функции <math>f</math> и любого разбиения отрезка <math>[a,b]</math>на части <math>[x_{i-1},x_i]</math>существует ровно один естественный сплайн <math>S_{i}(x)</math>, удовлетворяющий перечисленным выше условиям. |
||
Эта теорема является следствием более общей теоремы [[Шёнберг, Исаак|Шёнберга]]-Уитни об условиях существования интерполяционного сплайна. |
Эта теорема является следствием более общей теоремы [[Шёнберг, Исаак|Шёнберга]]-Уитни об условиях существования интерполяционного сплайна. |
||
== Построение == |
== Построение == |
||
На каждом отрезке <math>[x_{i |
На каждом отрезке <math>[x_{i},x_{i+1}],\ i=\overline{0,N-1}</math> функция <math>S(x)</math> есть полином третьей степени <math>S_i(x)</math>, коэффициенты которого надо определить. Запишем для удобства <math>S_i(x)</math> в виде: |
||
: |
:<math>S_i(x) = a_i + b_i(x - x_i) + {c_i}(x-x_i)^2 + {d_i}(x - x_i)^3</math> |
||
тогда |
тогда |
||
: |
:<math>S_i\left(x_i\right) = a_i, \quad S'_i(x_i) = b_i, \quad S''_i(x_i) = 2c_i, \quad |
||
S'''_i\left(x_i\right) = 6d_i \quad i=\overline{1,N}.</math> |
|||
Условия непрерывности всех производных до второго порядка включительно |
Условия непрерывности всех производных, до второго порядка включительно, записываются в виде <br /> |
||
:<math>S_i\left(x_{i-1}\right) = S_{i-1}(x_{i-1}),</math><br /> |
|||
записываются в виде <br /> |
|||
<math> |
:<math>S'_i\left(x_{i-1}\right) = S'_{i-1}(x_{i-1}),</math><br /> |
||
<math>S'_i\left(x_{i-1}\right) = S'_{i-1}(x_{i-1})</math><br /> |
:<math>S''_i\left(x_{i-1}\right) = S''_{i-1}(x_{i-1}),</math><br /> |
||
<math>S''_i\left(x_{i-1}\right) = S''_{i-1}(x_{i-1})</math><br /> |
|||
а условия интерполяции в виде |
|||
: <math>S_i\left(x_{i}\right) = f(x_{i})</math> |
|||
где <math>i</math> меняется от <math>1</math> до <math>N,</math> а условия интерполяции в виде |
|||
Обозначим<math>: \quad h_i = x_i - x_{i-1}, \quad f_{i} = f(x_{i})</math> |
|||
:<math>S_i\left(x_{i}\right) = f(x_{i}).</math> |
|||
Обозначим<math>: \quad h_i = x_i - x_{i-1}\quad (i = \overline{1,N}), \quad f_{i} = f(x_{i})\quad (i = \overline{0,N})</math> |
|||
Отсюда получаем формулы для вычисления коэффициентов сплайна: |
|||
: <math>a_i = f\left(x_{i}\right)</math> |
|||
: <math>h_{i}c_{i-1} + 2(h_i + h_{i+1})c_i + h_{i+1}c_{i+1} = |
|||
6\left({{f_{i+1} - f_i}\over{h_{i+1}}} - {{f_{i} - f_{i-1}}\over{h_{i}}}\right)</math> |
|||
: <math>d_i = {{c_i - c_{i-1}}\over{h_i}}</math> |
|||
: <math>b_i = {1\over2}h_ic_i - {1\over6}h^2_id_i + {{f_i - f_{i-1}}\over{h_i}}= {{f_i - f_{i-1}}\over{h_i}} + {{h_i(2c_i + c_{i-1})}\over6}</math> |
|||
Отсюда получаем формулы для вычисления коэффициентов "Естественного сплайна": |
|||
Если учесть, что <math>c_0 = c_n = 0</math>, то вычисление <math>c</math> можно провести с помощью [[Метод прогонки|метода прогонки]] для [[трёхдиагональная матрица|трёхдиагональной матрицы]]. |
|||
:<math id="ai">a_{i} = f(x_{i})</math>; |
|||
:<math id="di">d_{i} = \frac{c_{i} - c_{i - 1}}{3 \cdot h_{i}}</math>; |
|||
Реализация на языке [[C++]] |
|||
:<math>b_{i} = \frac{a_{i} - a_{i - 1}}{h_{i}} - \frac{2 \cdot c_{i-1} + c_{i}}{3} \cdot h_{i}</math>; |
|||
<source lang="cpp"> |
|||
:<math id="ci">c_{i - 1} \cdot h_{i} + 2 \cdot c_{i} \cdot(h_{i} + h_{i+1}) + c_{i + 1} \cdot h_{i+1} = 3 \cdot \left(\frac{a_{i+1} - a_{i}}{h_{i+1}} - \frac{a_{i} - a_{i - 1}}{h_{i}}\right)</math>, |
|||
#include <cstdlib> |
|||
:причем <math>c_{N} = S''(x_{N}) = 0</math> и <math>c_{1} - 3 \cdot d_{1} \cdot h_{1} = S''(x_{0}) = 0</math> <ref>{{Книга|автор=Аристова Е. Н., Завьялова Н. А., Лобанов А. И.|заглавие=Практические занятия по вычислительной математике Часть 1|год=2014|язык=ru|страницы=159-160|страниц=243|isbn=978-5-7417-0541-4}}</ref>. |
|||
#include <cmath> |
|||
Если учесть, что <math>c_{0} = c_{N} = 0</math>, то вычисление <math>c</math> можно провести с помощью [[Метод прогонки|метода прогонки]] для [[трёхдиагональная матрица|трёхдиагональной матрицы]]. |
|||
#include <limits> |
|||
class cubic_spline |
|||
{ |
|||
private: |
|||
// Структура, описывающая сплайн на каждом сегменте сетки |
|||
struct spline_tuple |
|||
{ |
|||
double a, b, c, d, x; |
|||
}; |
|||
spline_tuple *splines; // Сплайн |
|||
std::size_t n; // Количество узлов сетки |
|||
void free_mem(); // Освобождение памяти |
|||
public: |
|||
cubic_spline(); //конструктор |
|||
~cubic_spline(); //деструктор |
|||
// Построение сплайна |
|||
// x - узлы сетки, должны быть упорядочены по возрастанию, кратные узлы запрещены |
|||
// y - значения функции в узлах сетки |
|||
// n - количество узлов сетки |
|||
void build_spline(const double *x, const double *y, std::size_t n); |
|||
// Вычисление значения интерполированной функции в произвольной точке |
|||
double f(double x) const; |
|||
}; |
|||
cubic_spline::cubic_spline() : splines(NULL) |
|||
{ |
|||
} |
|||
cubic_spline::~cubic_spline() |
|||
{ |
|||
free_mem(); |
|||
} |
|||
void cubic_spline::build_spline(const double *x, const double *y, std::size_t n) |
|||
{ |
|||
free_mem(); |
|||
this->n = n; |
|||
// Инициализация массива сплайнов |
|||
splines = new spline_tuple[n]; |
|||
for (std::size_t i = 0; i < n; ++i) |
|||
{ |
|||
splines[i].x = x[i]; |
|||
splines[i].a = y[i]; |
|||
} |
|||
splines[0].c = 0.; |
|||
// Решение СЛАУ относительно коэффициентов сплайнов c[i] методом прогонки для трехдиагональных матриц |
|||
// Вычисление прогоночных коэффициентов - прямой ход метода прогонки |
|||
double *alpha = new double[n - 1]; |
|||
double *beta = new double[n - 1]; |
|||
double A, B, C, F, h_i, h_i1, z; |
|||
alpha[0] = beta[0] = 0.; |
|||
for (std::size_t i = 1; i < n - 1; ++i) |
|||
{ |
|||
h_i = x[i] - x[i - 1], h_i1 = x[i + 1] - x[i]; |
|||
A = h_i; |
|||
C = 2. * (h_i + h_i1); |
|||
B = h_i1; |
|||
F = 6. * ((y[i + 1] - y[i]) / h_i1 - (y[i] - y[i - 1]) / h_i); |
|||
z = (A * alpha[i - 1] + C); |
|||
alpha[i] = -B / z; |
|||
beta[i] = (F - A * beta[i - 1]) / z; |
|||
} |
|||
splines[n - 1].c = (F - A * beta[n - 2]) / (C + A * alpha[n - 2]); |
|||
// Нахождение решения - обратный ход метода прогонки |
|||
for (int i = n - 2; i > 0; --i) |
|||
splines[i].c = alpha[i] * splines[i + 1].c + beta[i]; |
|||
// Освобождение памяти, занимаемой прогоночными коэффициентами |
|||
delete[] beta; |
|||
delete[] alpha; |
|||
// По известным коэффициентам c[i] находим значения b[i] и d[i] |
|||
for (int i = n - 1; i > 0; --i) |
|||
{ |
|||
double h_i = x[i] - x[i - 1]; |
|||
splines[i].d = (splines[i].c - splines[i - 1].c) / h_i; |
|||
splines[i].b = h_i * (2. * splines[i].c + splines[i - 1].c) / 6. + (y[i] - y[i - 1]) / h_i; |
|||
} |
|||
} |
|||
double cubic_spline::f(double x) const |
|||
{ |
|||
if (!splines) |
|||
return std::numeric_limits<double>::quiet_NaN(); // Если сплайны ещё не построены - возвращаем NaN |
|||
spline_tuple *s; |
|||
if (x <= splines[0].x) // Если x меньше точки сетки x[0] - пользуемся первым эл-том массива |
|||
s = splines + 1; |
|||
else if (x >= splines[n - 1].x) // Если x больше точки сетки x[n - 1] - пользуемся последним эл-том массива |
|||
s = splines + n - 1; |
|||
else // Иначе x лежит между граничными точками сетки - производим бинарный поиск нужного эл-та массива |
|||
{ |
|||
std::size_t i = 0, j = n - 1; |
|||
while (i + 1 < j) |
|||
{ |
|||
std::size_t k = i + (j - i) / 2; |
|||
if (x <= splines[k].x) |
|||
j = k; |
|||
else |
|||
i = k; |
|||
} |
|||
s = splines + j; |
|||
} |
|||
double dx = (x - s->x); |
|||
return s->a + (s->b + (s->c / 2. + s->d * dx / 6.) * dx) * dx; // Вычисляем значение сплайна в заданной точке. |
|||
} |
|||
void cubic_spline::free_mem() |
|||
{ |
|||
delete[] splines; |
|||
splines = NULL; |
|||
} |
|||
</source> |
|||
Реализация на языке [[C Sharp|C#]] Платформа [[.NET Framework|.NET]] |
|||
<source lang="csharp"> |
|||
// Интерполирование функций естественными кубическими сплайнами |
|||
using System; |
|||
class CubicSpline |
|||
{ |
|||
SplineTuple[] splines; // Сплайн |
|||
// Структура, описывающая сплайн на каждом сегменте сетки |
|||
private struct SplineTuple |
|||
{ |
|||
public double a, b, c, d, x; |
|||
} |
|||
// Построение сплайна |
|||
// x - узлы сетки, должны быть упорядочены по возрастанию, кратные узлы запрещены |
|||
// y - значения функции в узлах сетки |
|||
// n - количество узлов сетки |
|||
public void BuildSpline(double[] x, double[] y, int n) |
|||
{ |
|||
// Инициализация массива сплайнов |
|||
splines = new SplineTuple[n]; |
|||
for (int i = 0; i < n; ++i) |
|||
{ |
|||
splines[i].x = x[i]; |
|||
splines[i].a = y[i]; |
|||
} |
|||
splines[0].c = splines[n - 1].c = 0.0; |
|||
// Решение СЛАУ относительно коэффициентов сплайнов c[i] методом прогонки для трехдиагональных матриц |
|||
// Вычисление прогоночных коэффициентов - прямой ход метода прогонки |
|||
double[] alpha = new double[n - 1]; |
|||
double[] beta = new double[n - 1]; |
|||
alpha[0] = beta[0] = 0.0; |
|||
for (int i = 1; i < n - 1; ++i) |
|||
{ |
|||
double hi = x[i] - x[i - 1]; |
|||
double hi1 = x[i + 1] - x[i]; |
|||
double A = hi; |
|||
double C = 2.0 * (hi + hi1); |
|||
double B = hi1; |
|||
double F = 6.0 * ((y[i + 1] - y[i]) / hi1 - (y[i] - y[i - 1]) / hi); |
|||
double z = (A * alpha[i - 1] + C); |
|||
alpha[i] = -B / z; |
|||
beta[i] = (F - A * beta[i - 1]) / z; |
|||
} |
|||
// Нахождение решения - обратный ход метода прогонки |
|||
for (int i = n - 2; i > 0; --i) |
|||
{ |
|||
splines[i].c = alpha[i] * splines[i + 1].c + beta[i]; |
|||
} |
|||
// По известным коэффициентам c[i] находим значения b[i] и d[i] |
|||
for (int i = n - 1; i > 0; --i) |
|||
{ |
|||
double hi = x[i] - x[i - 1]; |
|||
splines[i].d = (splines[i].c - splines[i - 1].c) / hi; |
|||
splines[i].b = hi * (2.0 * splines[i].c + splines[i - 1].c) / 6.0 + (y[i] - y[i - 1]) / hi; |
|||
} |
|||
} |
|||
// Вычисление значения интерполированной функции в произвольной точке |
|||
public double Interpolate(double x) |
|||
{ |
|||
if (splines == null) |
|||
{ |
|||
return double.NaN; // Если сплайны ещё не построены - возвращаем NaN |
|||
} |
|||
int n = splines.Length; |
|||
SplineTuple s; |
|||
if (x <= splines[0].x) // Если x меньше точки сетки x[0] - пользуемся первым эл-тов массива |
|||
{ |
|||
s = splines[0]; |
|||
} |
|||
else if (x >= splines[n - 1].x) // Если x больше точки сетки x[n - 1] - пользуемся последним эл-том массива |
|||
{ |
|||
s = splines[n - 1]; |
|||
} |
|||
else // Иначе x лежит между граничными точками сетки - производим бинарный поиск нужного эл-та массива |
|||
{ |
|||
int i = 0; |
|||
int j = n - 1; |
|||
while (i + 1 < j) |
|||
{ |
|||
int k = i + (j - i) / 2; |
|||
if (x <= splines[k].x) |
|||
{ |
|||
j = k; |
|||
} |
|||
else |
|||
{ |
|||
i = k; |
|||
} |
|||
} |
|||
s = splines[j]; |
|||
} |
|||
double dx = x - s.x; |
|||
// Вычисляем значение сплайна в заданной точке по схеме Горнера (в принципе, "умный" компилятор применил бы схему Горнера сам, но ведь не все так умны, как кажутся) |
|||
return s.a + (s.b + (s.c / 2.0 + s.d * dx / 6.0) * dx) * dx; |
|||
} |
|||
} |
|||
</source> |
|||
Реализация на языке [[PHP]]<syntaxhighlight lang="php"> |
|||
class CubicSpline |
|||
{ |
|||
private static $_splines = []; // Сплайн |
|||
// Структура, описывающая сплайн на каждом сегменте сетки |
|||
private static $_spline_struct = [ |
|||
'a' => 0, |
|||
'b' => 0, |
|||
'c' => 0, |
|||
'd' => 0, |
|||
'x' => 0, |
|||
]; |
|||
/** |
|||
* Построение сплайна |
|||
* |
|||
* @param array $x - узлы сетки, должны быть упорядочены по возрастанию, кратные узлы запрещены |
|||
* @param array $y - значения функции в узлах сетки |
|||
* @param integer $n - количество узлов сетки |
|||
* |
|||
* @return array возвращаем страктуру сплайна |
|||
*/ |
|||
public static function buildSpline($x, $y, $n) |
|||
{ |
|||
// Инициализация массива сплайнов |
|||
for ($i = 0; $i < $n; ++$i) { |
|||
self::$_splines[$i]['x'] = $x[$i]; |
|||
self::$_splines[$i]['a'] = $y[$i]; |
|||
} |
|||
self::$_splines[0]['c'] = self::$_splines[$n - 1]['c'] = 0; |
|||
// Решение СЛАУ относительно коэффициентов сплайнов c[i] методом прогонки для трехдиагональных матриц |
|||
// Вычисление прогоночных коэффициентов - прямой ход метода прогонки |
|||
$alpha = []; |
|||
$beta = []; |
|||
$alpha[0] = $beta[0] = 0; |
|||
for ($i = 1; $i < ($n - 1); ++$i) { |
|||
$hi = $x[$i] - $x[$i - 1]; |
|||
$hi1 = $x[$i + 1] - $x[$i]; |
|||
$A = $hi; |
|||
$C = 2.0 * ($hi + $hi1); |
|||
$B = $hi1; |
|||
$F = 6.0 * (($y[$i + 1] - $y[$i]) / $hi1 - ($y[$i] - $y[$i - 1]) / $hi); |
|||
$z = ($A * $alpha[$i - 1] + $C); |
|||
$alpha[$i] = -$B / $z; |
|||
$beta[$i] = ($F - $A * $beta[$i - 1]) / $z; |
|||
} |
|||
// Нахождение решения - обратный ход метода прогонки |
|||
for ($i = ($n - 2); $i > 0; --$i){ |
|||
self::$_splines[$i]['c'] = $alpha[$i] * self::$_splines[$i + 1]['c'] + $beta[$i]; |
|||
} |
|||
// По известным коэффициентам c[i] находим значения b[i] и d[i] |
|||
for ($i = ($n - 1); $i > 0; --$i) { |
|||
$hi = $x[$i] - $x[$i - 1]; |
|||
self::$_splines[$i]['d'] = (self::$_splines[$i]['c']- self::$_splines[$i - 1]['c']) / $hi; |
|||
self::$_splines[$i]['b'] = $hi * (2.0 * self::$_splines[$i]['c'] + self::$_splines[$i - 1]['c']) / 6.0 + ($y[$i] - $y[$i - 1]) / $hi; |
|||
} |
|||
return self::$_splines; |
|||
} |
|||
// Вычисление значения интерполированной функции в произвольной точке |
|||
public static function interpolate($x) |
|||
{ |
|||
if (self::$_splines == null) { |
|||
return null; // Если сплайны ещё не построены - возвращаем NULL |
|||
} |
|||
$n = count(self::$_splines); |
|||
$s = self::$_spline_struct; |
|||
if ($x <= self::$_splines[0]['x']) { // Если x меньше точки сетки x[0] - пользуемся первым эл-тов массива |
|||
$s = self::$_splines[0]; |
|||
} elseif ($x >= self::$_splines[$n - 1]['x']) { // Если x больше точки сетки x[n - 1] - пользуемся последним эл-том массива |
|||
$s = self::$_splines[$n - 1]; |
|||
} else { // Иначе x лежит между граничными точками сетки - производим бинарный поиск нужного эл-та массива |
|||
$i = 0; |
|||
$j = $n - 1; |
|||
while (($i + 1) < $j) { |
|||
$k = $i + ($j - $i) / 2; |
|||
if ($x <= self::$_splines[$k]['x']) { |
|||
$j = $k; |
|||
} else { |
|||
$i = $k; |
|||
} |
|||
} |
|||
$s = self::$_splines[$j]; |
|||
} |
|||
$dx = $x - $s['x']; |
|||
// Вычисляем значение сплайна в заданной точке по схеме Горнера (в принципе, "умный" компилятор применил бы схему Горнера сам, но ведь не все так умны, как кажутся) |
|||
return $s['a'] + ($s['b'] + ($s['c'] / 2.0 + $s['d'] * $dx / 6.0) * $dx) * $dx; |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
Python 2.7, шаг постоянный |
|||
<source lang="python"> |
|||
from collections import defaultdict |
|||
from matplotlib import mlab |
|||
import bisect, pylab, math |
|||
def drange(start, stop, step): |
|||
while start < stop: yield start; start += step; |
|||
class Dot: |
|||
def __init__(self, x, y): self.x, self.y = [x, y] |
|||
class Tuple: a, b, c, d, x = [0., 0., 0., 0., 0.] |
|||
def buildSpline(dots): |
|||
for i in range(len(dots)): splines[i].x, splines[i].a = dots[i].x, dots[i].y |
|||
alpha, beta = [defaultdict(lambda: 0.), defaultdict(lambda: 0.)] |
|||
for i in range(1, len(dots)-1): |
|||
C = 4. * in_step |
|||
F = 6. * ((dots[i + 1].y - dots[i].y) / in_step - (dots[i].y - dots[i - 1].y) / in_step) |
|||
z = (in_step* alpha[i - 1] + C) |
|||
alpha[i] = -in_step / z |
|||
beta[i] = (F - in_step* beta[i - 1]) / z |
|||
for i in reversed(range(1, len(dots) - 1)): splines[i].c = alpha[i] * splines[i+1].c + beta[i] |
|||
for i in reversed(range(1, len(dots))): |
|||
hi = dots[i].x - dots[i-1].x |
|||
splines[i].d = (splines[i].c - splines[i-1].c) / hi |
|||
splines[i].b = hi * (2.0 * splines[i].c + splines[i - 1].c) / 6.0 + (dots[i].y - dots[i-1].y) / hi |
|||
def calc(x): |
|||
distribution = sorted([t[1].x for t in splines.items()]) |
|||
indx = bisect.bisect_left(distribution, x) |
|||
if indx == len(distribution): return 0 |
|||
dx = x - splines[indx].x |
|||
return splines[indx].a + splines[indx].b * dx + splines[indx].c * dx**2 / 2. + splines[indx].d * dx**3 / 6. |
|||
#============================================ |
|||
in_func = lambda x: math.sin(x) |
|||
in_min_x = 0 |
|||
in_max_x = 25 |
|||
in_step = 2.5 |
|||
out_min_x = 0 |
|||
out_max_x = 25 |
|||
out_step = 0.1 |
|||
#============================================ |
|||
#build model |
|||
splines = defaultdict(lambda: Tuple()) |
|||
buildSpline(map(lambda x: Dot(x, in_func(x)), [x for x in drange(in_min_x, in_max_x+1, in_step)])) |
|||
#print result |
|||
for x in drange(out_min_x, out_max_x, out_step): |
|||
print str(x) + ';' + str(calc(x)) |
|||
#build graphics |
|||
xlist = mlab.frange (out_min_x, out_max_x, out_step) |
|||
pylab.plot(xlist, [calc(x) for x in xlist]) |
|||
pylab.plot(xlist, [in_func(x) for x in xlist]) |
|||
pylab.show() |
|||
</source> |
|||
== Литература == |
== Литература == |
||
# {{книга | автор = de Boor, Carl | заглавие = A Practical Guide to Splines | ссылка = https://archive.org/details/practicalguideto0027debo | издательство=Springer-Verlag | место=New York | год = 1978 | ref = Boor}} |
|||
* {{книга|автор=Роджерс Д., Адамс Дж.|заглавие=Математические основы машинной графики|издательство=Мир|место=М.|Издание=2-е, перераб. и доп.|станиц=604|год=2001|isbn=5-03-002143-4}} |
|||
# {{книга|автор=Роджерс Д., Адамс Дж.|заглавие=Математические основы машинной графики|издательство=Мир|место=М.|Издание=2-е, перераб. и доп.|станиц=604|год=2001|isbn=5-03-002143-4}} |
|||
* {{книга|автор=Костомаров Д. П., Фаворский А. П.|заглавие=Вводные лекции по численным методам}} |
|||
# {{книга|автор=[[Костомаров, Дмитрий Павлович|Костомаров Д. П.]], [[Фаворский, Антон Павлович|Фаворский А. П.]]|заглавие=Вводные лекции по численным методам}} |
|||
* {{книга |автор=Волков Е. А. |заглавие=Численные методы |издание=Учеб. пособие для вузов. — 2-е изд., испр. |место={{М.}} |издательство=Наука |год=1987 |страниц=248 |часть=Глава 1. Приближение функций многочленами. § 11. Сплайны |страницы=63-68}} |
|||
# {{книга |автор=Волков Е. А. |заглавие=Численные методы |издание=Учеб. пособие для вузов. — 2-е изд., испр. |место={{М.}} |издательство=Наука |год=1987 |страниц=248 |часть=Глава 1. Приближение функций многочленами. § 11. Сплайны |страницы=63-68}} |
|||
== Ссылки == |
== Ссылки == |
||
* [http://rudtp.pp.ru/cubicspline/ Интерполяция кубическими сплайнами на JavaScript (рус.)] |
* [http://rudtp.pp.ru/cubicspline/ Интерполяция кубическими сплайнами на JavaScript (рус.)] |
||
* [https://github.com/ValexCorp/Cubic-Interpolation Cubic Interpolation] {{sfn|Boor|1978}} |
|||
== Примечания == |
|||
{{примечания}} |
|||
{{rq|refless}} |
{{rq|refless}} |
||
Строка 472: | Строка 65: | ||
[[Категория:Численные методы]] |
[[Категория:Численные методы]] |
||
[[Категория:Интерполяция]] |
[[Категория:Интерполяция]] |
||
[[Категория:Статьи с примерами кода C++]] |
Текущая версия от 06:38, 15 октября 2024
Кубический сплайн — гладкая функция, область определения которой разбита на конечное число отрезков, на каждом из которых она совпадает с некоторым кубическим многочленом (полиномом).
Описание
[править | править код]Функция задана на отрезке , разбитом на части , . Кубическим сплайном дефекта 1 (разность между степенью многочлена и порядком его производной) называется функция , которая:
- на каждом отрезке является многочленом степени не выше третьей;
- имеет непрерывные первую и вторую производные на всём отрезке ;
- в точках выполняется равенство , т. е. сплайн интерполирует функцию в точках .
Для однозначного задания сплайна перечисленных условий недостаточно, для построения сплайна необходимо наложить дополнительные требования — граничные условия:
- "Естественный сплайн" — граничные условия вида: ;
- Непрерывность второй производной — граничные условия вида: ;
- Периодический сплайн — граничные условия вида: и .
Теорема: Для любой функции и любого разбиения отрезка на части существует ровно один естественный сплайн , удовлетворяющий перечисленным выше условиям.
Эта теорема является следствием более общей теоремы Шёнберга-Уитни об условиях существования интерполяционного сплайна.
Построение
[править | править код]На каждом отрезке функция есть полином третьей степени , коэффициенты которого надо определить. Запишем для удобства в виде:
тогда
Условия непрерывности всех производных, до второго порядка включительно, записываются в виде
где меняется от до а условия интерполяции в виде
Обозначим
Отсюда получаем формулы для вычисления коэффициентов "Естественного сплайна":
- ;
- ;
- ;
- ,
- причем и [1].
Если учесть, что , то вычисление можно провести с помощью метода прогонки для трёхдиагональной матрицы.
Литература
[править | править код]- de Boor, Carl. A Practical Guide to Splines. — New York: Springer-Verlag, 1978.
- Роджерс Д., Адамс Дж. Математические основы машинной графики. — М.: Мир, 2001. — ISBN 5-03-002143-4.
- Костомаров Д. П., Фаворский А. П. Вводные лекции по численным методам.
- Волков Е. А. Глава 1. Приближение функций многочленами. § 11. Сплайны // Численные методы. — Учеб. пособие для вузов. — 2-е изд., испр.. — М.: Наука, 1987. — С. 63-68. — 248 с.
Ссылки
[править | править код]Примечания
[править | править код]- ↑ Аристова Е. Н., Завьялова Н. А., Лобанов А. И. Практические занятия по вычислительной математике Часть 1ISBN 978-5-7417-0541-4. . — 2014. — С. 159-160. — 243 с. —
- ↑ Boor, 1978.
Для улучшения этой статьи желательно:
|