Среда программирования:
Brackets build 1.14.2-17770
Статья по теме:
Программа демонстрирующая интерполяцию сплайнами.
Для задания функции f(x) используется первое поле ввода. Можно использовать все основные математические функции. Поскольку программа написана на Python, для возведения в степень используется два оператора звёздочка **.
Далее необходимо задать значения производной функции на концах отрезка, производная - влияет на кривизну кривой.
В поле [Ax;Bx] задаются интервалы интерполирования.
Можно выбрать положительное число отрезков разбиения функции на равномерной сетке. Если нажать на чекбокс "Случайное разбиение" - сетка будет случайной.
Код программы:
from tkinter import * from tkinter import messagebox from PIL import ImageTk, Image import numpy as np import matplotlib.pyplot as plt import random from math import * class Application(Frame): def __init__(self,master=None): super().__init__(master) self.grid() self.create_widgets() self.master.title("Интерполяция сплайном") self.master.geometry(f"1100x480+50+50") self.master.resizable(False, False) def create_widgets(self): left_frame = Frame(root, width=640, height=480, pady=5).grid(row=0,column=0,sticky="wens") right_frame = Frame(root,width=460, height=480, padx=5, pady=5) right_frame.grid(row=0,column=1,sticky="wens") # холст для вывода графика функции и ее апроксимации self.canvas = Canvas(left_frame,width=640,height=480) self.canvas.grid(row=0, column=0,sticky="wens", pady=5, padx=5) # ввод функции для интерполяции Label(right_frame,text="f(x)=:",font=('Arial',10)).grid( row=0, column=0,sticky="w", pady=5, padx=5) self.enteredFunction = StringVar() Entry(right_frame,textvariable = self.enteredFunction,width=15,font=('Arial',10)).grid( row=0,column=1,sticky="w",padx=5,pady=5) # ввод производной в начальной точке Label(right_frame,text="f'(A)=:",font=('Arial',10)).grid( row=1, column=0,sticky="w", pady=5, padx=5) self.derivativeStart = DoubleVar() Entry(right_frame,textvariable = self.derivativeStart,width=15,font=('Arial',10)).grid( row=1,column=1,sticky="w",padx=5,pady=5) # ввод производной в конечной точке Label(right_frame,text="f'(B)=:",font=('Arial',10)).grid( row=2, column=0,sticky="w", pady=5, padx=5) self.derivativeEnd = DoubleVar() Entry(right_frame,textvariable = self.derivativeEnd,width=15,font=('Arial',10)).grid( row=2,column=1,sticky="w",padx=5,pady=5) # ввод интервалов интерполирования Label(right_frame,text="[Ax;Bx]:",font=('Arial',10)).grid( row=3, column=0,sticky="w", pady=5, padx=5) self.startPoint = DoubleVar() Entry(right_frame,textvariable = self.startPoint,width=15,font=('Arial',10)).grid( row=3,column=1,sticky="w",padx=5,pady=5) self.endPoint = DoubleVar() Entry(right_frame,textvariable = self.endPoint,width=15,font=('Arial',10)).grid( row=3,column=2,sticky="w",padx=5,pady=5) # ввод количества интервалов разбиения Label(right_frame,text="Ввести количество интервалов:",font=('Arial',10)).grid( row=4, column=0,sticky="w", pady=5, padx=5) self.NumberOfIntervals = IntVar() Entry(right_frame,textvariable = self.NumberOfIntervals,width=15,font=('Arial',10)).grid( row=4,column=1,sticky="w",padx=5,pady=5) # если переменная CheckVar = 0 равномерная сетка, случайные абсциссы иначе self.CheckVar= IntVar() R1 = Checkbutton(right_frame, text = "Случайное разбиение", variable = self.CheckVar, onvalue = 1, offvalue = 0).grid(row=5,column=0,sticky="we",padx=5,pady=5,columnspan=3) # кнопка для вывода графика Button(right_frame,text="Расчитать",font=('Arial',10),command=lambda: self.calc()).grid( row=6,column=0,columnspan=3, stick="we",padx=5,pady=5) def calc(self): # считываем количество разбиений n=self.NumberOfIntervals.get() if n == 0: messagebox.showwarning(title="Неверное значение", message="Введите количество интервалов больше 0") return xi=[] # равномерная сетка, если не выбранно обратное if self.CheckVar.get() == 0: for i in range(0,n+1): xi.append(self.startPoint.get()+i*((self.endPoint.get()-self.startPoint.get())/n)) else: for i in range(0,n+1): xi.append(random.uniform(self.startPoint.get(),self.endPoint.get())) # поскольку точки случайные, для корректного счета сортируем xi.sort() # находим значения y, для введенной функции yi=[] functionToInterrpolate=eval('lambda x: ' + self.enteredFunction.get()) for xd in xi: yi.append(functionToInterrpolate(xd)) h=[] hy=[] # находим дельты между абсциссами и ординатами for i in range(1,len(xi)): h.append(xi[i]-xi[i-1]) hy.append(yi[i]-yi[i-1]) # задаем значения производных в концах отрезка интерполирования prA=self.derivativeStart.get() prB=self.derivativeEnd.get() # находим коэффициенты для системы линейных уравнений N=len(xi)-1 a=[0]*N b=[0]*N c=[0]*N f=[0]*N k1=-0.5 k2=-0.5 m1=3*(hy[0]/(h[0]**2)-prA/h[0]) m2=3*h[len(h)-1]*(prB/h[len(h)-1]-hy[len(hy)-1]/(h[len(h)-1]**2)) for i in range(1,len(xi)-1): a[i]=h[i-1] c[i]=-2*(h[i-1]+h[i]) b[i]=h[i] f[i]=-6*(hy[i]/h[i]-hy[i-1]/h[i-1]) # находим решение трехдиагональной матрицы методом прогонки, вызывая функцию progonka res=self.progonka(N,a,b,c,f,k1,k2,m1,m2) # ищем кубическую функцию для каждого отрезка интерполирования и считаем значения через каждые 0.01 for i in range(1,len(xi)): grX=[] grY=[] sd=np.arange(xi[i-1],xi[i]+0.01,0.01) for st in sd: si=1/(6*h[i-1])*(res[i-1]*((xi[i]-st)**3)) si+=1/6/h[i-1]*(res[i]*((st-xi[i-1])**3)) si+=(st-xi[i-1])*yi[i]/h[i-1] si-=(st-xi[i-1])*h[i-1]*res[i]/6 si+=(xi[i]-st)*yi[i-1]/h[i-1] si-=(xi[i]-st)*h[i-1]*res[i-1]/6 grY.append(si) si=0 # выводим на график полученные значения функции и точки - между которыми интерполировали plt.plot(sd,grY) plt.plot(xi[i-1],yi[i-1],'o') plt.plot(xi[i],yi[i],'o') # задаем разбиение отрезка интерполирования с h=0.01 и считаем реальные значения функции xfunc=np.arange(self.startPoint.get(),self.endPoint.get()+0.01,0.01) yfunc=[] for xf in xfunc: yfunc.append(functionToInterrpolate(xf)) # выводим реальный график функции plt.plot(xfunc,yfunc, color="gray",alpha=0.5,label=self.enteredFunction.get()) plt.legend() plt.savefig("spline.png") # вызываем функцию загрузки картинки image = self.load_image("spline.png") # выводим на холст картинку self.set_image(image) # очищаем все что было на графике plt.clf() # метод загрузки изображения def load_image(self,name): img = Image.open(name) return ImageTk.PhotoImage(img) # метод установки изображения на холст def set_image(self,image): self.canvas.delete("all") self.canvas.image = image self.canvas.create_image(0,0,image= self.canvas.image,anchor='nw') # метод решающий трехдиагональную матрицу методом прогонки def progonka(self,N,a,b,c,f,k1,k2,m1,m2): p=[0]*(N+1) q=[0]*(N+1) s=[0]*(N+1) p[1]=k1 q[1]=m1 for j in range (1,N): denominator=c[j]-a[j]*p[j] p[j+1]=b[j]/denominator q[j+1]=(f[j]+a[j]*q[j])/denominator s[N]=(k2*q[N]+m2)/(1-k2*p[N]) for j in range (N-1,-1,-1): s[j]=p[j+1]*s[j+1]+q[j+1] return s root = Tk() app = Application(master=root) root.mainloop()
Прикрепленный файл | Размер |
---|---|
tsybrick_example_spline.rar | 2.67 кб |