2012-01-15 26 views
8

संक्षिप्त सारांश: मैं जल्दी से दो सरणी के सीमित संकल्प की गणना कैसे करूं?Riemann से Artefacts scipy.signal.convolve

समस्या का वर्णन

मैं के दो कार्य f (x), जी परिमित घुमाव के प्राप्त करने के लिए कोशिश कर रहा हूँ (एक्स)

finite convolution

द्वारा परिभाषित किया गया इस लक्ष्य को हासिल करने के लिए, मैं ले लिया है असतत नमूने कार्यों की और उन्हें लंबाई steps की सरणियों में बदल गया:

xarray = [x * i/steps for i in range(steps)] 
farray = [f(x) for x in xarray] 
garray = [g(x) for x in xarray] 

मैं तो रूपा की गणना करने की कोशिश की scipy.signal.convolve फ़ंक्शन का उपयोग करके olution। यह फ़ंक्शन एक ही परिणाम देता है जैसे एल्गोरिदम conv सुझाए गए here। हालांकि, परिणाम विश्लेषणात्मक समाधान से काफी अलग हैं। Trapezoidal नियम का उपयोग करने के लिए एल्गोरिदम conv संशोधित वांछित परिणाम देता है।

इसे दर्शाने के लिए, मैं

f(x) = exp(-x) 
g(x) = 2 * exp(-2 * x) 

जाने परिणाम हैं:

enter image description here

यहाँ Riemann एक सरल Riemann कुल योग होता है, trapezoidal Riemann एल्गोरिथ्म का उपयोग करने का एक संशोधित संस्करण है trapezoidal नियम, scipy.signal.convolve scipy समारोह है और analytical विश्लेषणात्मक दृढ़ संकल्प है।

अब g(x) = x^2 * exp(-x) जाने और परिणाम हो:

enter image description here

यहाँ 'अनुपात' scipy से विश्लेषणात्मक मूल्यों के लिए प्राप्त मूल्यों का अनुपात है। उपर्युक्त दर्शाता है कि अभिन्न अंगों को पुनर्निर्मित करके समस्या हल नहीं की जा सकती है।

सवाल

यह scipy की गति का उपयोग, लेकिन एक समलम्बाकार शासन के बेहतर परिणाम को कायम रखने में मैं एक सी विस्तार वांछित परिणाम प्राप्त करने के लिए लिखने के लिए क्या है करना संभव है?

एक उदाहरण

की प्रतिलिपि बना समस्या मैं का सामना कर रहा हूँ देखने के लिए नीचे कोड पेस्ट करें। steps परिवर्तनीय को बढ़ाकर दो परिणामों को निकट समझौते में लाया जा सकता है। मेरा मानना ​​है कि समस्या दाएं हाथ से कलाकृतियों के कारण है, रिमेंन रकम क्योंकि अभिन्न अंग बढ़ रहा है जब यह बढ़ रहा है और विश्लेषणात्मक समाधान के रूप में फिर से घट रहा है।

संपादित: मैं अब एक तुलना जो scipy.signal.convolve समारोह के रूप में एक ही परिणाम देता है के रूप में मूल एल्गोरिथ्म 2 शामिल किया है।

import numpy as np 
import scipy.signal as signal 
import matplotlib.pyplot as plt 
import math 

def convolveoriginal(x, y): 
    ''' 
    The original algorithm from http://www.physics.rutgers.edu/~masud/computing/WPark_recipes_in_python.html. 
    ''' 
    P, Q, N = len(x), len(y), len(x) + len(y) - 1 
    z = [] 
    for k in range(N): 
     t, lower, upper = 0, max(0, k - (Q - 1)), min(P - 1, k) 
     for i in range(lower, upper + 1): 
      t = t + x[i] * y[k - i] 
     z.append(t) 
    return np.array(z) #Modified to include conversion to numpy array 

