Splines cubiques — Principe et construction

Objectifs d'apprentissage

À la fin de cette leçon, vous serez en mesure de :

  • Comprendre l'origine physique des splines (ruban flexible)
  • Écrire la forme générale d'un polynôme cubique par morceaux
  • Établir les conditions de continuité pour ff, ff' et ff''
  • Dériver le système d'équations pour les dérivées secondes SiS_i

Prérequis

  • Interpolation polynomiale
  • Notion de continuité et dérivabilité
  • Résolution de systèmes linéaires

Motivation : dépasser les limites des polynômes

Le problème

Nous avons vu que l'interpolation polynomiale de Lagrange ou Newton-Gregory fonctionne bien avec peu de points. Mais dès que le nombre de points augmente, le degré du polynôme augmente aussi — et avec lui les oscillations parasites (phénomène de Runge). Ajouter des points pour mieux coller aux données empire souvent le résultat.

L'idée des splines

La solution est simple : au lieu d'un seul polynôme de degré élevé, utiliser plusieurs polynômes de degré faible raccordés entre eux. Chaque morceau reste un polynôme cubique (degré 3), ce qui suffit pour avoir une courbe lisse sans oscillation.

Le terme « spline » vient de l'outil des dessinateurs : une lame flexible (ruban de bois ou de métal) que l'on fait passer par des points de contrôle. La forme naturelle de cette lame minimise l'énergie de flexion, ce qui correspond mathématiquement à une spline cubique.


Définition d'une spline cubique

Structure

Une spline cubique sur nn points (x1,y1),(x2,y2),,(xn,yn)(x_1, y_1), (x_2, y_2), \ldots, (x_n, y_n) est constituée de n1n-1 polynômes cubiques :

Qi(x),i=1,2,,n1Q_i(x), \quad i = 1, 2, \ldots, n-1

Qi(x)Q_i(x) est défini sur l'intervalle [xi,xi+1][x_i, x_{i+1}].

Forme des polynômes

Chaque polynôme Qi(x)Q_i(x) s'écrit sous la forme :

Qi(x)=ai(xxi)3+bi(xxi)2+ci(xxi)+diQ_i(x) = a_i(x - x_i)^3 + b_i(x - x_i)^2 + c_i(x - x_i) + d_i

Cette forme est choisie pour simplifier les calculs aux points de raccord.

Nombre d'inconnues

Chaque polynôme a 4 coefficients : ai,bi,ci,dia_i, b_i, c_i, d_i.

Pour n1n-1 polynômes, on a donc 4(n1)4(n-1) inconnues à déterminer.


Les conditions de raccord

Continuité de la fonction (Condition 1)

La spline doit passer par tous les points de données :

Qi(xi)=yietQi(xi+1)=yi+1Q_i(x_i) = y_i \quad \text{et} \quad Q_i(x_{i+1}) = y_{i+1}

pour i=1,2,,n1i = 1, 2, \ldots, n-1.

Cela donne 2(n1)2(n-1) équations.

Continuité de la dérivée première (Condition 2)

Aux points intérieurs, les dérivées à gauche et à droite doivent coïncider :

Qi(xi+1)=Qi+1(xi+1)Q'_i(x_{i+1}) = Q'_{i+1}(x_{i+1})

pour i=1,2,,n2i = 1, 2, \ldots, n-2.

Cela donne n2n-2 équations.

Continuité de la dérivée seconde (Condition 3)

De même pour les dérivées secondes :

Qi(xi+1)=Qi+1(xi+1)Q''_i(x_{i+1}) = Q''_{i+1}(x_{i+1})

pour i=1,2,,n2i = 1, 2, \ldots, n-2.

Cela donne encore n2n-2 équations.

Bilan des équations

ConditionNombre d'équations
Passage par les points2(n1)2(n-1)
Continuité de ff'n2n-2
Continuité de ff''n2n-2
Total4n64n - 6

On a 4(n1)=4n44(n-1) = 4n - 4 inconnues et 4n64n - 6 équations.

Il manque 2 équations pour déterminer uniquement la spline. Ces équations supplémentaires sont les conditions aux frontières, que nous étudierons dans la prochaine leçon.


Notation et dérivation

Introduction des dérivées secondes

Posons Si=Qi(xi)S_i = Q''_i(x_i), la dérivée seconde au point xix_i.

