23 優(yōu)化
上一章我們建立了一個(gè)棒球飛行模型,其中包括重力和一個(gè)簡單的阻力褒纲,但忽略了自旋准夷、馬格努斯力和阻力系數(shù)對(duì)速度的依賴。
在本章中莺掠,我們將對(duì)該模型進(jìn)行優(yōu)化衫嵌。
23.1 曼尼-拉米雷斯問題
曼尼-拉米雷斯是波士頓紅襪隊(duì)(美國棒球隊(duì))的前成員,他因其輕松的態(tài)度和講笑話的品味而聞名彻秆。我們本章的目標(biāo)是解決下面這個(gè)受曼尼啟發(fā)的問題:
在芬威公園擊出全壘打所需的最小力是多少楔绞?
芬威公園是一座位于馬薩諸塞州波士頓的棒球場。其中最著名的特色之一就是“綠色怪物”唇兑,它是左外野的一堵墻酒朵,離本壘板非常近,只有310英尺扎附,為了彌補(bǔ)這個(gè)短距離蔫耽,這面墻異常的高,有37英尺帕棉。(詳見http://modsimpy.com/wally)
我們要找到球離開本壘同時(shí)還能越過“綠色怪物”的最低速度针肥,我們將按照以下步驟進(jìn)行:
1.給定速度饼记,我們要找出最佳發(fā)射角度香伴,也就是球離開本壘的角度,以使球到達(dá)墻面時(shí)高度最大具则。
2.然后我們將找到在最佳發(fā)射角度下越過墻的最小速度即纲。
我們將使用與上一章相同的模型,和這個(gè)Params對(duì)象:
t_end = 20 * s
dt = t_end / 100
params = Params(x = 0 * m,
y = 1 * m,
g = 9.8 * m/s**2,
mass = 145e-3 * m,
rho = 1.2 * kg/m**3,
C_d = 0.3,
angle = 45 * degree;
velocity = 40 * m/s,
t_end=t_end,
dt=dt)
make_system函數(shù):
def make_system(params):
angle, velocity = params.angle, params.velocity
# convert angle to degrees
theta = np.deg2rad(angle)
# compute x and y components of velocity
vx, vy = pol2cart(theta, velocity)
# make the initial state
R = Vector(params.x, params.y)
V = Vector(vx, vy)
init = State(R=R, V=V)
# compute area from diameter
diameter = params.diameter
area = np.pi * (diameter/2)**2
return System(params, init=init, area=area)
slope函數(shù):
def slope_func(state, t, system):
R, V = state
mass, g = system.mass, system.g
a_drag = drag_force(V, system) / mass
a_grav = Vector(0, -g)
A = a_grav + a_drag
return V, A
還有event函數(shù):
def event_func(state, t, system):
R, V = state
return R.y
23.2 尋找范圍
假設(shè)我們想找到最大射程的發(fā)射角度博肋,最大射程就是球在落地前在空中的飛行距離低斋。我們將使用ModSim庫中的一個(gè)函數(shù)maximize蜂厅,它可以接受一個(gè)函數(shù)并找到其最大值。
我們傳遞給maximize的函數(shù)應(yīng)該包含發(fā)射角度和一個(gè)params對(duì)象膊畴,并返回射程:
def range_func(angle, params):
params = Params(params, angle=angle)
system = make_system(params)
results, details = run_ode_solver(system, slope_func,
events=event_func)
x_dist = get_last_value(results.R).x
print(angle, x_dist)
return x_dist
range_func用給定的angle值創(chuàng)建一個(gè)新的Params對(duì)象掘猿,然后創(chuàng)建System對(duì)象,調(diào)用run_ode_solver唇跨,從結(jié)果中返回x的最終值稠通。
我們可以像這樣直接調(diào)用range_func:
range_func(45, params)
然后我們可以像這樣掃描一系列的角度:
angles = linspace(20, 80, 21)
sweep = SweepSeries()
for angle in angles:
x_dist = range_func(angle, params)
print(angle, x_dist)
sweep[angle] = x_dist
圖23.1展示了結(jié)果,看來最佳角度是在40°到45°之間买猖。
圖23.1:給定速度改橘,發(fā)射角度和距離本壘板的距離構(gòu)成的函數(shù)
我們可以更精確、更有效地使用maximize找到最佳角度玉控,比如這樣:
res = maximize(range_func, [0, 90], params)
第一個(gè)參數(shù)是我們要最大化的函數(shù)飞主,第二個(gè)參數(shù)是我們要找的數(shù)值范圍,本例中數(shù)值范圍為0°到90°高诺,第三個(gè)參數(shù)可以是任何對(duì)象碌识,當(dāng)maximize調(diào)用range_func時(shí)它會(huì)被作為參數(shù)傳遞過來。
maximize的返回值是一個(gè)表示結(jié)果的一維數(shù)組懒叛,包括x丸冕,即達(dá)到函數(shù)最高點(diǎn)的角度,和fun薛窥,即range_func在x處的值胖烛,也就是棒球以最佳角度發(fā)射時(shí)和本壘板的距離。
對(duì)于這些參數(shù)诅迷,最佳角度約為42°佩番,對(duì)應(yīng)射程為103m。
maximize使用了黃金分割搜索罢杉,你可以在這里閱讀到http://modsimpy.com/minimize
23.3解決問題
在本章的notebook代碼chap22.ipynb中趟畏,你將有機(jī)會(huì)解決曼尼-拉米雷斯問題,不過你需要做以下幾件事:
- 在上一節(jié)中滩租,“最佳”發(fā)射角度是指最大射程的角度赋秀,但這不是我們想要的。相反律想,我們想要的是當(dāng)球到達(dá)墻邊(距離本壘板310英尺)時(shí)高度最大化的角度猎莲,所以你需要寫一個(gè)高度函數(shù)來計(jì)算它,然后使用maximize來找到修改后的最優(yōu)值技即。
- 一旦找到任意速度的最佳角度著洼,接著我們需要找出讓球越過墻壁的最小速度,你可以寫一個(gè)函數(shù),把速度作為參數(shù)身笤,計(jì)算出這個(gè)速度的最佳角度豹悬,然后使用這個(gè)最佳角度返回球在墻上的高度。
- 最后液荸,你可以使用root_bisect來找到速度瞻佛,使墻的高度剛好是37英尺。
notebook上提供了一些額外的提示娇钱,這上面應(yīng)該有你需要的一切涤久,祝你好運(yùn)!
如果你喜歡這個(gè)練習(xí)忍弛,你可能會(huì)對(duì)這篇文章感興趣:How to hit home runs: Optimum baseball bat swing parameters for maximum range trajectories响迂,作者是Sawicki,Hubbard和Stronge细疚,網(wǎng)址: http://modsimpy.com/runs.
本書的中文翻譯由南開大學(xué)醫(yī)學(xué)院智能醫(yī)學(xué)工程專業(yè)2018級(jí)蔗彤、2019級(jí)的師生完成,方便后續(xù)學(xué)生學(xué)習(xí)《Python仿真建姆杓妫》課程然遏。翻譯人員(排名不分前后):薛淏源、金鈺吧彪、張雯待侵、張瑩睿、趙子雨姨裸、李翀秧倾、慕振墺、許靖云傀缩、李文碩那先、尹瀛寰、沈紀(jì)辰赡艰、迪力木拉售淡、樊旭波、商嘉文慷垮、趙旭揖闸、連煦、楊永新料身、樊一諾汤纸、劉志鑫、彭子豪惯驼、馬碧婷蹲嚣、吳曉玲、常智星祟牲、陳俊帆隙畜、高勝寒、韓志恒说贝、劉天翔议惰、張藝瀟、劉暢乡恕。
整理校訂由劉暢完成言询,如果您發(fā)現(xiàn)有翻譯不當(dāng)或者錯(cuò)誤,請(qǐng)郵件聯(lián)系changliu@nankai.edu.cn傲宜。
本書中文版不用于商業(yè)用途运杭,供大家自由使用。
未經(jīng)允許函卒,請(qǐng)勿轉(zhuǎn)載辆憔。