2014-01-04 3 views
2

Этот вопрос является полупрограммированием, но также и половиной математики. Я хочу, чтобы интерполировать множество точек кривой без добавления ненужных экстремумов, остающихся «близкими к линейной интерполяции», сохраняя при этом кривую, которая выглядит гладко. Я знаю, что эта формулировка расплывчата, но я надеюсь, что она станет более ясной с примера. Давайте посмотрим на следующий фрагмент кода и результат:Метод интерполяции, который не добавляет лишних экстремумов

#! /usr/bin/python 

import numpy as np 
from scipy.interpolate import interp1d 
import matplotlib.pyplot as plt 

fig = plt.figure() 
ax = fig.add_subplot(1,1,1) 
ax.spines['left'].set_position('zero') 
ax.spines['right'].set_color('none') 
ax.spines['bottom'].set_position('zero') 
ax.spines['top'].set_color('none') 
ax.xaxis.set_ticks_position('bottom') 
ax.yaxis.set_ticks_position('left') 

list_points=[(-3,0.1),(-2,0.15),(0,4),(2,-6),(4,-2),(7,-0.15),(8,-0.1)] 
(xp,yp)=zip(*list_points) 
fun=interp1d(xp,yp,kind='cubic') 

xc=np.linspace(min(xp),max(xp),300) 

plt.plot(xp,yp,'o',color='black',ms=5) 
plt.plot(xc,fun(xc)) 
fun2=interp1d(xp,yp,kind='linear') 
plt.plot(xc,fun2(xc)) 

plt.show() 

Interpolation

Я бы ожидать интерполянт, что есть только два экстремума (около х ~ 0 и х ~ 2) в то время как здесь мы имеем 5 экстремумы. Это то, что большинство людей будет рисовать, если мы попросим их присоединиться к точкам с гладкой кривой вручную. Есть ли способ достичь этой цели (на питоне).

Обновление: обратите внимание, что xfig имеет что-то близкое (называемое «приблизительным сплайн-чертежом») с неудобствами, которые кривая не проходит точно по указанным точкам. Я бы предпочел кривую, которая проходит точно через указанные точки, но я бы приветствовал метод xfig, если никто не знает лучшего решения.

+0

Хммм из любопытства , Это не слесарь, почему функция должна быть гладкой? При интерполяции вы всегда получите конечный набор точек.Поэтому вы никогда не сможете точно сказать, было ли оригинальное изображение гладким или нет. – luk32

ответ

4

Хотя не совсем то же самое, ваш вопрос похож на this one, поэтому, возможно, тот же ответ будет полезным (?). Вы можете попробовать монотонный интерполятор. Класс PchipInterpolator (к которому вы можете обратиться по его более короткому псевдониму pchip) в scipy.interpolate. Вот версия вашего сценария с кривым, созданными с использованием pchip включено:

import numpy as np 
from scipy.interpolate import interp1d, pchip 
import matplotlib.pyplot as plt 

fig = plt.figure() 
ax = fig.add_subplot(1,1,1) 
ax.spines['left'].set_position('zero') 
ax.spines['right'].set_color('none') 
ax.spines['bottom'].set_position('zero') 
ax.spines['top'].set_color('none') 
ax.xaxis.set_ticks_position('bottom') 
ax.yaxis.set_ticks_position('left') 

list_points = [(-3,0.1),(-2,0.15),(0,4),(2,-6),(4,-2),(7,-0.15),(8,-0.1)] 
(xp,yp) = zip(*list_points) 
fun = interp1d(xp,yp,kind='cubic') 

xc = np.linspace(min(xp),max(xp),300) 

plt.plot(xp,yp,'o',color='black',ms=5) 
plt.plot(xc,fun(xc)) 
fun2 = interp1d(xp,yp,kind='linear') 
plt.plot(xc,fun2(xc)) 

p = pchip(xp, yp) 
plt.plot(xc, p(xc), 'r', linewidth=3, alpha=0.6) 

plt.show() 

Участка он генерирует показано ниже.

  • Черные точки: Исходные данные
  • Зеленые линии: линейная интерполяция
  • Синие линии: кубический сплайн интерполяция
  • Красные линии: pchip интерполяция

plot

0

Вы попробовали квадратичную сплайн вместо этого - хотя я не уверен, что это поможет. Еще одна опция fudge - добавить дополнительные точки данных, очень близкие к вашим максимумам. , например. при (-0,05,4) и (1,95, -6) - это приведет к тому, что алгоритм кубического сплайна сгладит эти области вблизи максимума. Зависит от того, чего вы пытаетесь достичь. Существуют методы ограничения максимального и минимального кубических сплайнов, но я недостаточно хорошо знаком с ними или python/matplotlib, чтобы помочь, извините!

+0

Это любопытное эвристическое слепое хождение =) (или случайная прогулка, если вы предпочитаете). Я не думаю, что какой-либо поли-номинальный подход будет работать. – luk32

+0

Нет, квадратичные сплайны еще хуже. @ luk32 Я не убежден ни в том, что полиномиальная интерполяция поможет. На самом деле я понятия не имею, какую математику он должен будет использовать. Интересно, кто-то закодировал такую ​​вещь (с любым методом) (обратите внимание, что у xfig есть что-то близкое: см. Обновленный вопрос). – olivier

0

Вы можете использовать линейную интерполяцию, а затем процеживают (со средним фильтром):

size = 51.0;  
fun = interpolate.interp1d(xp, yp,kind='linear'); 
filt = (1/size)*np.ones(size); 
yc = signal.convolve(fun(xc),filt,'same'); 

С помощью параметра size вы можете контролировать степень сглаживания.

enter image description here

Это интегрированный код:

import numpy as np 
from scipy.interpolate import interp1d 
import matplotlib.pyplot as plt 
from scipy import interpolate,signal 

fig = plt.figure() 
ax = fig.add_subplot(1,1,1) 
ax.spines['left'].set_position('zero') 
ax.spines['right'].set_color('none') 
ax.spines['bottom'].set_position('zero') 
ax.spines['top'].set_color('none') 
ax.xaxis.set_ticks_position('bottom') 
ax.yaxis.set_ticks_position('left') 

list_points=[(-3,0.1),(-2,0.15),(0,4),(2,-6),(4,-2),(7,-0.15),(8,-0.1)] 
(xp,yp)=zip(*list_points) 
xc=np.linspace(min(xp),max(xp),300) 

######################################################## 
size = 41.0;#Put here any odd number 
fun = interpolate.interp1d(xp, yp,kind='linear'); 
filt = (1/size)*np.ones(size); 
yc = signal.convolve(fun(xc),filt,'same'); 
######################################################## 

plt.plot(xp,yp,'o',color='black',ms=5) 
plt.plot(xc,yc) 
plt.plot(xc,fun(xc)) 
plt.show() 
+0

Кривая не проходит точно через указанные точки, но, тем не менее, дает хороший результат. – olivier

Смежные вопросы