Puisque Qi(x)Q_i(x) est cubique, Qi(x)Q''_i(x) est linéaire :

Qi(x)=Si+Si+1Sihi(xxi)Q''_i(x) = S_i + \frac{S_{i+1} - S_i}{h_i}(x - x_i)

hi=xi+1xih_i = x_{i+1} - x_i est le pas sur l'intervalle [xi,xi+1][x_i, x_{i+1}].

Relation avec les coefficients

En comparant avec Qi(x)=ai(xxi)3+bi(xxi)2+ci(xxi)+diQ_i(x) = a_i(x-x_i)^3 + b_i(x-x_i)^2 + c_i(x-x_i) + d_i :

Qi(x)=6ai(xxi)+2biQ''_i(x) = 6a_i(x - x_i) + 2b_i

En x=xix = x_i : Qi(xi)=2bi=SiQ''_i(x_i) = 2b_i = S_i, donc :

bi=Si2b_i = \frac{S_i}{2}

En x=xi+1x = x_{i+1} : Qi(xi+1)=6aihi+2bi=Si+1Q''_i(x_{i+1}) = 6a_i h_i + 2b_i = S_{i+1}, donc :

ai=Si+1Si6hia_i = \frac{S_{i+1} - S_i}{6h_i}

Calcul des autres coefficients

Coefficient did_i

La condition Qi(xi)=yiQ_i(x_i) = y_i donne immédiatement :

di=yid_i = y_i

Coefficient cic_i

La condition Qi(xi+1)=yi+1Q_i(x_{i+1}) = y_{i+1} permet de trouver cic_i.

En développant :

Qi(xi+1)=aihi3+bihi2+cihi+di=yi+1Q_i(x_{i+1}) = a_i h_i^3 + b_i h_i^2 + c_i h_i + d_i = y_{i+1}

On isole cic_i :

ci=yi+1yihihi6(Si+1+2Si)c_i = \frac{y_{i+1} - y_i}{h_i} - \frac{h_i}{6}(S_{i+1} + 2S_i)

Résumé des coefficients

ai=Si+1Si6hi\boxed{a_i = \frac{S_{i+1} - S_i}{6h_i}}
bi=Si2\boxed{b_i = \frac{S_i}{2}}
ci=yi+1yihihi6(Si+1+2Si)\boxed{c_i = \frac{y_{i+1} - y_i}{h_i} - \frac{h_i}{6}(S_{i+1} + 2S_i)}
di=yi\boxed{d_i = y_i}

Le système pour les SiS_i

Condition de continuité de ff'

On veut que la pente soit continue à chaque nœud intérieur : le polynôme QiQ_i qui arrive au nœud xi+1x_{i+1} doit avoir la même pente que le polynôme Qi+1Q_{i+1} qui en repart. Formellement :

Qi(xi+1)=Qi+1(xi+1)Q'_i(x_{i+1}) = Q'_{i+1}(x_{i+1})

Calculons chaque côté séparément.

Pente à gauche — On dérive Qi(x)=ai(xxi)3+bi(xxi)2+ci(xxi)+diQ_i(x) = a_i(x-x_i)^3 + b_i(x-x_i)^2 + c_i(x-x_i) + d_i :

Qi(x)=3ai(xxi)2+2bi(xxi)+ciQ'_i(x) = 3a_i(x-x_i)^2 + 2b_i(x-x_i) + c_i

On évalue à x=xi+1x = x_{i+1}, c'est-à-dire avec (xxi)=hi(x-x_i) = h_i :

Qi(xi+1)=3aihi2+2bihi+ciQ'_i(x_{i+1}) = 3a_i h_i^2 + 2b_i h_i + c_i

Pente à droite — Le polynôme Qi+1Q_{i+1} est évalué à son point de départ xi+1x_{i+1}, donc (xxi+1)=0(x - x_{i+1}) = 0 :

Qi+1(xi+1)=ci+1Q'_{i+1}(x_{i+1}) = c_{i+1}

Substitution des coefficients

On remplace maintenant aia_i, bib_i, cic_i et ci+1c_{i+1} par leurs expressions en fonction des SiS_i (trouvées plus haut) :