def convolve(y1, y2, dx = None): 
    ''' 
    Compute the finite convolution of two signals of equal length. 
    @param y1: First signal. 
    @param y2: Second signal. 
    @param dx: [optional] Integration step width. 
    @note: Based on the algorithm at http://www.physics.rutgers.edu/~masud/computing/WPark_recipes_in_python.html. 
    ''' 
    P = len(y1) #Determine the length of the signal 
    z = [] #Create a list of convolution values 
    for k in range(P): 
     t = 0 
     lower = max(0, k - (P - 1)) 
     upper = min(P - 1, k) 
     for i in range(lower, upper): 
      t += (y1[i] * y2[k - i] + y1[i + 1] * y2[k - (i + 1)])/2 
     z.append(t) 
    z = np.array(z) #Convert to a numpy array 
    if dx != None: #Is a step width specified? 
     z *= dx 
    return z 

steps = 50 #Number of integration steps 
maxtime = 5 #Maximum time 
dt = float(maxtime)/steps #Obtain the width of a time step 
time = [dt * i for i in range (steps)] #Create an array of times 
exp1 = [math.exp(-t) for t in time] #Create an array of function values 
exp2 = [2 * math.exp(-2 * t) for t in time] 
#Calculate the analytical expression 
analytical = [2 * math.exp(-2 * t) * (-1 + math.exp(t)) for t in time] 
#Calculate the trapezoidal convolution 
trapezoidal = convolve(exp1, exp2, dt) 
#Calculate the scipy convolution 
sci = signal.convolve(exp1, exp2, mode = 'full') 
#Slice the first half to obtain the causal convolution and multiply by dt 
#to account for the step width 
sci = sci[0:steps] * dt 
#Calculate the convolution using the original Riemann sum algorithm 
riemann = convolveoriginal(exp1, exp2) 
riemann = riemann[0:steps] * dt 

#Plot 
plt.plot(time, analytical, label = 'analytical') 
plt.plot(time, trapezoidal, 'o', label = 'trapezoidal') 
plt.plot(time, riemann, 'o', label = 'Riemann') 
plt.plot(time, sci, '.', label = 'scipy.signal.convolve') 
plt.legend() 
plt.show() 

आपके समय के लिए धन्यवाद!

+3

