在iOS端做流体力学相关的仪表盘,往往会遇到一个矛盾:既要看到大尺度涡旋的整体形态,又必须呈现近壁面处直接数值模拟才能捕捉到的精细湍流结构。将大涡模拟(LES)与直接数值模拟(DNS)混合,是一种兼顾算力与精度的工程解法。本文围绕Core Graphics如何把这种混合模拟的结果实时绘制到流量计风格的仪表盘展开,重点说明数值层的耦合方式以及图形层的高效渲染策略。

LES与DNS混合方法的计算原理
大涡模拟的核心思想是对 Navier-Stokes 方程做滤波,将尺度大于网格宽度的涡显式求解,小于滤波宽度的部分用亚格子模型(如 Smagorinsky 模型)来近似。这样做可以把计算量从 DNS 的 O(Re^3) 降到可接受范围。但直接数值模拟不做任何滤波,所有尺度直接离散,因此在边界层、分离区等小尺度主导的区域,DNS 的结果明显更可靠。
混合方法通常按空间区域或尺度区间拆分:在流场主体用 LES 推进,在仪表盘探针附近或管壁临界层切出一块子域跑 DNS。两个域在交界面交换速度场与通量,常用缓冲层(overlap zone)来减小数值反射。下面是一段简化版的耦合步进伪代码,用 Swift 表达计算过程:
// 混合求解器每一步
func step(dt: Double) {
// LES 主体域推进
lesSolver.applySubgridModel()
lesSolver.advance(dt: dt)
// 取交界面速度
let interfaceVel = lesSolver.velocityAt(interface)
// DNS 子域以界面速度为边界条件
dnsSolver.setBoundary(interfaceVel)
dnsSolver.advance(dt: dt)
// 把 DNS 精细结果写回 LES 缓冲层
lesSolver.writeBack(dnsSolver.fineVelocity)
}
亚格子模型在这里不只是数值稳定器,它直接决定了可视化时小尺度能量的表现。若 Smagorinsky 常数取值偏大,绘出来的湍流会过于平滑,丢失仪表盘需要的“毛刺感”;偏小则计算发散。因此在 iOS 端做可视化前,通常要在离线训练集上标定常数,再固化到 App 的资源包中。
用Core Graphics将流场映射为仪表盘图形
Core Graphics 是 iOS 上基于 Quartz 的底层绘制框架,适合逐帧重绘自定义仪表。我们把混合模拟输出的二维速度场 u(x,y)、v(x,y) 采样到极坐标网格,再映射为仪表盘的半径与角度偏移。流量计外壳用 CGContextStrokeEllipse 画环,刻度线用旋转变换批量绘制。
湍流精细结构的可视化依赖渐变与半透明叠加。对 DNS 子域返回的高频速度扰动,我们用 CGGradient 按涡量大小着色:正涡量红、负涡量蓝。由于每帧都要重建路径,应避免在 draw 方法里做内存分配,推荐用 CGMutablePath 复用。示例绘制核心如下:
func drawTurbine(ctx: CGContext, field: VelocityField) {
ctx.saveGState()
let center = CGPoint(x: 200, y: 200)
// 画外环
ctx.setLineWidth(4.0)
ctx.strokeEllipse(in: CGRect(x: 50, y: 50, width: 300, height: 300))
// 画流速路径
let path = CGMutablePath()
for i in 0..<field.count {
let p = field.sample(i)
let radius = 60 + p.speed * 120
let ang = p.angle
let x = center.x + radius * cos(ang)
let y = center.y + radius * sin(ang)
if i == 0 { path.move(to: CGPoint(x: x, y: y)) }
else { path.addLine(to: CGPoint(x: x, y: y)) }
}
ctx.addPath(path)
ctx.setStrokeColor(UIColor.cyan.cgColor)
ctx.strokePath()
ctx.restoreGState()
}
在真机调试时发现,若把 DNS 子域分辨率设到 128x128 以上,Core Graphics 的离屏渲染会拖慢主线程。解决办法是把流场计算放到 Background 线程,用 DispatchQueue 算完再切回主线程只做绘制。同时开启 shouldRasterize 缓存静态刻度层,只让流体层动态刷新,六十帧可以稳定达成。
亚格子模型对可视化配色与性能的影响
很多开发者忽略了一点:亚格子应力项虽然不是直接画出来的,却改变了速度场的统计特征,进而影响配色映射的阈值。我们在仪表盘上用颜色表示湍流强度,如果亚格子模型把高能区过度耗散,颜色就会集中在低端,用户看不到大涡破碎的过程。因此可视化模块应读取模型输出的亚格子动能项,动态缩放色阶。
具体做法是维护一个滑动窗口的最大涡量值,每帧用 CGFloat 归一化后再传给 CGColor 生成函数。这样即使模拟参数变化,仪表盘也不会突然变暗或爆白。下面的代码展示动态色阶计算:
func colorForVorticity(v: Double, maxV: Double) -> CGColor {
let norm = min(1.0, abs(v) / maxV)
if v >= 0 {
return UIColor(red: CGFloat(norm), green: 0, blue: 0, alpha: 1).cgColor
} else {
return UIColor(red: 0, green: 0, blue: CGFloat(norm), alpha: 1).cgColor
}
}
从性能角度看,亚格子模型越简单,CPU 占用越低,留给 Core Graphics 的帧时间越多。我们对比过 Smagorinsky 与 WALE 模型,在 iPhone 13 上前者每步省约 0.8 毫秒,但 WALE 在近壁表现更好。如果仪表盘主要给现场工程师快速读数,建议用简化模型加后处理锐化;若用于教学演示,则可用复杂模型换清晰度。混合方法的价值,正在于让你按场景自由权衡数值与图形两端。
Core GraphicsiOS仪表盘大涡模拟修改时间:2026-08-21 13:25:31