ai=Si+1Si6hi,bi=Si2,ci=yi+1yihihi6(Si+1+2Si)a_i = \frac{S_{i+1} - S_i}{6h_i}, \quad b_i = \frac{S_i}{2}, \quad c_i = \frac{y_{i+1} - y_i}{h_i} - \frac{h_i}{6}(S_{i+1} + 2S_i)

La condition Qi(xi+1)=ci+1Q'_i(x_{i+1}) = c_{i+1} devient :

3Si+1Si6hihi2+2Si2hi+yi+1yihihi6(Si+1+2Si)=yi+2yi+1hi+1hi+16(Si+2+2Si+1)3 \cdot \frac{S_{i+1} - S_i}{6h_i} \cdot h_i^2 + 2 \cdot \frac{S_i}{2} \cdot h_i + \frac{y_{i+1} - y_i}{h_i} - \frac{h_i}{6}(S_{i+1} + 2S_i) = \frac{y_{i+2} - y_{i+1}}{h_{i+1}} - \frac{h_{i+1}}{6}(S_{i+2} + 2S_{i+1})

Simplification étape par étape

Étape 1 — Simplifions le premier terme :

3Si+1Si6hihi2=hi2(Si+1Si)3 \cdot \frac{S_{i+1} - S_i}{6h_i} \cdot h_i^2 = \frac{h_i}{2}(S_{i+1} - S_i)

Étape 2 — Le deuxième terme : 2Si2hi=hiSi2 \cdot \frac{S_i}{2} \cdot h_i = h_i S_i

Étape 3 — Regroupons les termes en SiS_i, Si+1S_{i+1} et Si+2S_{i+2} du côté gauche :

hi2Si+1hi2Si+hiSihi6Si+1hi3Si+hi+16Si+2+hi+13Si+1\frac{h_i}{2}S_{i+1} - \frac{h_i}{2}S_i + h_i S_i - \frac{h_i}{6}S_{i+1} - \frac{h_i}{3}S_i + \frac{h_{i+1}}{6}S_{i+2} + \frac{h_{i+1}}{3}S_{i+1}

Étape 4 — En regroupant par variable :

  • Termes en SiS_i : hi2+hihi3=hi6-\frac{h_i}{2} + h_i - \frac{h_i}{3} = \frac{h_i}{6}
  • Termes en Si+1S_{i+1} : hi2hi6+hi+13=hi3+hi+13=2(hi+hi+1)6\frac{h_i}{2} - \frac{h_i}{6} + \frac{h_{i+1}}{3} = \frac{h_i}{3} + \frac{h_{i+1}}{3} = \frac{2(h_i + h_{i+1})}{6}
  • Termes en Si+2S_{i+2} : hi+16\frac{h_{i+1}}{6}

Équation de raccord finale

En multipliant tout par 6, on obtient l'équation fondamentale :

hiSi+2(hi+hi+1)Si+1+hi+1Si+2=6(yi+2yi+1hi+1yi+1yihi)\boxed{h_i S_i + 2(h_i + h_{i+1})S_{i+1} + h_{i+1} S_{i+2} = 6\left(\frac{y_{i+2} - y_{i+1}}{h_{i+1}} - \frac{y_{i+1} - y_i}{h_i}\right)}

pour i=1,2,,n2i = 1, 2, \ldots, n-2.

Le terme de droite représente 6 fois la différence des pentes entre les segments adjacents. Si les données étaient sur une droite, ce terme serait nul et on aurait Si=0S_i = 0 partout — courbure nulle, pas de flexion.


Structure du système

De l'équation au système

L'équation de raccord fait intervenir trois SS consécutifs :

hiSi+2(hi+hi+1)Si+1+hi+1Si+2=ri+1h_i S_i + 2(h_i + h_{i+1})S_{i+1} + h_{i+1} S_{i+2} = r_{i+1}

où on note le second membre :

ri+1=6(yi+2yi+1hi+1yi+1yihi)r_{i+1} = 6\left(\frac{y_{i+2} - y_{i+1}}{h_{i+1}} - \frac{y_{i+1} - y_i}{h_i}\right)

Les ri+1r_{i+1} se calculent directement à partir des données (xi,yi)(x_i, y_i) — ce sont des constantes connues.

En écrivant cette équation pour i=1,2,,n2i = 1, 2, \ldots, n-2, on obtient n2n-2 équations. Mais les inconnues sont S1,S2,,SnS_1, S_2, \ldots, S_n (soit nn inconnues). Les valeurs S1S_1 et SnS_n aux extrémités seront fixées par les conditions frontières (leçon suivante). Pour l'instant, on les traite comme des paramètres connus et on résout pour les SS intérieurs S2,S3,,Sn1S_2, S_3, \ldots, S_{n-1}.

