2011-12-28 5 views
16

में बिलीनेर इंटरपोलेशन कैसे करें I Python का उपयोग करके blinear इंटरपोलेशन करना चाहते हैं।
उदाहरण जीपीएस बात है जिसके लिए मैं ऊंचाई को जोड़ करना चाहते है:
पायथन

B = 54.4786674627 
L = 17.0470721369 

चार आसन्न अंक का उपयोग कर ज्ञात निर्देशांक और ऊंचाई के मान के साथ:

n = [(54.5, 17.041667, 31.993), (54.5, 17.083333, 31.911), (54.458333, 17.041667, 31.945), (54.458333, 17.083333, 31.866)] 


z01 z11 

    z 
z00 z10 


और यहां मेरा आदिम प्रयास है:

import math 
z00 = n[0][2] 
z01 = n[1][2] 
z10 = n[2][2] 
z11 = n[3][2] 
c = 0.016667 #grid spacing 
x0 = 56 #latitude of origin of grid 
y0 = 13 #longitude of origin of grid 
i = math.floor((L-y0)/c) 
j = math.floor((B-x0)/c) 
t = (B - x0)/c - j 
z0 = (1-t)*z00 + t*z10 
z1 = (1-t)*z01 + t*z11 
s = (L-y0)/c - i 
z = (1-s)*z0 + s*z1 


जहां z0 और z1

z01 z0 z11 

    z 
z00 z1 z10 


मैं 31.964 मिलता है लेकिन अन्य सॉफ्टवेयर से मैं 31.961 मिलता है।
क्या मेरी स्क्रिप्ट सही है?
क्या आप एक और दृष्टिकोण प्रदान कर सकते हैं?

+2

आपको गोल करने वाली त्रुटियां मिल गई हैं और आप गोल कर रहे हैं ??? यदि आप 'मंजिल' को हटाते हैं तो क्या होता है? – Ben

+2

एल और बी क्या हैं? उस बिंदु के निर्देशांक जिस पर आप इंटरपोल करना चाहते हैं? –

+0

@ माचिन सालाना सही है – daikini

उत्तर

31

यहाँ एक पुन: प्रयोज्य समारोह का उपयोग कर सकते है।

