翼型俯仰+尾緣變形完整攻略)
做風力機葉片或者機翼的氣動彈性分析時我經常要面對一個不算特別復雜、但也非常容易翻車的需求翼型本身在繞某一點做俯仰振蕩與此同時尾緣還要疊加一定幅度的柔性變形。前者是典型的剛體運動對應Fluent動網格里的剛體區(qū)域加CG運動后者是典型的邊界變形對應Deforming區(qū)域加網格光順。兩個拆開做教程一抓一大把都不難一旦要求它們同時作用在同一個翼型上很多人就開始犯嘀咕了——動網格區(qū)域到底怎么設UDF怎么寫同一個邊界能不能又剛體又變形網格會不會在某個時刻直接被擠爆……這篇文章就圍繞“Fluent動網格實現(xiàn)翼型俯仰振蕩同時尾緣變形”這個組合把從方案選型、網格準備、UDF編寫到求解器設置、常見問題排錯的完整過程梳理一遍。案例本身選的是最簡單的NACA0012翼型低速來流剛體俯仰加尾緣二次型變形但里面的方法論可以直接遷移到風機葉片、渦輪葉片、直升機旋翼這類工程問題上。適合已經會跑基本Fluent仿真、想進階動網格的工程師也適合正在做氣動彈性課題、被“剛體柔性變形疊加”卡住的學生。1. 同樣都是動網格為什么這個案例要單獨拿出來講1.1 先想清楚翼型在“動”的到底是什么很多新手上來就寫UDF結果連自己要模擬的運動都沒拆清楚。翼型俯仰振蕩加尾緣變形聽起來是“一個運動”數學上其實是兩個獨立位移場的疊加。第一部分是剛體俯仰。整個翼型繞固定的彈性軸做正弦轉動典型形式是θ(t) θ? A·sin(2πft)其中θ?是平均攻角A是俯仰振幅f是俯仰頻率。這個運動的特點是翼型表面上所有網格節(jié)點的相對位置不改變整體繞旋轉中心轉一個角度。在Fluent里最經典的實現(xiàn)方式是DEFINE_CG_MOTION直接給定瞬時角速度即可。第二部分是尾緣變形。這個更微妙——它不是整體轉動而是翼型尾緣附近的一段邊界相對它自身的初始位置做一個連續(xù)、光滑的偏移。比如尾緣點在某個時刻下移0.03倍弦長然后離尾緣越近變形越大越往上游變形越小到某個起點位置變形恰好為零。這種運動不能用CG_MOTION表達因為它破壞了“剛性”——區(qū)域內節(jié)點之間的相對距離變了。所以本質上是剛體位移場 柔性變形場按時間同步疊加。搞清楚這一點后面所有技術選擇都順理成章。1.2 剛體俯仰和尾緣變形的“疊加”難點難點恰恰出在Fluent動網格的框架上。在一個動網格計算里一個邊界區(qū)域通常只允許一種運動屬性設成Rigid Body整個區(qū)域做剛性平移/旋轉你無法單獨挑出尾緣那一小塊讓它再多動一點設成Deforming所有節(jié)點的位置都由用戶自己控制剛體運動也得自己寫到UDF里。也就是說你不能把同一個壁面既設成剛體又設成Deforming。那怎么辦直覺的解決辦法是把翼型一分為二前段到尾緣上游設為Rigid Body做俯仰尾緣單獨設為Deforming做變形。中間切一個interface。這個思路我最早也試過結果是交界面兩側的網格密度必須高度匹配否則插值誤差會直接污染壁面壓力場而且邊界層在interface處被硬生生切斷動網格光順在這種位置經常出現(xiàn)負體積。真實算下來穩(wěn)定性很差。后來我換了一種思路既然Deforming模式允許我直接控制節(jié)點位置那為什么不在UDF里同時寫上“剛性旋轉位移 尾緣變形位移”讓Fluent的光順算法去處理網格內部更新這個思路最終穩(wěn)定跑通了也是下面這篇文章所有內容的核心。整個方案的代價是UDF要自己寫但換來的是對流場物理的更可控、對運動疊加的完全接管。2. 方案選型放棄CG Motion把整個翼型交給GRID_MOTION2.1 Fluent動網格三種方法哪些能用哪些不能用Fluent動網格大體有三類手段Smoothing、Remeshing、Overset。選型前建議先把適用范圍圈清楚。方法適用場景本案例可行性Smoothing光順邊界位移中小幅度網格拓撲不變核心手段配合Diffusion光順Remeshing局部重構大位移、大轉動局部網格拓撲重建輔助手段大俯仰角時需要Overset重疊網格多體大位移、相互穿越可用但殺雞用牛刀交界面插值額外耗成本本案例的運動量級如果控制在工程界很常見的范圍內——俯仰振幅±5°、尾緣變形3%~5%弦長——那么Smoothing加局部Remeshing足夠。Diffusion-based光順比彈簧光順的魯棒性好得多尤其適合邊界做旋轉運動的情況因為它會把變形量“均勻擴散”到全場而不是像彈簧一樣在局部積累。真正需要糾結的并不是這三種方法的取舍而是邊界區(qū)域運動屬性怎么設。我最終使用的是Deforming區(qū)域加DEFINE_GRID_MOTION讓一個UDF同時控制剛體旋轉和尾緣變形內部網格交給Diffusion光順吸收變形。2.2 本案例的動網格區(qū)域設置在Fluent里按照下面的方式設置動網格區(qū)域思路很清晰打開Dynamic Mesh啟用Smoothing和Remeshing在Dynamic Mesh Zones中將翼型壁面設置為DeformingMotion UDF指定為后面要寫的airfoil_pitch_deform遠場邊界設置為Stationary保持固定計算域內部不需要額外指定動態(tài)區(qū)域光順算法會自動把壁面的位移擴散到整個網格。這里有個容易誤解的點Deforming區(qū)域指定的雖然是翼型壁面但Fluent在調用UDF得到壁面節(jié)點位移后會通過Smoothing算法把位移逐步傳遞到內部網格節(jié)點。所以UDF里只需要管壁面節(jié)點的位置內部網格怎么動是求解器的事。Smoothing參數里我習慣把Diffusion參數調到1.5~2.0。Diffusion參數越大壁面附近的位移衰減越快網格更傾向于在遠場吸收變形這對保護邊界層質量非常關鍵。如果案例的俯仰角較大再把Remeshing里Minimum Length Scale和Maximum Length Scale設成當地網格尺寸的0.5倍和2倍目標偏斜度0.7左右局部網格壞了就讓Fluent自動重構。2.3 計算域、網格與邊界層準備要點網格是整個動網格算例的地基。翼型幾何本身可以用NACA0012標準型值點生成弦長取1m。計算域推薦C型或O型拓撲遠場半徑取20~30倍弦長太小會污染氣動力系數太大浪費網格量。近壁網格按y≈1來準備。粗略估算第一層網格高度可以直接用平板邊界層公式uτ U·√(Cf/2)Cf ≈ 0.0576·Re_x^(-1/5)y? y·μ/(ρ·uτ)以Re3×10?、來流50m/s估算第一層高度大約在10??m量級。邊界層內網格增長率建議1.1~1.2尾緣變形區(qū)域x/c從0.7到1.0的弦向網格間距建議不大于0.01c否則變形后網格會被拉伸得很難看。如果你用的是Fluent Meshing而非ICEM有個操作細節(jié)容易踩新建的Group在網格顯示里不出現(xiàn)多半不是網格沒建上而是顯示對象的勾選沒對上。在Graphics面板里新建Scene把要顯示的Zone或Group加進去并勾選刷新一下就會顯示。直接在Mesh Display的默認設置里找新Group經常找不到。網格生成后先檢查質量skewness最好小于0.7minimum orthogonal quality大于0.2。動網格案例的網格質量余量要比定常算例留得更足因為變形過程會讓網格質量持續(xù)下降。3. UDF逐行拆解俯仰加尾緣變形的核心邏輯3.1 為什么剛體旋轉要用角度增量而不是絕對角度這是整個UDF里最容易寫錯的地方也最需要理解清楚。Fluent的DEFINE_GRID_MOTION在每一個時間步開始前被調用它執(zhí)行的是在當前網格位置基礎上施加一個位移增量而不是直接把節(jié)點挪到某個絕對位置。如果你寫成“把節(jié)點坐標設置為旋轉后的絕對坐標”那么第一個時間步網格挪到位第二個時間步又基于被挪過的位置再設置一次位移會反復累積幾個步之后網格就廢了。正確做法是計算當前步的角度增量dθ θ(tΔt) - θ(t)然后把這個增量對應的節(jié)點位移加到當前坐標上。寫成代碼就是dx xr·(cos(dθ) - 1) - yr·sin(dθ)dy xr·sin(dθ) yr·(cos(dθ) - 1)其中(xr, yr)是節(jié)點相對旋轉中心的相對坐標。這個方式無論dθ多大都能保持剛性旋轉的精確性不會產生小角度近似誤差。還有一個好處Fluent在一個物理時間步內可能因為網格重構問題多次調用動網格函數但傳入的time和dtime是同一個時間步的這樣dθ每次算出來都是0不會重復疊加位移。用絕對角度寫法就會出大問題。3.2 DEFINE_GRID_MOTION完整代碼與注釋下面給出我實際使用的完整UDF代碼層面做了參數化處理方便調到自己的工況。#include udf.h #include dynamesh_tools.h #include math.h #ifndef M_PI #define M_PI 3.14159265358979323846 #endif /* 翼型參數 */ #define CHORD 1.0 /* 弦長 */ #define PITCH_CX 0.25 /* 俯仰旋轉中心x坐標取1/4弦點 */ #define PITCH_CY 0.0 /* 旋轉中心y坐標 */ /* 俯仰運動參數 */ #define PITCH_AMP 5.0 /* 俯仰振幅單位度 */ #define PITCH_FREQ 2.0 /* 俯仰頻率單位Hz */ /* 尾緣變形參數 */ #define TAIL_X0 0.7 /* 尾緣變形起始位置x/c */ #define TAIL_AMP 0.03 /* 尾緣最大變形量單位m0.03倍弦長 */ #define TAIL_FREQ 4.0 /* 尾緣變形頻率單位Hz */ DEFINE_GRID_MOTION(airfoil_pitch_deform, domain, dt, time, dtime) { Thread *tf DT_THREAD(dt); face_t f; Node *v; int n; real theta, theta_pdt, dtheta; real cos_d, sin_d; real x, y, xr, yr, dxr, dyr; real dx, dy; real xr_norm, shape, dy_deform; /* 標記當前線程為網格變形線程這一步不能少 */ SET_DEFORMING_THREAD_FLAG(THREAD_T0(tf)); /* 計算本時間步的角度增量 */ theta PITCH_AMP * M_PI / 180.0 * sin(2.0 * M_PI * PITCH_FREQ * time); theta_pdt PITCH_AMP * M_PI / 180.0 * sin(2.0 * M_PI * PITCH_FREQ * (time dtime)); dtheta theta_pdt - theta; cos_d cos(dtheta); sin_d sin(dtheta); begin_f_loop(f, tf) { f_node_loop(f, tf, n) { v F_NODE(f, tf, n); if (NODE_POS_NEED_UPDATE(v)) { NODE_POS_UPDATED(v); x NODE_X(v); y NODE_Y(v); /* 1. 剛體俯仰旋轉繞旋轉中心的位移增量 */ xr x - PITCH_CX; yr y - PITCH_CY; dxr xr * (cos_d - 1.0) - yr * sin_d; dyr xr * sin_d yr * (cos_d - 1.0); dx dxr; dy dyr; /* 2. 尾緣變形在尾緣局部疊加y向變形 */ if (x TAIL_X0) { xr_norm (x - TAIL_X0) / (CHORD - TAIL_X0); /* 二次形狀函數起始位置變形為0尾緣處變形最大 */ shape xr_norm * xr_norm; dy_deform TAIL_AMP * shape * sin(2.0 * M_PI * TAIL_FREQ * time); dy dy_deform; } NODE_X(v) dx; NODE_Y(v) dy; } } } end_f_loop(f, tf) }代碼本身并不長但有幾個關鍵點需要重點解釋。首先SET_DEFORMING_THREAD_FLAG(THREAD_T0(tf))是必須的它告訴Fluent當前線程的網格節(jié)點需要更新位置。如果不設置UDF雖然會被調用但節(jié)點位置可能完全不變化問題是“函數執(zhí)行了網格紋絲不動”很多新手在這個坑里耗很久。其次NODE_POS_NEED_UPDATE和NODE_POS_UPDATED是配套使用的防重復更新機制。在一個時間步里同一個節(jié)點可能被多個面共享如果不做這個判斷節(jié)點會在這個循環(huán)里被反復更新位移被疊加多次。這是寫好動網格UDF的基本功。第三f_node_loop(f, tf, n)里的n是節(jié)點在當前面上的局部編號每次循環(huán)拿到的v是一個指向節(jié)點的指針。Fluent允許一個節(jié)點被多個面共享但因為有了NODE_POS_NEED_UPDATE的判斷共享節(jié)點只被更新一次。編譯時選擇Compiled UDF不能用Interpreted模式因為代碼里用了dynamesh_tools.h。編譯成功后在Dynamic Mesh Zones的Deforming區(qū)域的Motion UDF下拉列表里選擇airfoil_pitch_deform。3.3 尾緣變形的形狀函數與變形范圍設定代碼里的shape xr_norm * xr_norm也就是從變形起始點x/c0.7到尾緣x/c1.0采用二次函數過渡。這樣保證了在起始位置變形量及其斜率都為0避免在x0.7處出現(xiàn)幾何突變——如果變形函數在起始點不光滑那個位置附近會產生很大的網格畸變很容易直接負體積。如果想要更光滑的過渡可以用Hermite型形狀函數shape xr_norm3 · (6·xr_norm2 - 15·xr_norm 10)這個函數在起始點和終點的一階導都是0變形輪廓更接近結構模態(tài)里的懸臂梁一階彎曲振型。我實際對比過這個函數對網格質量的保護明顯好于簡單二次型代價只是多一行代碼。變形方向這里用了全局y方向是因為NACA0012上下表面本身關于x軸對稱尾緣垂直方向變形可以近似用y向表達。如果要做有彎度的翼型或變形方向沿局部表面法向需要更精細的處理在face循環(huán)里通過F_AREA(f, tf)取面的面積矢量歸一化得到法向再把變形位移沿法向施加。這會讓UDF更復雜但物理意義更準確。還有一個經驗變形量和頻率不要一開始就拉滿。建議先用俯仰UDF單獨跑通再疊加尾緣變形。疊加時先給一半振幅確認網格沒問題再逐步加大。4. 求解設置與收斂控制先穩(wěn)后動是鐵律4.1 定常初場為什么要先“凍住”翼型算穩(wěn)定動網格計算最忌諱的就是從均勻流場直接啟動。如果初始化后就直接開瞬態(tài)、動網格第一個時間步翼型開始轉動尾緣開始變形流場會感受到一個劇烈的“沖擊”壁面附近必然產生非物理的壓力波輕則前幾個周期升力系數亂跳重則直接發(fā)散。我的標準流程是先用定常求解器在平均攻角位置把翼型固定住算一個穩(wěn)態(tài)流場待殘差降到1×10??以下升阻力系數不再明顯變化再切換為瞬態(tài)在瞬態(tài)計算開始的同時打開動網格讓網格運動在一個相對真實的流場上逐步啟動。如果定常計算本身就很難收斂先解決網格和湍流模型的問題不要指望動網格能幫你“兜底”。動網格只會放大初場的不穩(wěn)定不會修正它。實際操作中很多老工程師還會在切瞬態(tài)后先固定翼型再跑幾百步讓定常流場在瞬態(tài)格式下進一步穩(wěn)定然后才真正啟動動網格。這個方法尤其適合雷諾數較高、邊界層敏感的算例。4.2 時間步長、約化頻率與每步迭代次數本案例的參數我建議這樣取項目設定值說明來流速度50 m/s低速不可壓縮弦長1 m參考長度俯仰頻率2 Hz周期T0.5s約化頻率kπfc/U≈0.126較低約化頻率對時間步長要求不算苛刻時間步長0.0005~0.001 sT/500到T/1000每步內迭代20~40次視殘差和升力系數穩(wěn)定情況網格最大位移小于最小網格尺寸的1/3重要的穩(wěn)定性判據約化頻率k是無量綱的振蕩頻率公式是kπfc/U。它直接決定了流動非定常性的強弱。k0.126屬于低頻大幅振蕩流場能較快響應翼型運動如果k接近0.5甚至更高時間步長必須成倍縮小。時間步長的選擇除了滿足每個周期的采樣點數還要考慮網格位移。一個時間步內翼型表面節(jié)點移動的距離不能超過當地最小網格尺寸的三分之一否則Diffusion光順很容易產生負體積。用這個判據反推往往比單純按周期取步長更有效。并行計算方面Fluent Launcher啟動時在Parallel選項卡里設置的Processor進程數一般不超過機器物理核心數。動網格加UDF的計算我建議先跑串行或4核以下排查UDF和網格問題確認穩(wěn)定后再上大規(guī)模并行否則日志文件里全是網格畸變報錯排查效率極低。4.3 湍流模型與離散格式選型依據低速翼型繞流壓力基求解器是自然選擇。湍流模型我在這個案例里推薦兩段式策略先用Spalart-Allmaras模型把計算框架跑通得到初步結果后再用SST k-ω模型做正式計算。理由很直接SA模型只有單一湍流輸運方程數值魯棒性好收斂難度低特別適合在動網格調通階段使用但SA對強逆壓梯度下的流動分離預測偏粗糙。翼型俯仰振蕩往往伴隨動態(tài)失速尾緣附近的流動會出現(xiàn)周期性分離與再附這時候SST k-ω對分離點和再附的捕捉準確得多代價是收斂難度上升對網格質量更敏感。離散格式的設置我有明確偏好壓力用Second Order動量用Second Order Upwind湍流量也用Second Order Upwind。瞬態(tài)格式先用First Order Implicit起跑50~100步等流場結構穩(wěn)定后切換到Bounded Second Order Implicit。壓力速度耦合推薦Coupled雖然每個迭代步成本高一些但整體時間步內收斂更快動網格工況下比SIMPLE族算法更穩(wěn)。我不建議在正式計算時開Solution Steering的自動模式它為了魯棒性會主動降低離散格式迎風階數掩蓋網格運動帶來的真實數值行為結果就是“算完看著沒發(fā)散但曲線一塌糊涂”。手動控制格式每步監(jiān)控殘差和升力系數才是最可靠的。5. 實戰(zhàn)踩坑記錄負體積、發(fā)散和曲線導出5.1 負體積網格到底在哪里被“擠爆”了跑動網格的人對這條報錯一定不陌生Negative Cell Volume。第一次遇到時基本是凌晨兩三點盯著Console里的報錯代碼一臉茫然。根據我的經驗負體積最常出現(xiàn)在兩個位置一是旋轉中心附近的邊界層網格二是尾緣變形起始點x/c0.7附近。前者的機理是網格在旋轉過程中被“壓扁”后者則是變形函數曲率突變導致的拉伸過度。排查套路要系統(tǒng)看Console里報出的單元ID在Display面板用Cell ID顯示方式把這幾個網格高亮出來先確認“爆”在哪回看報錯時間是物理時間還是某一步——是所有周期都會爆還是只在某個俯仰角附近爆如果是所有周期都爆優(yōu)先減小時間步長如果只在大角度時刻爆說明光順算法來不及吸收位移需要加大Diffusion參數或調整變形形狀函數確認負體積網格集中在極薄的邊界層區(qū)域時考慮減少每個時間步內壁面節(jié)點位移而不是盲目加密網格——網格越密允許的位移反而越小。Debug時最好先關閉Remeshing把問題全部歸因到Smoothing身上。如果關閉重構后網格能跑通再開啟Remeshing并仔細設置最小和最大尺寸標尺。用尾緣變形做調試時我會故意把變形量設成0先跑一個32核、幾百步的純俯仰算例確認光順參數沒有大問題再逐步加變形量。這樣能把變量隔離快速定位問題源頭。5.2 升力曲線毛刺與網格更新頻率的關系動網格計算完成后把升力系數時程導出來經常能看到曲線底部有密密麻麻的小鋸齒。試幾個案例之后你會明白這通常不是物理現(xiàn)象而是數值噪聲。毛刺的來源往往是每個時間步開始時的網格位置更新導致壁面附近的壓力場瞬間被擾動。如果每步內迭代次數太少、壓力場尚未充分恢復就進入下一步鋸齒就會逐級累積。我的對策順序是增加每步內迭代次數到30~50次觀察毛刺是否收斂如果仍然有鋸齒把時間步長減半代價是計算量翻倍調大Diffusion參數讓網格位移在空間上更平滑減小局部網格體積突變率檢查Smoothing里的Spring Constant或Diffusion參數設置不要同時開多個高剛度設置。我自己的經驗總結是升力曲線小幅鋸齒可以接受但如果鋸齒幅值超過升力平均值的1%說明數值噪聲已經大到會污染高階統(tǒng)計量必須處理后再繼續(xù)計算。5.3 Report Definition曲線導出與后處理經驗很多人在Fluent里定義了Report Definition計算完了卻不知道怎么把曲線數據導出來。操作其實很簡單在樹形菜單的Results → Report Definitions里找到你定義的升力系數或阻力系數右鍵選擇Export會彈出一個保存CSV或文本文件的對話框里面就是每個時間步的物理時間與對應量值。如果想要計算過程中自動保存就在創(chuàng)建Report Definition時勾選Write to File并設置輸出文件路徑。計算結束后直接拿到完整時程數據不用再手動點Export。如果要用Origin或matplotlib畫圖我習慣把第一個參數列設為t/T無量綱周期數第二列設為Cl第三列為Cd第四列為Cm。對比文獻數據時注意力矩參考點很多文獻的Cm參考點是1/4弦線Fluent里默認參考點要自己核對。需要導出壁面壓力分布時用File → Export → Solution Data在Location里選翼型壁面Variable里勾選Pressure和Wall Shear可以導出各個工位的壓力系數分布。后續(xù)對所有時刻的壓力分布做積分還能還原出升力系數時程和Report Definition的直出結果互相校驗。最后再多說一句關于這個算例我前后調了很多個版本最大的體會是動網格發(fā)散十有八九不是求解器不行而是運動寫得不干凈要么是剛體旋轉用了絕對位移導致累計誤差要么是變形函數在節(jié)點處不光滑要么是Deforming區(qū)域和Smoothing參數配合不合適。尤其是“剛體加柔性變形”這種疊加運動坐標系、增量寫法、起始范圍這三點想清楚整個案例就成功了一半。如果后面你遇到類似問題可以先用一個只有俯仰的UDF把網格魯棒性測利索再漸進式地把尾緣變形加進來。動網格這個東西慢就是快急不來。