簡體   English   中英

如何繪制grad(f(x,y))?

[英]How to plot grad(f(x,y))?

我想計算並繪制兩個變量的任何標量函數的梯度。 如果你真的想要一個具體的例子,讓我們說f = x ^ 2 + y ^ 2,其中x從-10到10,對y來說是相同的。 如何計算和繪制grad(f)? 解決方案應該是矢量,我應該看到矢量線。 我是python的新手所以請使用簡單的單詞。

編輯:

@Andras Deak:謝謝你的帖子,我嘗試了你的建議,而不是你的測試功能(fun = 3 * x ^ 2-5 * y ^ 2)我使用了我定義為V(x,y)的函數; 這是代碼的樣子,但報告錯誤

import numpy as np
import math 
import sympy
import matplotlib.pyplot as plt

def V(x,y):
    t=[]
    for k in range (1,3): 
        for l in range (1,3):
            t.append(0.000001*np.sin(2*math.pi*k*0.5)/((4*(math.pi)**2)* (k**2+l**2)))  
            term = t* np.sin(2 * math.pi * k * x/0.004) * np.cos(2 * math.pi * l * y/0.004)
            return term 
    return term.sum()

x,y=sympy.symbols('x y')
fun=V(x,y)
gradfun=[sympy.diff(fun,var) for var in (x,y)]
numgradfun=sympy.lambdify([x,y],gradfun)

X,Y=np.meshgrid(np.arange(-10,11),np.arange(-10,11))
graddat=numgradfun(X,Y)
plt.figure()
plt.quiver(X,Y,graddat[0],graddat[1])
plt.show()

AttributeError: 'Mul' object has no attribute 'sin'

讓我說我刪除罪,我得到另一個錯誤:

TypeError: can't multiply sequence by non-int of type 'Mul'

我閱讀了針對sympy的教程並且它說“像SymPy這樣的符號計算系統的真正力量是能夠象征性地進行各種計算”。 我得到了這個,我只是不明白為什么我不能將x和y符號乘以浮點數。