Écriture détaillée des équations

Écrivons explicitement les premières et dernières équations pour comprendre la structure.

Première équation (i=1i = 1) :

h1S1connu (bord)+2(h1+h2)S2+h2S3=r2h_1 \underbrace{S_1}_{\text{connu (bord)}} + 2(h_1 + h_2)S_2 + h_2 S_3 = r_2

On déplace le terme en S1S_1 vers le second membre :

2(h1+h2)S2+h2S3=r2h1S12(h_1 + h_2)S_2 + h_2 S_3 = r_2 - h_1 S_1

Deuxième équation (i=2i = 2) — ici S2S_2, S3S_3, S4S_4 sont tous des inconnues intérieures :

h2S2+2(h2+h3)S3+h3S4=r3h_2 S_2 + 2(h_2 + h_3)S_3 + h_3 S_4 = r_3

Pas de terme à déplacer : le second membre reste r3r_3 tel quel.

Dernière équation (i=n2i = n-2) :

hn2Sn2+2(hn2+hn1)Sn1+hn1Snconnu (bord)=rn1h_{n-2} S_{n-2} + 2(h_{n-2} + h_{n-1})S_{n-1} + h_{n-1} \underbrace{S_n}_{\text{connu (bord)}} = r_{n-1}

On déplace SnS_n :

hn2Sn2+2(hn2+hn1)Sn1=rn1hn1Snh_{n-2} S_{n-2} + 2(h_{n-2} + h_{n-1})S_{n-1} = r_{n-1} - h_{n-1} S_n

Système tridiagonal

Seules la première et la dernière ligne ont un second membre modifié (par les conditions aux bords). Les lignes intermédiaires gardent simplement rir_i. Le système complet s'écrit :

(2(h1+h2)h200h22(h2+h3)h300h32(h3+h4)hn200hn22(hn2+hn1))(S2S3S4Sn1)=(r2h1S1r3r4rn1hn1Sn)\begin{pmatrix} 2(h_1{+}h_2) & h_2 & 0 & \cdots & 0 \\ h_2 & 2(h_2{+}h_3) & h_3 & \cdots & 0 \\ 0 & h_3 & 2(h_3{+}h_4) & \ddots & \vdots \\ \vdots & \ddots & \ddots & \ddots & h_{n-2} \\ 0 & \cdots & 0 & h_{n-2} & 2(h_{n-2}{+}h_{n-1}) \end{pmatrix} \begin{pmatrix} S_2 \\ S_3 \\ S_4 \\ \vdots \\ S_{n-1} \end{pmatrix} = \begin{pmatrix} r_2 - h_1 S_1 \\ r_3 \\ r_4 \\ \vdots \\ r_{n-1} - h_{n-1} S_n \end{pmatrix}

Chaque équation ne fait intervenir que 3 inconnues consécutives (Si,Si+1,Si+2S_{i}, S_{i+1}, S_{i+2}). La matrice n'a de valeurs non nulles que sur la diagonale principale et les deux diagonales adjacentes — d'où le nom tridiagonal. Cette structure permettra une résolution très efficace en O(n)O(n) (algorithme de Thomas, leçon suivante).

Cas du pas constant

Si hi=hh_i = h pour tout ii, les coefficients se simplifient. La diagonale principale vaut 2(h+h)=4h2(h + h) = 4h et les sous/sur-diagonales valent hh. En divisant chaque ligne par hh :

Si+4Si+1+Si+2=6h2(yi2yi+1+yi+2)S_i + 4S_{i+1} + S_{i+2} = \frac{6}{h^2}(y_i - 2y_{i+1} + y_{i+2})

La matrice devient :

(4100141001410014)\begin{pmatrix} 4 & 1 & 0 & \cdots & 0 \\ 1 & 4 & 1 & \cdots & 0 \\ 0 & 1 & 4 & \ddots & \vdots \\ \vdots & \ddots & \ddots & \ddots & 1 \\ 0 & \cdots & 0 & 1 & 4 \end{pmatrix}