def bilinear_interpolation(x, y, points): 
    '''Interpolate (x,y) from values associated with four points. 

    The four points are a list of four triplets: (x, y, value). 
    The four points can be in any order. They should form a rectangle. 

     >>> bilinear_interpolation(12, 5.5, 
     ...      [(10, 4, 100), 
     ...       (20, 4, 200), 
     ...       (10, 6, 150), 
     ...       (20, 6, 300)]) 
     165.0 

    ''' 
    # See formula at: http://en.wikipedia.org/wiki/Bilinear_interpolation 

    points = sorted(points)    # order points by x, then by y 
    (x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = points 

    if x1 != _x1 or x2 != _x2 or y1 != _y1 or y2 != _y2: 
     raise ValueError('points do not form a rectangle') 
    if not x1 <= x <= x2 or not y1 <= y <= y2: 
     raise ValueError('(x, y) not within the rectangle') 

    return (q11 * (x2 - x) * (y2 - y) + 
      q21 * (x - x1) * (y2 - y) + 
      q12 * (x2 - x) * (y - y1) + 
      q22 * (x - x1) * (y - y1) 
      )/((x2 - x1) * (y2 - y1) + 0.0) 

आप जोड़कर परीक्षण कोड चला सकते हैं::

if __name__ == '__main__': 
    import doctest 
    doctest.testmod() 

आपके डेटासेट पर प्रक्षेप चल रहा है पैदा करता है:

>>> n = [(54.5, 17.041667, 31.993), 
     (54.5, 17.083333, 31.911), 
     (54.458333, 17.041667, 31.945), 
     (54.458333, 17.083333, 31.866), 
    ] 
>>> bilinear_interpolation(54.4786674627, 17.0470721369, n) 
31.95798688313631 
+2

ग्रेट समाधान, धन्यवाद। सॉफ़्टवेयर इंजीनियरिंग के लिए – daikini

+4

+1। –

+0

@ रेमंड हेटिंगर इस उत्तर के लिए आपका बहुत बहुत धन्यवाद। इस मामले में 'scipy.interpolate.interp2d' क्यों काम नहीं करेगा? 'इंटरप 2 डी' भी एक द्विपक्षीय इंटरपोलेशन नहीं है क्योंकि यह "2-डी ग्रिड पर इंटरपोलेट करता है" (स्रोत: docs.scipy.org/doc/scipy-0.14.0/reference/generated/...)? –

2

मुझे लगता है कि floor फ़ंक्शन करने का बिंदु यह है कि आम तौर पर आप उस मान को अलग करने की सोच रहे हैं जिसका समन्वय दो अलग निर्देशांक के बीच होता है। हालांकि आपके पास पहले से निकटतम बिंदुओं के वास्तविक वास्तविक समन्वय मूल्य हैं, जो इसे सरल गणित बनाता है।

z00 = n[0][2] 
z01 = n[1][2] 
z10 = n[2][2] 
z11 = n[3][2] 

# Let's assume L is your x-coordinate and B is the Y-coordinate 

dx = n[2][0] - n[0][0] # The x-gap between your sample points 
dy = n[1][1] - n[0][1] # The Y-gap between your sample points 

dx1 = (L - n[0][0])/dx # How close is your point to the left? 
dx2 = 1 - dx1    # How close is your point to the right? 
dy1 = (B - n[0][1])/dy # How close is your point to the bottom? 
dy2 = 1 - dy1    # How close is your point to the top? 

left = (z00 * dy1) + (z01 * dy2) # First interpolate along the y-axis 
right = (z10 * dy1) + (z11 * dy2) 

z = (left * dx1) + (right * dx2) # Then along the x-axis 

वहाँ अपने उदाहरण से अनुवाद करने में गलत तर्क का एक सा हो सकता है, लेकिन यह का सार आप कितना करीब वह अपने अन्य पड़ोसियों से प्रक्षेप लक्ष्य बात करने के लिए है के आधार पर प्रत्येक बिंदु वजन कर सकते हैं।

+0

क्या आप 'बाएं', 'दाएं' और 'z' को' dy1 + dy2', 'dy1 + dy2' और' dx1 + dx2' से सम्मानित करना भूल नहीं रहे हैं? – ovgolovin

+0

मुझे यकीन नहीं है कि आप ऐसा क्यों करेंगे। 'dx1',' dx2', 'dy1', और' dy2' सभी 0 और 1 के बीच पूरक मानों के लिए सामान्यीकृत होते हैं (इसलिए 'dy1 + dy2' हमेशा 1 के बराबर होता है) क्योंकि डीएक्स बाएं पड़ोसी के बीच कुल दूरी है और सही पड़ोसी, और इसी तरह के लिए। –

+0

ओह, क्षमा करें। वे पहले से ही सामान्यीकृत हैं। – ovgolovin

4

सुनिश्चित नहीं हैं कि यह बहुत मदद करता है, तो है, लेकिन जब रैखिक प्रक्षेप कर scipy का उपयोग कर मैं एक अलग मूल्य प्राप्त:

>>> import numpy as np 
>>> from scipy.interpolate import griddata 
>>> n = np.array([(54.5, 17.041667, 31.993), 
        (54.5, 17.083333, 31.911), 
        (54.458333, 17.041667, 31.945), 
        (54.458333, 17.083333, 31.866)]) 
>>> griddata(n[:,0:2], n[:,2], [(54.4786674627, 17.0470721369)], method='linear') 
array([ 31.95817681]) 
+0

आपके उत्तर के लिए धन्यवाद। – daikini

+0

'griddata' एक आयताकार में bilinearly के बजाय एक सरल (त्रिकोण) में रैखिक रूप से interpolates; इसका मतलब है कि यह पहले त्रिकोण (Delaunay?) कर रहा है। – sastanin

3

here से प्रेरित, मैं निम्नलिखित स्निपेट के साथ आया था।

from bisect import bisect_left 

class BilinearInterpolation(object): 
    """ Bilinear interpolation. """ 
    def __init__(self, x_index, y_index, values): 
     self.x_index = x_index 
     self.y_index = y_index 
     self.values = values 

    def __call__(self, x, y): 
     # local lookups 
     x_index, y_index, values = self.x_index, self.y_index, self.values 

     i = bisect_left(x_index, x) - 1 
     j = bisect_left(y_index, y) - 1 

     x1, x2 = x_index[i:i + 2] 
     y1, y2 = y_index[j:j + 2] 
     z11, z12 = values[j][i:i + 2] 
     z21, z22 = values[j + 1][i:i + 2] 

     return (z11 * (x2 - x) * (y2 - y) + 
       z21 * (x - x1) * (y2 - y) + 
       z12 * (x2 - x) * (y - y1) + 
       z22 * (x - x1) * (y - y1))/((x2 - x1) * (y2 - y1)) 

आप इस तरह इसका इस्तेमाल कर सकते हैं::

table = BilinearInterpolation(
    x_index=(54.458333, 54.5), 
    y_index=(17.041667, 17.083333), 
    values=((31.945, 31.866), (31.993, 31.911)) 
) 

print(table(54.4786674627, 17.0470721369)) 
# 31.957986883136307 

यह वर्शन त्रुटि जाँच की है और अगर तुम कोशिश आप मुसीबत में पड़ जाएगा एपीआई समय की एक बहुत ही तालिका पुन: उपयोग के लिए अनुकूलित है सूचकांक (या उससे परे) की सीमाओं पर इसका उपयोग करने के लिए। कोड के पूर्ण संस्करण के लिए, त्रुटि जांच और वैकल्पिक extrapolation सहित, here देखें।