अगर आप प्रदान करते हैं यह उपयोगी हो सकता है एक [ पूर्ण न्यूनतम उदाहरण] (http: // sscce।संगठन /) जो समस्या को पुन: उत्पन्न करता है, छोटी त्रुटियों को बाहर करने के लिए जैसे कि पूर्णांक विभाजन का उपयोग किया जाता है जहां सच्चे विभाजन का उपयोग किया जाना चाहिए। – jfs

+2

यदि आप 'विज्ञान' सरणी को दाईं ओर (एक चरण से) स्थानांतरित करते हैं और इसे सामान्यीकृत करते हैं तो समाधान [समान दिखते हैं] (http://i403.photobucket.com/albums/pp111/uber_ulrich/convolve.png): [' sci = np.r_ [0, विज्ञान [: चरण -1]] * 0.86'] (https://gist.github.com/ac45fb5d117d8ecb66a3)। ऐसा लगता है कि 'convolve() 'साधन (एफएफटी, परिपत्र) के विभिन्न परिभाषाएं हैं, [नम्पी/Scipy में कनवॉल्यूशन computations] में चर्चा देखें (http://stackoverflow.com/q/6855169/4279)। – jfs

+0

संकल्प धागे के संदर्भों के लिए धन्यवाद। सही बदलाव समस्या को ठीक करने के एक दिलचस्प तरीके की तरह दिखता है। क्या आप मुझे बता सकते हैं कि आपने 0.86 के सामान्यीकरण कारक को कैसे प्राप्त किया? मैंने मूल रिमैन योग एल्गोरिदम को शामिल किया है ताकि यह समझाया जा सके कि मेरा मानना ​​है कि यह संकल्प का अर्थ क्या है, इसकी एक अलग परिभाषा के बजाय यह संख्यात्मक आर्टेफैक्ट है। –

उत्तर

0

संक्षिप्त उत्तर: इसे सी में लिखें!

लांग जवाब

रसोई की किताब का उपयोग के बारे में numpy arrays मैं सी में समलम्बाकार घुमाव के विधि दुबारा लिखा आदेश सी कोड का उपयोग करने के एक से तीन फ़ाइलें (https://gist.github.com/1626919)

  • सी कोड (performancemodule की आवश्यकता है। सी)।
  • कोड बनाने के लिए सेटअप फ़ाइल और इसे पायथन (performancemodulesetup.py) से कॉल करने योग्य बनाएं।
  • अजगर फ़ाइल कि सी एक्सटेंशन (performancetest.py) का उपयोग करता है

कोड करके डाउनलोड करने पर चलाना चाहिए निम्न

  • performancemodule.c में शामिल पथ को समायोजित करें।
  • भागो निम्नलिखित

    अजगर performancemodulesetup.py अजगर का निर्माण

आप एक ही निर्देशिका में performancetest.py के रूप में पुस्तकालय फ़ाइल performancemodule.so या performancemodule.dll कॉपी करना पड़ सकता है performancetest.py।

परिणाम और प्रदर्शन

परिणाम एक दूसरे के साथ बड़े करीने से सहमति व्यक्त करते हैं जिन्हें आप नीचे देख:

Comparison of methods

सी विधि का प्रदर्शन scipy के convolve विधि से भी बेहतर है। सरणी लंबाई 50 के साथ 10k convolutions चलाने की आवश्यकता है

convolve (seconds, microseconds) 81 349969 
scipy.signal.convolve (seconds, microseconds) 1 962599 
convolve in C (seconds, microseconds) 0 87024 

इस प्रकार, सी कार्यान्वयन के बारे में 1000 बार अजगर कार्यान्वयन और थोड़ा की तुलना में तेजी से 20 से अधिक बार के रूप में तेजी से scipy कार्यान्वयन (वैसे, scipy कार्यान्वयन के रूप में अधिक बहुमुखी है)।

EDIT: यह मूल प्रश्न को ठीक से हल नहीं करता है लेकिन मेरे उद्देश्यों के लिए पर्याप्त है।

+0

'साइथन' आपको आसानी से सी एक्सटेंशन बनाने की अनुमति देता है, उदाहरण के लिए, ['rotT()'] (http://stackoverflow.com/a/4973390/4279)। – jfs

1

या, जो सी के लिए numpy पसंद करते हैं उनके लिए यह सी कार्यान्वयन से धीमा हो जाएगा, लेकिन यह केवल कुछ लाइनें है।

>>> t = np.linspace(0, maxtime-dt, 50) 
>>> fx = np.exp(-np.array(t)) 
>>> gx = 2*np.exp(-2*np.array(t)) 
>>> analytical = 2 * np.exp(-2 * t) * (-1 + np.exp(t)) 

इस इस मामले में समलम्बाकार तरह लग रहा है (लेकिन मैं गणित जांच नहीं की)

>>> s2a = signal.convolve(fx[1:], gx, 'full')*dt 
>>> s2b = signal.convolve(fx, gx[1:], 'full')*dt 
>>> s = (s2a+s2b)/2 
>>> s[:10] 
array([ 0.17235682, 0.29706872, 0.38433313, 0.44235042, 0.47770012, 
     0.49564748, 0.50039326, 0.49527721, 0.48294359, 0.46547582]) 
>>> analytical[:10] 
array([ 0.  , 0.17221333, 0.29682141, 0.38401317, 0.44198216, 
     0.47730244, 0.49523485, 0.49997668, 0.49486489, 0.48254154]) 

सबसे बड़ा निरपेक्ष त्रुटि:

>>> np.max(np.abs(s[:len(analytical)-1] - analytical[1:])) 
0.00041657780840698155 
>>> np.argmax(np.abs(s[:len(analytical)-1] - analytical[1:])) 
6