這是怎么回事? :( 請幫忙!

UPDATE

@Andras Deak:我想讓事情更短,所以我從V(x,y)和Cn * Dm的原始公式中刪除了許多常量。 正如你所指出的,這導致sin函數總是返回0(我剛注意到)。 為此道歉。 我將在今天晚些時候更新帖子,當時我會詳細閱讀您的評論。 十分感謝!

更新2我在表達式中更改了電壓系數,這是結果:

情節

它看起來不錯,只是箭頭指向相反的方向(它們應該從紅色點出來並進入藍色點)。 你知道我怎么能改變它嗎? 如果可能的話,你能告訴我增加箭頭大小的方法嗎? 我嘗試了另一個主題( 計算和繪圖矢量字段 )中的建議:

skip = (slice(None, None, 3), slice(None, None, 3))

這只繪制了每三個箭頭和matplotlib進行自動縮放,但它對我不起作用(當我添加此項時,沒有任何反應,對於我輸入的任何數字)你已經得到了很大的幫助,我不能夠感謝你!

這是一個使用sympynumpy的解決方案。 這是我第一次使用sympy,因此其他人/可能會提出更好,更優雅的解決方案。

import sympy

#define symbolic vars, function
x,y=sympy.symbols('x y')
fun=3*x**2-5*y**2

#take the gradient symbolically
gradfun=[sympy.diff(fun,var) for var in (x,y)]

#turn into a bivariate lambda for numpy
numgradfun=sympy.lambdify([x,y],gradfun)

現在你可以使用numgradfun(1,3)計算(x,y)==(1,3)處的梯度。 然后,此功能可用於繪圖,您可以這樣做。

對於繪圖,您可以使用matplotlibquiver ,例如:

import numpy as np
import matplotlib.pyplot as plt

X,Y=np.meshgrid(np.arange(-10,11),np.arange(-10,11))
graddat=numgradfun(X,Y)

plt.figure()
plt.quiver(X,Y,graddat[0],graddat[1])
plt.show()

在此輸入圖像描述

UPDATE

您為要計算的函數添加了規范。 它包含取決於xy的術語的乘積,這似乎打破了我的上述解決方案。 我設法想出一個新的,以滿足您的需求。 但是,你的功能似乎毫無意義。 來自您編輯的問題:

t.append(0.000001*np.sin(2*math.pi*k*0.5)/((4*(math.pi)**2)* (k**2+l**2)))
term = t* np.sin(2 * math.pi * k * x/0.004) * np.cos(2 * math.pi * l * y/0.004)

另一方面,從您對應答案的相應評論:

V(x,y)= [Cn * Dm * sin(2pinx)* cos(2pimy)]的n和m之和; 總和從-10到10; Cn和Dm是系數,並且我計算出CkD1 = sin(2pik)/(k ^ 2 + 1 ^ 2)(這里我使用k和l作為來自n和m之和的索引之一)。

我有幾個問題: sin(2*pi*k)sin(2*pi*k/2) (前因子中的兩個競爭版本對於整數k總是為零,每次給你一個恆定的零V (x,y) 。此外,在你的代碼中,你在三角函數中有神奇的頻率因子,它們在評論中缺失。如果你將x乘以4e-3 ,你就會大大改變函數的空間依賴性(通過改變波長大約是一千倍。所以你應該真正決定你的功能是什么。

所以這是一個解決方案,我假設了

V(x,y)= sum_ {k,l = 1到10} C_ {k,l} * sin(2 * pi * k * x)* cos(2 * pi * l * y),
C_ {K,L} = SIN(2 * PI * K / 4)/((4 * PI ^ 2)*(K ^ 2 + 1 ^ 2))* 1E-6

這是函數的各種版本的組合,在prefactor中修改sin(2*pi*k/4)以具有非零函數。 在您找到合適的數學模型后,我希望您能夠根據實際需要確定數值因子。

所以這是完整的代碼:

import sympy as sp
import numpy as np
import matplotlib.pyplot as plt

def CD(k,l):
    #return sp.sin(2*sp.pi*k/2)/((4*sp.pi**2)*(k**2+l**2))*1e-6
    return sp.sin(2*sp.pi*k/4)/((4*sp.pi**2)*(k**2+l**2))*1e-6

def Vkl(x,y,k,l):
    return CD(k,l)*sp.sin(2*sp.pi*k*x)*sp.cos(2*sp.pi*l*y)

def V(x,y,kmax,lmax):
    k,l=sp.symbols('k l',integers=True)
    return sp.summation(Vkl(x,y,k,l),(k,1,kmax),(l,1,lmax))


#define symbolic vars, function
kmax=10
lmax=10
x,y=sp.symbols('x y')
fun=V(x,y,kmax,lmax)

#take the gradient symbolically
gradfun=[sp.diff(fun,var) for var in (x,y)]

#turn into bivariate lambda for numpy
numgradfun=sp.lambdify([x,y],gradfun,'numpy')
numfun=sp.lambdify([x,y],fun,'numpy')

#plot
X,Y=np.meshgrid(np.linspace(-10,10,51),np.linspace(-10,10,51))
graddat=numgradfun(X,Y)
fundat=numfun(X,Y)

hf=plt.figure()
hc=plt.contourf(X,Y,fundat,np.linspace(fundat.min(),fundat.max(),25))
plt.quiver(X,Y,graddat[0],graddat[1])
plt.colorbar(hc)
plt.show()

我使用一些輔助功能來定義你的V(x,y)函數以實現透明度。 我把總和截止值作為文字參數, kmaxlmax :在你的代碼中這些是3,在你的評論中他們被認為是10,無論如何他們應該是無限的。

漸變采用與以前相同的方式,但是當使用lambdify轉換為numpy函數時,您必須設置一個額外的字符串參數'numpy' 這將使得生成的numpy lambda接受數組輸入(基本上它將使用np.sin而不是math.sin ,而cos則相同)。

我還將網格的定義從array更改為np.linspace :這通常更方便。 由於你的函數在整數網格點幾乎不變,我創建了一個更密集的網格用於繪圖(51點,同時保持原始極限(-10,10)固定)。

為清楚起見,我還包括了幾個圖:一個用於顯示函數值的contourf (輪廓線應始終與梯度向量正交),以及一個用於指示函數值的contourf條。 這是結果:

在此輸入圖像描述

組成顯然不是最好的,但我不想偏離你的規格太多。 這個圖中的箭頭實際上幾乎看不到,但正如你所看到的(並且從V的定義中也很明顯),你的函數是周期性的,所以如果用較小的限制和較少的網格點繪制相同的東西,你會看到更多功能和更大的箭頭。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM