燃烧仿真-主题047-不确定性量化方法
主题047:燃烧数值模拟中的不确定性量化
目录
1. 引言
1.1 不确定性量化的重要性
燃烧数值模拟在工程设计和科学研究中发挥着越来越重要的作用,但模拟结果往往存在不确定性:
- 模型不确定性:湍流模型、燃烧模型、辐射模型的简化假设
- 参数不确定性:边界条件、物性参数、化学反应速率
- 数值不确定性:网格离散、时间步长、收敛判据
**不确定性量化(UQ)**的目标:
- 识别和量化不确定性的来源
- 评估不确定性对结果的影响
- 提高模拟结果的可靠性和可信度
- 为决策提供风险评估依据
1.2 燃烧模拟中的典型不确定性
物理模型不确定性:
- 湍流-燃烧相互作用模型
- 详细反应机理的简化
- 辐射传热模型
输入参数不确定性:
- 燃料组分和热值波动
- 入口流速和温度测量误差
- 几何尺寸的制造公差
数值方法不确定性:
- 网格密度和类型
- 数值格式和格式参数
- 迭代收敛标准
1.3 不确定性量化方法概述
主要方法分类:
-
敏感性分析(SA):
- 局部敏感性分析
- 全局敏感性分析
- 筛选方法
-
不确定性传播(UP):
- 蒙特卡洛方法
- 多项式混沌展开
- 随机配点法
-
模型验证与确认(V&V):
- 代码验证
- 模型确认
- 不确定性量化
2. 不确定性来源与分类
2.1 认知不确定性 vs 偶然不确定性
2.1.1 认知不确定性(Epistemic)
定义:由于缺乏知识或信息不足导致的不确定性
特点:
- 可以通过更多研究减少
- 通常用区间或模糊数表示
- 主观性较强
燃烧模拟中的例子:
- 反应机理的缺失路径
- 湍流模型的适用性
- 边界条件的精确值
2.1.2 偶然不确定性(Aleatory)
定义:由于系统固有的随机性导致的不确定性
特点:
- 不可通过研究消除
- 通常用概率分布描述
- 客观存在
燃烧模拟中的例子:
- 燃料组分的自然波动
- 环境温度的随机变化
- 测量仪器的随机误差
2.2 不确定性分类框架
不确定性
├── 模型不确定性
│ ├── 模型形式不确定性
│ ├── 模型参数不确定性
│ └── 模型适用性不确定性
├── 输入不确定性
│ ├── 边界条件不确定性
│ ├── 初始条件不确定性
│ └── 物性参数不确定性
└── 数值不确定性
├── 离散化不确定性
├── 迭代不确定性
└── 舍入不确定性
2.3 燃烧模拟中的关键不确定参数
2.3.1 化学反应动力学参数
反应速率常数:
k = A ⋅ T n ⋅ exp ( − E a R T ) k = A \cdot T^n \cdot \exp\left(-\frac{E_a}{RT}\right) k=A⋅Tn⋅exp(−RTEa)
不确定性来源:
- 指前因子A:±20-50%
- 活化能Ea:±5-10%
- 温度指数n:±0.1-0.3
示例:甲烷燃烧关键反应
| 反应 | A (不确定性) | Ea (不确定性) |
|---|---|---|
| CH₄ + OH → CH₃ + H₂O | ±30% | ±5% |
| CH₃ + O₂ → CH₂O + OH | ±50% | ±10% |
| CO + OH → CO₂ + H | ±20% | ±3% |
2.3.2 湍流模型参数
k-ε模型参数:
| 参数 | 标准值 | 典型不确定性 |
|---|---|---|
| C_μ | 0.09 | ±10% |
| C_ε1 | 1.44 | ±5% |
| C_ε2 | 1.92 | ±5% |
| σ_k | 1.0 | ±10% |
| σ_ε | 1.3 | ±10% |
影响:
- 射流扩散角度变化:±15%
- 回流区长度变化:±20%
- 混合效率变化:±10%
2.3.3 边界条件不确定性
典型边界条件不确定性:
| 参数 | 测量精度 | 不确定性范围 |
|---|---|---|
| 入口流速 | ±1% FS | ±0.5-2% |
| 入口温度 | ±1°C | ±5-20K |
| 燃料流量 | ±0.5% | ±1-3% |
| 压力 | ±0.1% FS | ±100-500 Pa |
3. 概率统计基础
3.1 概率分布类型
3.1.1 常用连续分布
正态分布(Gaussian):
f ( x ) = 1 σ 2 π exp ( − ( x − μ ) 2 2 σ 2 ) f(x) = \frac{1}{\sigma\sqrt{2\pi}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right) f(x)=σ2π1exp(−2σ2(x−μ)2)
适用场景:
- 测量误差
- 制造公差
- 自然变异
对数正态分布:
f ( x ) = 1 x σ 2 π exp ( − ( ln x − μ ) 2 2 σ 2 ) f(x) = \frac{1}{x\sigma\sqrt{2\pi}} \exp\left(-\frac{(\ln x - \mu)^2}{2\sigma^2}\right) f(x)=xσ2π1exp(−2σ2(lnx−μ)2)
适用场景:
- 反应速率常数
- 颗粒尺寸分布
- 寿命数据
均匀分布:
f ( x ) = { 1 b − a a ≤ x ≤ b 0 其他 f(x) = \begin{cases} \frac{1}{b-a} & a \leq x \leq b \\ 0 & \text{其他} \end{cases} f(x)={b−a10a≤x≤b其他
适用场景:
- 缺乏数据时的保守估计
- 模型参数的先验分布
- 舍入误差
三角分布:
f ( x ) = { 2 ( x − a ) ( b − a ) ( c − a ) a ≤ x ≤ c 2 ( b − x ) ( b − a ) ( b − c ) c < x ≤ b 0 其他 f(x) = \begin{cases} \frac{2(x-a)}{(b-a)(c-a)} & a \leq x \leq c \\ \frac{2(b-x)}{(b-a)(b-c)} & c < x \leq b \\ 0 & \text{其他} \end{cases} f(x)=⎩ ⎨ ⎧(b−a)(c−a)2(x−a)(b−a)(b−c)2(b−x)0a≤x≤cc<x≤b其他
适用场景:
- 专家判断
- 有限数据
- 保守估计
3.1.2 分布选择指南
| 数据特征 | 推荐分布 | 理由 |
|---|---|---|
| 对称、无界 | 正态分布 | 中心极限定理 |
| 正、右偏 | 对数正态 | 物理约束 |
| 有明确范围 | 均匀/三角 | 最大熵原理 |
| 极端值重要 | 威布尔/极值 | 尾部特性 |
3.2 统计量与置信区间
3.2.1 描述性统计量
集中趋势:
- 均值(Mean): μ = 1 N ∑ i = 1 N x i \mu = \frac{1}{N}\sum_{i=1}^N x_i μ=N1∑i=1Nxi
- 中位数(Median):排序后中间值
- 众数(Mode):出现频率最高值
离散程度:
- 标准差: σ = 1 N ∑ i = 1 N ( x i − μ ) 2 \sigma = \sqrt{\frac{1}{N}\sum_{i=1}^N (x_i - \mu)^2} σ=N1∑i=1N(xi−μ)2
- 变异系数: C V = σ μ × 100 % CV = \frac{\sigma}{\mu} \times 100\% CV=μσ×100%
- 四分位距: I Q R = Q 3 − Q 1 IQR = Q_3 - Q_1 IQR=Q3−Q1
形状特征:
- 偏度: γ 1 = 1 N ∑ i = 1 N ( x i − μ σ ) 3 \gamma_1 = \frac{1}{N}\sum_{i=1}^N \left(\frac{x_i-\mu}{\sigma}\right)^3 γ1=N1∑i=1N(σxi−μ)3
- 峰度: γ 2 = 1 N ∑ i = 1 N ( x i − μ σ ) 4 − 3 \gamma_2 = \frac{1}{N}\sum_{i=1}^N \left(\frac{x_i-\mu}{\sigma}\right)^4 - 3 γ2=N1∑i=1N(σxi−μ)4−3
3.2.2 置信区间
正态分布的置信区间:
C I = x ˉ ± z α / 2 ⋅ s n CI = \bar{x} \pm z_{\alpha/2} \cdot \frac{s}{\sqrt{n}} CI=xˉ±zα/2⋅ns
常用置信水平:
| 置信水平 | z值 |
|---|---|
| 90% | 1.645 |
| 95% | 1.96 |
| 99% | 2.576 |
Bootstrap置信区间:
- 从原始样本中有放回地抽取n个样本
- 计算统计量(如均值)
- 重复B次(通常B=1000-10000)
- 取统计量的分位数作为置信区间
3.3 假设检验
3.3.1 参数检验
t检验(均值比较):
t = x ˉ 1 − x ˉ 2 s p 1 n 1 + 1 n 2 t = \frac{\bar{x}_1 - \bar{x}_2}{s_p \sqrt{\frac{1}{n_1} + \frac{1}{n_2}}} t=spn11+n21xˉ1−xˉ2
F检验(方差比较):
F = s 1 2 s 2 2 F = \frac{s_1^2}{s_2^2} F=s22s12
适用条件:
- 数据近似正态分布
- 样本独立
- 方差齐性(t检验)
3.3.2 非参数检验
Kolmogorov-Smirnov检验:
D = max x ∣ F n ( x ) − F ( x ) ∣ D = \max_x |F_n(x) - F(x)| D=xmax∣Fn(x)−F(x)∣
Mann-Whitney U检验:
- 不假设分布形式
- 比较两个独立样本
- 基于秩次
4. 敏感性分析方法
4.1 局部敏感性分析
4.1.1 单因素扰动法
基本原理:
S i = ∂ y ∂ x i ≈ y ( x i + Δ x i ) − y ( x i ) Δ x i S_i = \frac{\partial y}{\partial x_i} \approx \frac{y(x_i + \Delta x_i) - y(x_i)}{\Delta x_i} Si=∂xi∂y≈Δxiy(xi+Δxi)−y(xi)
无量纲化敏感性系数:
S i ∗ = ∂ y / y ∂ x i / x i = x i y ⋅ ∂ y ∂ x i S_i^* = \frac{\partial y / y}{\partial x_i / x_i} = \frac{x_i}{y} \cdot \frac{\partial y}{\partial x_i} Si∗=∂xi/xi∂y/y=yxi⋅∂xi∂y
实施步骤:
- 选择基准点(通常是 nominal 值)
- 对每个参数进行小扰动(±1-5%)
- 计算输出变化
- 计算敏感性系数
优缺点:
- 优点:计算量小,易于实现
- 缺点:仅适用于线性或弱非线性系统,忽略参数间交互作用
4.1.2 有限差分法
前向差分:
∂ y ∂ x i ≈ y ( x i + h ) − y ( x i ) h \frac{\partial y}{\partial x_i} \approx \frac{y(x_i + h) - y(x_i)}{h} ∂xi∂y≈hy(xi+h)−y(xi)
中心差分:
∂ y ∂ x i ≈ y ( x i + h ) − y ( x i − h ) 2 h \frac{\partial y}{\partial x_i} \approx \frac{y(x_i + h) - y(x_i - h)}{2h} ∂xi∂y≈2hy(xi+h)−y(xi−h)
步长选择:
- 太大:截断误差增大
- 太小:舍入误差增大
- 经验法则: h ≈ ϵ m a c h ⋅ x i h \approx \sqrt{\epsilon_{mach}} \cdot x_i h≈ϵmach⋅xi
4.2 全局敏感性分析
4.2.1 Morris筛选法
基本思想:
- 在参数空间内随机采样
- 计算基本效应(Elementary Effects)
- 通过统计量识别重要参数
基本效应计算:
E E i = y ( x 1 , . . . , x i + Δ , . . . , x k ) − y ( x 1 , . . . , x i , . . . , x k ) Δ EE_i = \frac{y(x_1, ..., x_i + \Delta, ..., x_k) - y(x_1, ..., x_i, ..., x_k)}{\Delta} EEi=Δy(x1,...,xi+Δ,...,xk)−y(x1,...,xi,...,xk)
统计量:
- 均值 μ \mu μ:参数的总体影响
- 标准差 σ \sigma σ:参数的非线性程度和交互作用
参数分类:
| 类型 | 特征 | 处理策略 |
|---|---|---|
| 不重要 | 低 μ \mu μ,低 σ \sigma σ | 固定为名义值 |
| 线性重要 | 高 μ \mu μ,低 σ \sigma σ | 精确建模 |
| 非线性重要 | 高 μ \mu μ,高 σ \sigma σ | 重点研究 |
| 交互作用 | 低 μ \mu μ,高 σ \sigma σ | 考虑交互项 |
4.2.2 Sobol敏感性分析
方差分解:
V ( Y ) = ∑ i V i + ∑ i < j V i j + . . . + V 12... k V(Y) = \sum_i V_i + \sum_{i<j} V_{ij} + ... + V_{12...k} V(Y)=i∑Vi+i<j∑Vij+...+V12...k
一阶敏感性指数:
S i = V i V ( Y ) = V X i ( E X ∼ i ( Y ∣ X i ) ) V ( Y ) S_i = \frac{V_i}{V(Y)} = \frac{V_{X_i}(E_{X_{\sim i}}(Y|X_i))}{V(Y)} Si=V(Y)Vi=V(Y)VXi(EX∼i(Y∣Xi))
总敏感性指数:
S T i = E X ∼ i ( V X i ( Y ∣ X ∼ i ) ) V ( Y ) = 1 − V X ∼ i ( E X i ( Y ∣ X ∼ i ) ) V ( Y ) S_{Ti} = \frac{E_{X_{\sim i}}(V_{X_i}(Y|X_{\sim i}))}{V(Y)} = 1 - \frac{V_{X_{\sim i}}(E_{X_i}(Y|X_{\sim i}))}{V(Y)} STi=V(Y)EX∼i(VXi(Y∣X∼i))=1−V(Y)VX∼i(EXi(Y∣X∼i))
解释:
- S i S_i Si:参数 X i X_i Xi的单独贡献
- S T i S_{Ti} STi:参数 X i X_i Xi的总贡献(包括交互作用)
- S T i − S i S_{Ti} - S_i STi−Si:参数 X i X_i Xi与其他参数的交互作用
计算方法:
- 蒙特卡洛积分
- 准蒙特卡洛(Sobol序列、Halton序列)
- 多项式混沌展开
4.2.3 FAST方法
Fourier Amplitude Sensitivity Test
原理:
- 将参数映射为频率
- 通过傅里叶分析识别各参数的贡献
- 每个参数分配不同特征频率
优点:
- 计算效率高于Sobol方法
- 可以同时计算一阶和总敏感性指数
4.3 敏感性分析在燃烧模拟中的应用
4.3.1 反应机理简化
目标:识别对目标量影响最大的基元反应
步骤:
- 定义目标量(如点火延迟时间、火焰速度)
- 对所有反应速率常数进行敏感性分析
- 识别高敏感性反应
- 保留关键反应,简化次要反应
示例结果:
| 反应 | 敏感性系数 | 重要性 |
|---|---|---|
| H + O₂ → OH + O | 0.85 | 关键 |
| CH₄ + OH → CH₃ + H₂O | 0.62 | 重要 |
| CH₃ + O → CH₂O + H | 0.15 | 次要 |
| … | <0.1 | 可简化 |
4.3.2 模型参数标定
目标:确定模型参数的最优值和不确定性范围
方法:
- 选择待标定参数
- 定义目标函数(模拟值与实验值的偏差)
- 进行敏感性分析,识别关键参数
- 使用优化算法调整关键参数
- 量化参数不确定性
5. 不确定性传播方法
5.1 蒙特卡洛方法
5.1.1 基本蒙特卡洛
算法流程:
1. 定义输入参数的概率分布
2. For i = 1 to N:
a. 从输入分布中随机采样
b. 运行模拟计算
c. 记录输出结果
3. 统计分析输出结果
样本量确定:
对于95%置信水平、5%相对误差:
N = ( z α / 2 ⋅ C V ϵ ) 2 ≈ ( 1.96 ⋅ C V 0.05 ) 2 N = \left(\frac{z_{\alpha/2} \cdot CV}{\epsilon}\right)^2 \approx \left(\frac{1.96 \cdot CV}{0.05}\right)^2 N=(ϵzα/2⋅CV)2≈(0.051.96⋅CV)2
典型样本量:
- 低维问题(k<10):10³-10⁴
- 中维问题(10<k<50):10⁴-10⁵
- 高维问题(k>50):10⁵-10⁶
5.1.2 方差缩减技术
拉丁超立方采样(LHS):
- 将每个参数的范围分成N个等概率区间
- 在每个区间中随机采样一个点
- 组合成N个样本点
优点:
- 比纯随机采样更均匀地覆盖参数空间
- 可以用更少的样本达到相同的精度
- 通常可以减少10-50%的样本量
重要性采样:
E [ g ( X ) ] = ∫ g ( x ) f ( x ) d x = ∫ g ( x ) f ( x ) h ( x ) h ( x ) d x E[g(X)] = \int g(x) f(x) dx = \int g(x) \frac{f(x)}{h(x)} h(x) dx E[g(X)]=∫g(x)f(x)dx=∫g(x)h(x)f(x)h(x)dx
适用场景:
- 小概率事件估计
- 尾部特性分析
- 失效概率计算
5.2 谱方法
5.2.1 多项式混沌展开(PCE)
基本思想:
将随机输出表示为随机输入的正交多项式展开:
Y ( ξ ) = ∑ α c α Ψ α ( ξ ) Y(\xi) = \sum_{\alpha} c_{\alpha} \Psi_{\alpha}(\xi) Y(ξ)=α∑cαΨα(ξ)
其中:
- ξ \xi ξ:标准随机变量
- Ψ α \Psi_{\alpha} Ψα:正交多项式基函数
- c α c_{\alpha} cα:展开系数
多项式选择:
| 输入分布 | 正交多项式 | 权重函数 |
|---|---|---|
| 正态分布 | Hermite | e − x 2 / 2 e^{-x^2/2} e−x2/2 |
| 均匀分布 | Legendre | 1 |
| 伽马分布 | Laguerre | x α e − x x^{\alpha}e^{-x} xαe−x |
| 贝塔分布 | Jacobi | ( 1 − x ) α ( 1 + x ) β (1-x)^{\alpha}(1+x)^{\beta} (1−x)α(1+x)β |
系数计算:
投影法:
c α = ⟨ Y , Ψ α ⟩ ⟨ Ψ α , Ψ α ⟩ = E [ Y Ψ α ] E [ Ψ α 2 ] c_{\alpha} = \frac{\langle Y, \Psi_{\alpha} \rangle}{\langle \Psi_{\alpha}, \Psi_{\alpha} \rangle} = \frac{E[Y\Psi_{\alpha}]}{E[\Psi_{\alpha}^2]} cα=⟨Ψα,Ψα⟩⟨Y,Ψα⟩=E[Ψα2]E[YΨα]
回归法:
- 在配置点上计算输出
- 使用最小二乘法拟合系数
5.2.2 随机配点法
基本思想:
- 在精心选择的配点上求解确定性问题
- 使用插值或回归构造响应面
- 基于响应面进行统计分析
配点选择:
- 全因子设计(低维)
- 稀疏网格(中维)
- 自适应配点(高维)
优点:
- 可以使用现有的确定性求解器
- 非侵入式方法
- 适用于复杂模型
5.3 矩方法
5.3.1 泰勒展开法
一阶近似:
Y ≈ Y ( μ X ) + ∑ i = 1 k ∂ Y ∂ X i ( X i − μ X i ) Y \approx Y(\mu_X) + \sum_{i=1}^k \frac{\partial Y}{\partial X_i}(X_i - \mu_{X_i}) Y≈Y(μX)+i=1∑k∂Xi∂Y(Xi−μXi)
均值:
μ Y ≈ Y ( μ X ) \mu_Y \approx Y(\mu_X) μY≈Y(μX)
方差:
σ Y 2 ≈ ∑ i = 1 k ( ∂ Y ∂ X i ) 2 σ X i 2 \sigma_Y^2 \approx \sum_{i=1}^k \left(\frac{\partial Y}{\partial X_i}\right)^2 \sigma_{X_i}^2 σY2≈i=1∑k(∂Xi∂Y)2σXi2
适用条件:
- 输入不确定性小
- 系统接近线性
- 快速估计
5.3.2 点估计法
Rosenblueth方法:
对于k个参数,需要计算2^k个点:
Y ± = Y ( μ X 1 ± σ X 1 , . . . , μ X k ± σ X k ) Y_{\pm} = Y(\mu_{X_1} \pm \sigma_{X_1}, ..., \mu_{X_k} \pm \sigma_{X_k}) Y±=Y(μX1±σX1,...,μXk±σXk)
均值和方差:
μ Y = 1 2 k ∑ Y ± \mu_Y = \frac{1}{2^k} \sum Y_{\pm} μY=2k1∑Y±
σ Y 2 = 1 2 k ∑ ( Y ± − μ Y ) 2 \sigma_Y^2 = \frac{1}{2^k} \sum (Y_{\pm} - \mu_Y)^2 σY2=2k1∑(Y±−μY)2
改进方法:
- Harr方法
- 改进Rosenblueth方法
- 仅适用于低维问题
6. Python仿真实现
6.1 概率分布与采样仿真
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from scipy import stats
print("=" * 70)
print("主题047:不确定性量化方法 - Python仿真")
print("=" * 70)
# ============================================================================
# 实验1: 概率分布与采样方法
# ============================================================================
print("\n" + "=" * 70)
print("实验1: 概率分布与采样方法")
print("=" * 70)
# 设置随机种子以保证可重复性
np.random.seed(42)
# 定义燃烧模拟中常见的概率分布
print("\n常见概率分布定义:")
print("-" * 50)
# 1. 正态分布 - 测量误差
temp_mean = 300 # K
temp_std = 10 # K
temp_dist = stats.norm(temp_mean, temp_std)
print(f"入口温度: 正态分布 N({temp_mean}, {temp_std}²)")
# 2. 对数正态分布 - 反应速率常数
A_mean = 1e10
A_sigma = 0.5 # 对数标准差
A_dist = stats.lognorm(s=A_sigma, scale=A_mean)
print(f"指前因子: 对数正态分布 LN({A_mean}, {A_sigma}²)")
# 3. 均匀分布 - 缺乏精确数据时
phi_low = 0.8
phi_high = 1.2
phi_dist = stats.uniform(phi_low, phi_high - phi_low)
print(f"当量比: 均匀分布 U({phi_low}, {phi_high})")
# 4. 三角分布 - 专家判断
pressure_min = 100000 # Pa
pressure_mode = 101325 # Pa
pressure_max = 102000 # Pa
pressure_dist = stats.triang(
c=(pressure_mode - pressure_min)/(pressure_max - pressure_min),
loc=pressure_min,
scale=pressure_max - pressure_min
)
print(f"环境压力: 三角分布 T({pressure_min}, {pressure_mode}, {pressure_max})")
# 生成样本
n_samples = 10000
temp_samples = temp_dist.rvs(n_samples)
A_samples = A_dist.rvs(n_samples)
phi_samples = phi_dist.rvs(n_samples)
pressure_samples = pressure_dist.rvs(n_samples)
print(f"\n生成样本统计 (n={n_samples}):")
print("-" * 50)
print(f"温度样本: 均值={np.mean(temp_samples):.2f}, 标准差={np.std(temp_samples):.2f}")
print(f"A因子样本: 均值={np.mean(A_samples):.2e}, 标准差={np.std(A_samples):.2e}")
print(f"当量比样本: 均值={np.mean(phi_samples):.3f}, 标准差={np.std(phi_samples):.3f}")
print(f"压力样本: 均值={np.mean(pressure_samples):.0f}, 标准差={np.std(pressure_samples):.0f}")
# 绘制分布
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 温度分布
axes[0, 0].hist(temp_samples, bins=50, density=True, alpha=0.7, color='blue', edgecolor='black')
x_temp = np.linspace(temp_mean - 4*temp_std, temp_mean + 4*temp_std, 100)
axes[0, 0].plot(x_temp, temp_dist.pdf(x_temp), 'r-', linewidth=2, label='PDF')
axes[0, 0].axvline(temp_mean, color='g', linestyle='--', label=f'Mean={temp_mean}')
axes[0, 0].set_xlabel('Temperature (K)', fontsize=11)
axes[0, 0].set_ylabel('Probability Density', fontsize=11)
axes[0, 0].set_title('Normal Distribution: Inlet Temperature', fontsize=12)
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 对数正态分布
axes[0, 1].hist(A_samples, bins=50, density=True, alpha=0.7, color='green', edgecolor='black')
x_A = np.linspace(A_mean*0.1, A_mean*3, 100)
axes[0, 1].plot(x_A, A_dist.pdf(x_A), 'r-', linewidth=2, label='PDF')
axes[0, 1].axvline(A_mean, color='g', linestyle='--', label=f'Mean={A_mean:.0e}')
axes[0, 1].set_xlabel('Pre-exponential Factor', fontsize=11)
axes[0, 1].set_ylabel('Probability Density', fontsize=11)
axes[0, 1].set_title('Log-normal Distribution: Rate Constant', fontsize=12)
axes[0, 1].set_xscale('log')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)
# 均匀分布
axes[1, 0].hist(phi_samples, bins=50, density=True, alpha=0.7, color='orange', edgecolor='black')
x_phi = np.linspace(phi_low-0.1, phi_high+0.1, 100)
axes[1, 0].plot(x_phi, phi_dist.pdf(x_phi), 'r-', linewidth=2, label='PDF')
axes[1, 0].axvline((phi_low+phi_high)/2, color='g', linestyle='--', label=f'Mean={(phi_low+phi_high)/2}')
axes[1, 0].set_xlabel('Equivalence Ratio', fontsize=11)
axes[1, 0].set_ylabel('Probability Density', fontsize=11)
axes[1, 0].set_title('Uniform Distribution: Equivalence Ratio', fontsize=12)
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)
# 三角分布
axes[1, 1].hist(pressure_samples, bins=50, density=True, alpha=0.7, color='purple', edgecolor='black')
x_pressure = np.linspace(pressure_min-500, pressure_max+500, 100)
axes[1, 1].plot(x_pressure, pressure_dist.pdf(x_pressure), 'r-', linewidth=2, label='PDF')
axes[1, 1].axvline(pressure_mode, color='g', linestyle='--', label=f'Mode={pressure_mode}')
axes[1, 1].set_xlabel('Pressure (Pa)', fontsize=11)
axes[1, 1].set_ylabel('Probability Density', fontsize=11)
axes[1, 1].set_title('Triangular Distribution: Pressure', fontsize=12)
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('exp1_probability_distributions.png', dpi=150, bbox_inches='tight')
print("\n结果已保存至: exp1_probability_distributions.png")
plt.close()
6.2 敏感性分析仿真
# ============================================================================
# 实验2: 敏感性分析
# ============================================================================
print("\n" + "=" * 70)
print("实验2: 敏感性分析")
print("=" * 70)
def ignition_delay(T, P, phi, Ea=50000, A=1e10):
"""
简化的点火延迟时间模型
参数:
T: 温度 (K)
P: 压力 (Pa)
phi: 当量比
Ea: 活化能 (J/mol)
A: 指前因子 (1/s)
返回:
点火延迟时间 (s)
"""
R = 8.314 # J/(mol·K)
# 简化Arrhenius模型
tau = (1 / A) * np.exp(Ea / (R * T)) * (1e5 / P)**0.5 * (1 + abs(phi - 1))
return tau
def flame_speed(T, P, phi, alpha=1.5, beta=0.3):
"""
简化的层流火焰速度模型
参数:
T: 温度 (K)
P: 压力 (Pa)
phi: 当量比
alpha, beta: 模型参数
返回:
火焰速度 (m/s)
"""
# 简化模型
S_l = 0.4 * (T / 300)**alpha * (P / 1e5)**(-beta) * np.exp(-2*(phi - 1.05)**2)
return S_l
# 局部敏感性分析
print("\n局部敏感性分析:")
print("-" * 50)
# 基准值
T0, P0, phi0 = 300, 101325, 1.0
h = 0.01 # 扰动幅度
# 点火延迟时间的敏感性
tau0 = ignition_delay(T0, P0, phi0)
# 温度敏感性
tau_T_plus = ignition_delay(T0*(1+h), P0, phi0)
tau_T_minus = ignition_delay(T0*(1-h), P0, phi0)
S_T = (tau_T_plus - tau_T_minus) / (2*h*T0) * T0 / tau0
# 压力敏感性
tau_P_plus = ignition_delay(T0, P0*(1+h), phi0)
tau_P_minus = ignition_delay(T0, P0*(1-h), phi0)
S_P = (tau_P_plus - tau_P_minus) / (2*h*P0) * P0 / tau0
# 当量比敏感性
tau_phi_plus = ignition_delay(T0, P0, phi0*(1+h))
tau_phi_minus = ignition_delay(T0, P0, phi0*(1-h))
S_phi = (tau_phi_plus - tau_phi_minus) / (2*h*phi0) * phi0 / tau0
print(f"基准点火延迟时间: {tau0:.6f} s")
print(f"温度敏感性系数: {S_T:.3f}")
print(f"压力敏感性系数: {S_P:.3f}")
print(f"当量比敏感性系数: {S_phi:.3f}")
# 全局敏感性分析 - Morris方法简化版
print("\n全局敏感性分析 (Morris方法):")
print("-" * 50)
n_trajectories = 10
n_params = 3
delta = 0.1
param_names = ['Temperature', 'Pressure', 'Equivalence Ratio']
param_ranges = [(250, 350), (80000, 120000), (0.6, 1.4)]
EE_matrix = np.zeros((n_trajectories, n_params))
for t in range(n_trajectories):
# 随机起点
x_base = np.array([
np.random.uniform(param_ranges[i][0], param_ranges[i][1])
for i in range(n_params)
])
for i in range(n_params):
# 计算基本效应
x_plus = x_base.copy()
x_minus = x_base.copy()
param_range = param_ranges[i][1] - param_ranges[i][0]
x_plus[i] = min(x_base[i] + delta * param_range, param_ranges[i][1])
x_minus[i] = max(x_base[i] - delta * param_range, param_ranges[i][0])
y_plus = ignition_delay(x_plus[0], x_plus[1], x_plus[2])
y_minus = ignition_delay(x_minus[0], x_minus[1], x_minus[2])
EE_matrix[t, i] = (y_plus - y_minus) / (x_plus[i] - x_minus[i])
EE_matrix[t, i] *= x_base[i] / ignition_delay(x_base[0], x_base[1], x_base[2])
# 统计量
mu = np.mean(EE_matrix, axis=0)
sigma = np.std(EE_matrix, axis=0)
print("参数\t\t\t 均值(μ)\t 标准差(σ)")
print("-" * 50)
for i, name in enumerate(param_names):
print(f"{name:20s}\t{mu[i]:8.3f}\t{sigma[i]:8.3f}")
# 绘制敏感性分析结果
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 局部敏感性
params = ['Temperature', 'Pressure', 'Equivalence Ratio']
local_sens = [abs(S_T), abs(S_P), abs(S_phi)]
axes[0].bar(params, local_sens, color=['red', 'blue', 'green'], edgecolor='black')
axes[0].set_ylabel('Sensitivity Coefficient |S|', fontsize=11)
axes[0].set_title('Local Sensitivity Analysis', fontsize=12)
axes[0].grid(True, alpha=0.3, axis='y')
axes[0].tick_params(axis='x', rotation=15)
# Morris散点图
axes[1].scatter(mu, sigma, s=200, c=['red', 'blue', 'green'], alpha=0.7, edgecolors='black')
for i, name in enumerate(param_names):
axes[1].annotate(name[:4], (mu[i], sigma[i]), xytext=(5, 5),
textcoords='offset points', fontsize=10)
axes[1].axhline(y=0.1, color='gray', linestyle='--', alpha=0.5)
axes[1].axvline(x=0, color='gray', linestyle='--', alpha=0.5)
axes[1].set_xlabel('Mean (μ)', fontsize=11)
axes[1].set_ylabel('Standard Deviation (σ)', fontsize=11)
axes[1].set_title('Morris Sensitivity Analysis', fontsize=12)
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('exp2_sensitivity_analysis.png', dpi=150, bbox_inches='tight')
print("\n结果已保存至: exp2_sensitivity_analysis.png")
plt.close()
6.3 蒙特卡洛不确定性传播仿真
# ============================================================================
# 实验3: 蒙特卡洛不确定性传播
# ============================================================================
print("\n" + "=" * 70)
print("实验3: 蒙特卡洛不确定性传播")
print("=" * 70)
def combustion_model(T, P, phi, X_O2=0.21):
"""
简化的燃烧性能模型
返回多个输出量
"""
# 点火延迟时间
tau = ignition_delay(T, P, phi)
# 火焰速度
S_l = flame_speed(T, P, phi)
# 绝热火焰温度(简化计算)
T_ad = T + 2000 * phi * np.exp(-0.5*(phi-1)**2) * (P/1e5)**0.1
# 燃烧效率
eta = 0.95 * np.exp(-0.1*abs(phi-1)) * (T/300)**0.05
return tau, S_l, T_ad, eta
# 定义输入不确定性
print("\n输入参数不确定性:")
print("-" * 50)
# 温度: 正态分布 N(300, 15²)
T_dist = stats.norm(300, 15)
# 压力: 正态分布 N(101325, 2000²)
P_dist = stats.norm(101325, 2000)
# 当量比: 三角分布 T(0.8, 1.0, 1.2)
phi_dist = stats.triang(c=0.5, loc=0.8, scale=0.4)
# 氧气浓度: 均匀分布 U(0.19, 0.23)
XO2_dist = stats.uniform(0.19, 0.04)
print("温度: N(300, 15²) K")
print("压力: N(101325, 2000²) Pa")
print("当量比: Triangular(0.8, 1.0, 1.2)")
print("氧浓度: U(0.19, 0.23)")
# 蒙特卡洛模拟
n_mc = 5000
print(f"\n蒙特卡洛模拟 (n={n_mc}):")
print("-" * 50)
# 生成输入样本
T_samples = T_dist.rvs(n_mc)
P_samples = P_dist.rvs(n_mc)
phi_samples = phi_dist.rvs(n_mc)
XO2_samples = XO2_dist.rvs(n_mc)
# 计算输出
tau_results = []
Sl_results = []
Tad_results = []
eta_results = []
for i in range(n_mc):
tau, S_l, T_ad, eta = combustion_model(T_samples[i], P_samples[i], phi_samples[i], XO2_samples[i])
tau_results.append(tau)
Sl_results.append(S_l)
Tad_results.append(T_ad)
eta_results.append(eta)
tau_results = np.array(tau_results)
Sl_results = np.array(Sl_results)
Tad_results = np.array(Tad_results)
eta_results = np.array(eta_results)
# 统计分析
print("\n输出统计量:")
print("-" * 50)
print(f"{'输出量':<20s} {'均值':<12s} {'标准差':<12s} {'CV(%)':<8s}")
print("-" * 50)
print(f"{'点火延迟时间(s)':<20s} {np.mean(tau_results):<12.6f} {np.std(tau_results):<12.6f} {np.std(tau_results)/np.mean(tau_results)*100:<8.2f}")
print(f"{'火焰速度(m/s)':<20s} {np.mean(Sl_results):<12.4f} {np.std(Sl_results):<12.4f} {np.std(Sl_results)/np.mean(Sl_results)*100:<8.2f}")
print(f"{'绝热火焰温度(K)':<20s} {np.mean(Tad_results):<12.2f} {np.std(Tad_results):<12.2f} {np.std(Tad_results)/np.mean(Tad_results)*100:<8.2f}")
print(f"{'燃烧效率':<20s} {np.mean(eta_results):<12.4f} {np.std(eta_results):<12.4f} {np.std(eta_results)/np.mean(eta_results)*100:<8.2f}")
# 置信区间
print("\n95%置信区间:")
print("-" * 50)
print(f"点火延迟时间: [{np.percentile(tau_results, 2.5):.6f}, {np.percentile(tau_results, 97.5):.6f}] s")
print(f"火焰速度: [{np.percentile(Sl_results, 2.5):.4f}, {np.percentile(Sl_results, 97.5):.4f}] m/s")
print(f"绝热火焰温度: [{np.percentile(Tad_results, 2.5):.2f}, {np.percentile(Tad_results, 97.5):.2f}] K")
print(f"燃烧效率: [{np.percentile(eta_results, 2.5):.4f}, {np.percentile(eta_results, 97.5):.4f}]")
# 绘制结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 点火延迟时间
axes[0, 0].hist(tau_results, bins=50, density=True, alpha=0.7, color='blue', edgecolor='black')
axes[0, 0].axvline(np.mean(tau_results), color='r', linestyle='--', linewidth=2, label=f'Mean={np.mean(tau_results):.6f}')
axes[0, 0].axvline(np.percentile(tau_results, 2.5), color='g', linestyle=':', linewidth=2, label='95% CI')
axes[0, 0].axvline(np.percentile(tau_results, 97.5), color='g', linestyle=':', linewidth=2)
axes[0, 0].set_xlabel('Ignition Delay Time (s)', fontsize=11)
axes[0, 0].set_ylabel('Probability Density', fontsize=11)
axes[0, 0].set_title('Ignition Delay Time Distribution', fontsize=12)
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 火焰速度
axes[0, 1].hist(Sl_results, bins=50, density=True, alpha=0.7, color='green', edgecolor='black')
axes[0, 1].axvline(np.mean(Sl_results), color='r', linestyle='--', linewidth=2, label=f'Mean={np.mean(Sl_results):.4f}')
axes[0, 1].axvline(np.percentile(Sl_results, 2.5), color='g', linestyle=':', linewidth=2, label='95% CI')
axes[0, 1].axvline(np.percentile(Sl_results, 97.5), color='g', linestyle=':', linewidth=2)
axes[0, 1].set_xlabel('Flame Speed (m/s)', fontsize=11)
axes[0, 1].set_ylabel('Probability Density', fontsize=11)
axes[0, 1].set_title('Flame Speed Distribution', fontsize=12)
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)
# 绝热火焰温度
axes[1, 0].hist(Tad_results, bins=50, density=True, alpha=0.7, color='red', edgecolor='black')
axes[1, 0].axvline(np.mean(Tad_results), color='b', linestyle='--', linewidth=2, label=f'Mean={np.mean(Tad_results):.2f}')
axes[1, 0].axvline(np.percentile(Tad_results, 2.5), color='g', linestyle=':', linewidth=2, label='95% CI')
axes[1, 0].axvline(np.percentile(Tad_results, 97.5), color='g', linestyle=':', linewidth=2)
axes[1, 0].set_xlabel('Adiabatic Flame Temperature (K)', fontsize=11)
axes[1, 0].set_ylabel('Probability Density', fontsize=11)
axes[1, 0].set_title('Adiabatic Flame Temperature Distribution', fontsize=12)
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)
# 燃烧效率
axes[1, 1].hist(eta_results, bins=50, density=True, alpha=0.7, color='purple', edgecolor='black')
axes[1, 1].axvline(np.mean(eta_results), color='r', linestyle='--', linewidth=2, label=f'Mean={np.mean(eta_results):.4f}')
axes[1, 1].axvline(np.percentile(eta_results, 2.5), color='g', linestyle=':', linewidth=2, label='95% CI')
axes[1, 1].axvline(np.percentile(eta_results, 97.5), color='g', linestyle=':', linewidth=2)
axes[1, 1].set_xlabel('Combustion Efficiency', fontsize=11)
axes[1, 1].set_ylabel('Probability Density', fontsize=11)
axes[1, 1].set_title('Combustion Efficiency Distribution', fontsize=12)
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('exp3_monte_carlo.png', dpi=150, bbox_inches='tight')
print("\n结果已保存至: exp3_monte_carlo.png")
plt.close()
6.4 响应面与代理模型仿真
# ============================================================================
# 实验4: 响应面方法
# ============================================================================
print("\n" + "=" * 70)
print("实验4: 响应面方法")
print("=" * 70)
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
# 定义火焰速度的响应面
print("\n构建火焰速度响应面:")
print("-" * 50)
# 生成训练数据(使用LHS设计)
from pyDOE2 import lhs
n_train = 50
# 拉丁超立方采样
lhs_samples = lhs(2, samples=n_train)
# 将样本映射到参数空间
T_train = 250 + lhs_samples[:, 0] * 100 # 250-350 K
phi_train = 0.6 + lhs_samples[:, 1] * 0.8 # 0.6-1.4
# 计算训练输出
Sl_train = np.array([flame_speed(T, 101325, phi) for T, phi in zip(T_train, phi_train)])
# 添加噪声模拟实验误差
noise = np.random.normal(0, 0.02, len(Sl_train))
Sl_train_noisy = Sl_train + noise
# 构建多项式响应面
poly = PolynomialFeatures(degree=2)
X_train = np.column_stack([T_train, phi_train])
X_train_poly = poly.fit_transform(X_train)
# 拟合模型
model = LinearRegression()
model.fit(X_train_poly, Sl_train_noisy)
# 预测
Sl_pred = model.predict(X_train_poly)
print(f"响应面模型: 二阶多项式")
print(f"R² = {r2_score(Sl_train_noisy, Sl_pred):.4f}")
# 生成预测网格
T_grid = np.linspace(250, 350, 50)
phi_grid = np.linspace(0.6, 1.4, 50)
T_mesh, phi_mesh = np.meshgrid(T_grid, phi_grid)
# 响应面预测
X_grid = np.column_stack([T_mesh.ravel(), phi_mesh.ravel()])
X_grid_poly = poly.transform(X_grid)
Sl_mesh = model.predict(X_grid_poly).reshape(T_mesh.shape)
# 真实值
Sl_true = np.array([flame_speed(T, 101325, phi) for T, phi in zip(T_mesh.ravel(), phi_mesh.ravel())])
Sl_true_mesh = Sl_true.reshape(T_mesh.shape)
# 不确定性传播
print("\n使用响应面进行不确定性传播:")
print("-" * 50)
# 定义输入分布
T_dist_rsp = stats.norm(300, 15)
phi_dist_rsp = stats.triang(c=0.5, loc=0.8, scale=0.4)
# 蒙特卡洛(使用响应面)
n_rsp = 10000
T_samples_rsp = T_dist_rsp.rvs(n_rsp)
phi_samples_rsp = phi_dist_rsp.rvs(n_rsp)
X_samples = np.column_stack([T_samples_rsp, phi_samples_rsp])
X_samples_poly = poly.transform(X_samples)
Sl_samples_rsp = model.predict(X_samples_poly)
print(f"响应面MC结果:")
print(f" 均值: {np.mean(Sl_samples_rsp):.4f} m/s")
print(f" 标准差: {np.std(Sl_samples_rsp):.4f} m/s")
print(f" 95% CI: [{np.percentile(Sl_samples_rsp, 2.5):.4f}, {np.percentile(Sl_samples_rsp, 97.5):.4f}]")
# 与直接MC比较(少量样本)
n_direct = 500
T_direct = T_dist_rsp.rvs(n_direct)
phi_direct = phi_dist_rsp.rvs(n_direct)
Sl_direct = np.array([flame_speed(T, 101325, phi) for T, phi in zip(T_direct, phi_direct)])
print(f"\n直接MC结果 (n={n_direct}):")
print(f" 均值: {np.mean(Sl_direct):.4f} m/s")
print(f" 标准差: {np.std(Sl_direct):.4f} m/s")
print(f" 95% CI: [{np.percentile(Sl_direct, 2.5):.4f}, {np.percentile(Sl_direct, 97.5):.4f}]")
print(f"\n计算效率:")
print(f" 响应面MC: {n_rsp}次预测(几乎瞬时)")
print(f" 直接MC: {n_direct}次模拟(耗时)")
# 绘制结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 响应面3D图
ax1 = axes[0, 0]
contour1 = ax1.contourf(T_mesh, phi_mesh, Sl_mesh, levels=20, cmap='viridis')
ax1.scatter(T_train, phi_train, c='red', s=30, edgecolors='black', label='Training points')
ax1.set_xlabel('Temperature (K)', fontsize=11)
ax1.set_ylabel('Equivalence Ratio', fontsize=11)
ax1.set_title('Response Surface: Flame Speed', fontsize=12)
plt.colorbar(contour1, ax=ax1, label='Flame Speed (m/s)')
ax1.legend()
# 真实值对比
ax2 = axes[0, 1]
contour2 = ax2.contourf(T_mesh, phi_mesh, Sl_true_mesh, levels=20, cmap='viridis')
ax2.set_xlabel('Temperature (K)', fontsize=11)
ax2.set_ylabel('Equivalence Ratio', fontsize=11)
ax2.set_title('True Model: Flame Speed', fontsize=12)
plt.colorbar(contour2, ax=ax2, label='Flame Speed (m/s)')
# 残差图
ax3 = axes[1, 0]
residuals = Sl_train_noisy - Sl_pred
ax3.scatter(Sl_pred, residuals, alpha=0.6, edgecolors='black')
ax3.axhline(y=0, color='r', linestyle='--')
ax3.set_xlabel('Predicted Values', fontsize=11)
ax3.set_ylabel('Residuals', fontsize=11)
ax3.set_title('Residual Plot', fontsize=12)
ax3.grid(True, alpha=0.3)
# 不确定性传播结果对比
ax4 = axes[1, 1]
ax4.hist(Sl_samples_rsp, bins=50, density=True, alpha=0.5, color='blue',
label=f'RSM (n={n_rsp})', edgecolor='black')
ax4.hist(Sl_direct, bins=30, density=True, alpha=0.5, color='red',
label=f'Direct (n={n_direct})', edgecolor='black')
ax4.set_xlabel('Flame Speed (m/s)', fontsize=11)
ax4.set_ylabel('Probability Density', fontsize=11)
ax4.set_title('Uncertainty Propagation Comparison', fontsize=12)
ax4.legend()
ax4.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('exp4_response_surface.png', dpi=150, bbox_inches='tight')
print("\n结果已保存至: exp4_response_surface.png")
plt.close()
print("\n" + "=" * 70)
print("所有实验完成!")
print("=" * 70)





AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)