Cette matrice est symétrique définie positive (la diagonale domine strictement : 4>1+14 > 1 + 1). Cela garantit l'existence et l'unicité de la solution, ainsi que la stabilité numérique de l'algorithme de résolution.


Interprétation physique

La spline comme ruban flexible

Physiquement, la spline cubique minimise l'énergie de flexion :

E=ab[f(x)]2dxE = \int_a^b [f''(x)]^2 \, dx

Cette propriété explique pourquoi :

  1. La dérivée seconde représente la courbure
  2. La continuité de ff'' assure une flexion sans à-coup
  3. Les conditions aux bords influencent le comportement global

Avantages des splines cubiques

AvantageExplication
Pas d'oscillationPolynômes de degré 3 seulement
Courbe lisseContinuité de f, f' et f''
Contrôle localModifier un point n'affecte que les segments voisins
Calcul efficaceSystème tridiagonal en O(n)

Algorithme de construction

spline_construction.pypython
import numpy as np

def calculer_coefficients_spline(x, y, S):
  """
  Calcule les coefficients a, b, c, d de chaque polynôme cubique
  à partir des dérivées secondes S aux noeuds.

  Paramètres:
      x : abscisses des noeuds (n points)
      y : ordonnées des noeuds
      S : dérivées secondes aux noeuds

  Retourne:
      a, b, c, d : tableaux des coefficients (n-1 valeurs chacun)
  """
  n = len(x)
  h = np.diff(x)  # h[i] = x[i+1] - x[i]

  a = np.zeros(n - 1)
  b = np.zeros(n - 1)
  c = np.zeros(n - 1)
  d = np.zeros(n - 1)

  for i in range(n - 1):
      a[i] = (S[i + 1] - S[i]) / (6 * h[i])
      b[i] = S[i] / 2
      c[i] = (y[i + 1] - y[i]) / h[i] - h[i] * (S[i + 1] + 2 * S[i]) / 6
      d[i] = y[i]

  return a, b, c, d

def evaluer_spline(x_data, a, b, c, d, x):
  """
  Évalue la spline au point x.

  Paramètres:
      x_data : abscisses des noeuds
      a, b, c, d : coefficients des polynômes
      x : point d'évaluation

  Retourne:
      valeur de la spline en x
  """
  # Trouver l'intervalle contenant x
  n = len(x_data)
  for i in range(n - 1):
      if x_data[i] <= x <= x_data[i + 1]:
          dx = x - x_data[i]
          return a[i] * dx**3 + b[i] * dx**2 + c[i] * dx + d[i]

  # Extrapolation (à éviter en général)
  if x < x_data[0]:
      dx = x - x_data[0]
      return a[0] * dx**3 + b[0] * dx**2 + c[0] * dx + d[0]
  else:
      dx = x - x_data[-2]
      return a[-1] * dx**3 + b[-1] * dx**2 + c[-1] * dx + d[-1]

# Exemple d'utilisation (les S seront calculés dans la prochaine leçon)
x = np.array([1, 2, 3, 4])
y = np.array([4, -2, 3, 1])

# Pour l'instant, supposons S connu (spline naturelle, exemple)
S = np.array([0, 20.4, -15.6, 0])

a, b, c, d = calculer_coefficients_spline(x, y, S)

print("Coefficients des polynômes cubiques :")
for i in range(len(a)):
  print(f"  Q_{i+1}(x) : a={a[i]:.2f}, b={b[i]:.2f}, c={c[i]:.2f}, d={d[i]:.2f}")

Résumé

Dans cette leçon, nous avons établi les fondements des splines cubiques :

  • Une spline cubique est constituée de n1n-1 polynômes cubiques raccordés
  • Chaque polynôme a la forme Qi(x)=ai(xxi)3+bi(xxi)2+ci(xxi)+diQ_i(x) = a_i(x-x_i)^3 + b_i(x-x_i)^2 + c_i(x-x_i) + d_i
  • Les conditions de continuité de ff, ff' et ff'' fournissent 4n64n-6 équations
  • Les coefficients s'expriment en fonction des dérivées secondes SiS_i aux nœuds
  • Le système pour les SiS_i est tridiagonal et se résout en O(n)O(n)

Pour aller plus loin

La prochaine leçon présentera les différentes conditions aux frontières qui complètent le système : splines naturelles, paraboliques, et à pentes imposées. Nous verrons également l'algorithme complet de résolution.