news 2026/9/11 22:51:15

两阶段鲁棒优化解决微网电源容量配置的完整建模与求解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
两阶段鲁棒优化解决微网电源容量配置的完整建模与求解

简介:面向微电网规划研究人员与电气工程专业学生,这份资源针对风、光、储、燃气轮机联合容量配置问题,构建了考虑不确定性的两阶段鲁棒优化模型:一阶段决策储能与风光装机容量,二阶段优化典型日下实际出力,并采用列与约束生成(CCG)算法迭代求解。包内共19个文件,约3.76MB,以MATLAB脚本(m文件)为核心,包含主程序、MP/SP子问题及CCG实现;6份docx文档详解两阶段鲁棒构建与模型求解过程,便于对照阅读;另有四个典型日数据表格、矩阵推导图片、参考论文及caj文献,辅助理解算法细节。目前已有1328人学习,适合需要复现微网两阶段鲁棒规划代码、撰写论文或完成课程设计的读者。

1. 两阶段鲁棒优化算法解决微网电源容量配置问题的完整思路

做微网规划的人,迟早会在两种失败的方案之间来回挣扎:按最保守的负荷与风光出力去配置容量,结果是设备闲置率居高不下,项目经济性被初始投资压死;按典型日平均出力去配置,一到连续阴天或极端低温,系统又得靠外购电和切负荷来保底。电源容量配置本质上是“先决定买哪些设备、再在不确定出力下决定怎么运行”的顺序决策问题,两阶段鲁棒优化算法恰好把这种顺序决策结构化:第一阶段只做容量决策,第二阶段在所有可能的风光出力序列下做最省钱的运行调度,优化目标是在最坏情况下的年度总成本最小。这个思路在微网规划场景中既符合工程直觉,又能被分解算法稳定求解,是目前园区微网、海岛微网和企业微网容量配置里最常见的建模方式之一。接下来按建模、求解、参数整定、结果验证的路径展开,每一部分都会给出可直接复现的公式、代码或排查思路。

2. 微网电源容量配置的两阶段鲁棒优化建模

2.1 容量配置模型中的决策变量与不确定性来源

微网电源容量配置要确定的决策变量通常是:光伏阵列的装机容量(kWp)、风电的装机容量(kW)、储能系统的额定能量与额定功率(kWh/kW),有时候还会加入柴油发电机台数或燃气轮机的单机容量。这些变量一旦确定,在项目生命周期内基本不可调整,属于典型的第一阶段决策。而第二阶段决策则是未来每个调度时段内的出力分配:储能何时充电、何时放电、联络线交换功率多大、是否需要切负荷。风光出力和负荷需求都是不确定参数,它们的时序序列直接影响到第二阶段调度的可行性和经济性。

如果用确定性优化做容量配置,常见做法是把全年 8760 小时压缩成几个典型日再乘以对应天数。这种做法在平稳负荷场景下可以接受,但会丢掉小时级序列的连续性:无法表达连续两天阴雨导致光伏出力持续偏低、午峰与晚峰叠加等场景,也没有办法量化储能 SOC 在极端序列下的累积效应。两阶段鲁棒优化的价值正在这里:它用一个数学意义上严格的 max-min 结构,在给定的不确定集里寻找“最难受”的一组时序场景,并保证容量配置在该场景下仍然可运行且运行成本不失控。

两阶段鲁棒容量配置模型的标准形式是 min-max-min 三层结构。第一步决策变量是容量配置向量 $x$,第二阶段是在给定 $x$ 和不确定参数 $u$ 下的运行调度 $y$。用紧凑形式表达为:

$$\min_{x \in X} ; c(x) + \max_{u \in U} \min_{y \in F(x,u)} ; b(x,u,y)$$

其中 $c(x)$ 是投资成本的年化值,$b$ 是运行成本与惩罚成本之和。$U$ 是不确定集,$F(x,u)$ 是固定 $x$ 和 $u$ 后第二阶段运行问题的可行域。这里需要特别强调 $u$ 是一个时序向量,而不是若干个独立标量;$\max_{u \in U}$ 寻找的不只是某一时刻的极端出力,而是整段调度周期里让系统调节能力最受挤压的一组出力曲线。

第二阶段运行约束包含:每个时段的功率平衡约束、储能容量与充放电功率上下限、储能 SOC 跨时段递推、机组爬坡约束、联络线交换功率限制、弃风弃光量非负约束等。由于 SOC 递推是跨时段的线性方程,第二阶段问题即使在其他部分都是单时段约束,整体上仍然是一个带时间耦合结构的线性规划。这也是容量配置鲁棒优化区别于“仅做单时刻最优潮流”的鲁棒扩展的关键点。后面对偶变换若漏掉 SOC 递推对应的对偶变量,求出来的最坏场景会天然偏乐观。

2.2 不确定集设计:盒式、预算约束与多面体扩展

不确定集 $U$ 的构造直接决定鲁棒模型的保守程度和求解难度。盒式不确定集是最原始的形式,把每个时段的光伏出力或负荷限制在区间 $[\bar{u}_t - \hat{u}_t, \bar{u}_t + \hat{u}_t]$ 内。优点是代码简单、物理含义直观,缺点是假设所有时段同时达到最坏情况,这在真实气象过程中几乎不可能发生,所得容量配置往往过度投资。

工程上更常用的是带预算约束的盒式集合,记 $u_t = \bar{u}_t + \delta_t \hat{u}_t$,并要求偏差量满足:

$$U = \left{ \delta_t \in \mathbb{R}, ; |\delta_t| \le 1, ; \sum_{t=1}^T |\delta_t| \le \Gamma \right}$$

参数 $\Gamma$ 是不确定预算,$\Gamma=0$ 对应确定性模型,$\Gamma=T$ 退化为全盒式。它用一条线性不等式就实现了对总体偏离规模的限制,且不破坏线性模型的对偶结构,因此成为目前微网容量配置中使用频率最高的不确定集。$\Gamma$ 的具体取值没有放之四海而皆准的公式,一般先按 $T/4$ 到 $T/3$ 设定,然后通过蒙特卡洛模拟或历史数据的分位数来校正。比如一个 24 时段调度模型,$\Gamma$ 通常取 6~8,如果历史数据里连续阴雨的最大时长更大,就要相应调高。

如果风光之间、负荷之间存在时间相关性,还可以采用多面体扩展形式,比如加入相邻时段偏移量的差分约束,或限制持续阴雨的最大天数。这类不确定集的刻画更精细,但第二阶段对偶模型的系数矩阵会更稠密,求解耗时明显上升。实际工程判断时,先跑一遍预算约束模型,若发现最坏场景几乎总集中在某几个连续时段,说明时序相关不可忽略,再升级到带差分约束的多面体集。

不确定集类型保守程度对偶模型复杂度适用场景
全盒式最高保供要求极高的离网场景
盒式+预算约束中等工商业并网微网、园区微网
多面体+时序差分较低中等高光伏渗透、多日连续阴雨地区

2.3 用 Pyomo 定义带预算约束的不确定集

在具体代码实现中,我习惯用 Pyomo 作为建模语言,求解器根据授权选择 Gurobi 或 CBC。先定义不确定参数 $u$ 与偏差变量 $\delta$,再施加预算约束。以下代码把光伏出力的不确定集建模成预算约束形式:

import pyomo.environ as pyo def build_uncertainty_set(model, T, p_mean, p_dev, Gamma): # p_mean: 预测出力序列, p_dev: 允许偏差幅度, Gamma: 不确定预算 model.delta = pyo.Var(range(T), bounds=(-1, 1)) model.u_pv = pyo.Var(range(T)) # 预算约束:所有时段绝对偏差之和不超过 Gamma def budget_rule(m): return sum(abs(m.delta[t]) for t in range(T)) <= Gamma model.budget_constr = pyo.Constraint(rule=budget_rule) # 实际出力 = 预测均值 + 偏差比例 * 偏差幅度 def link_rule(m, t): return m.u_pv[t] == p_mean[t] + m.delta[t] * p_dev[t] model.u_link_constr = pyo.Constraint(range(T), rule=link_rule)

Pyomo 会把abs(m.delta[t])自动线性化,不需要手动引入辅助变量和额外约束。p_dev一般取预测均值的 0.15~0.3,具体数值来自历史预测误差的分位数。这里有一点容易混淆:$\Gamma$ 的单位是“时段偏移量的总计数”,而不是“最多允许多少个时段发生偏移”的整数阈值,因为 $\delta_t$ 可以是连续的。这样模型保持了线性规划性质,子问题仍然可以用对偶方式求解。

2.4 完整两阶段鲁棒容量配置模型的目标与约束

将决策变量、不确定集和运行约束组合到一起,容量配置问题可以写成如下完整形式。第一阶段目标函数为投资成本,第二阶段目标函数包括运行维护成本、向上级电网购电成本和弃风弃光惩罚:

$$\min_{x} ; C_{inv} + \max_{u \in U} \min_{y} ; \sum_{t=1}^T \left( c_{om} y_t + c_{buy} p^{buy}t + c{curt} p^{curt}_t \right)$$

约束方面,第一阶段包括各电源容量的上下限、总投资预算上限,第二阶段包括功率平衡、储能 SOC 递推、发电与购电上下限等。容量配置与纯调度问题的核心区别在于:第二阶段的储能容量上限 $E_{t} \le E_{rated}$ 中,$E_{rated}$ 是第一阶段的决策变量,而这个变量在子问题求解时已经被固定为常数。也就是说,子问题不会自动让储能容量更大,容量是否够用完全看主问题给出的配置。这也解释了为什么 C&CG 需要在主问题中反复加入极端场景下的第二阶段部分——只有这些极端场景被加进主问题后,主问题才会意识到储能或光伏容量不足,从而增加配置。

3. 列与约束生成算法求解两阶段鲁棒容量配置问题

3.1 为什么 min-max-min 不能一步求解

两阶段鲁棒容量配置问题从数学结构上是 min-max-min 三层嵌套,无法直接交给 Gurobi、Cplex 这类求解器,因为它们要求表达式是标准约束规划或 min-max 或 min-min,而不是这种混合嵌套。常规思路是切分成主问题和子问题交替求解。主问题只留第一阶段投资决策和一个场景池,场景池里每加入一个极端场景,第二阶段变量与约束就复制一套,主问题变成有限规模的混合整数或线性规划。子问题则固定第一阶段变量,在不确定集范围内搜索最坏场景及其最小运行成本。

这种分解有两种常见形式:Benders 分解和列与约束生成算法(Column-and-Constraint Generation,C&CG)。Benders 分解产生的割平面基于第二阶段对偶变量的极点,迭代中需要不断往主问题添加“关于投资变量”的线性不等式,当第二阶段约束数量庞大时收敛较慢。C&CG 不同,它通过往主问题显式添加新的第二段变量和约束来逼近原问题,本质上是一种“外逼近+枚举场景”的混合方法。对于第二阶段是连续线性规划的微网容量配置问题,C&CG 的收敛性通常优于 Benders,且实现难度并不高。

3.2 C&CG 主问题与子问题的数学描述

设第 $k$ 次迭代时,主问题包含已经发现的最坏场景集合 $U_k = {u^{(1)}, u^{(2)}, ..., u^{(k)}}$,则主问题可以写成:

$$\min_{x, y^{(1)}, ..., y^{(k)}} ; c(x) + \max_{u\in U_k} F(x,u)$$

上式的第二项是不可直接计算的,需要把每个场景对应的第二阶段目标拆开,写成对所有场景取最大。实际写出来其实是:

$$\begin{aligned} \min_{x, y^{(i)}} \quad & c(x) + \tau \ \text{s.t.} \quad & \tau \ge b^T y^{(i)}, \quad \forall i=1..k \ & y^{(i)} \in F(x, u^{(i)}), \quad \forall i=1..k \end{aligned}$$

用变量 $\tau$ 替代 max,再配合每个场景各自独立的第二阶段变量 $y^{(i)}$。请注意,$y^{(i)}$ 是每个场景各一套,不能共用,否则场景会互相耦合,变回一个巨大的单一确定性模型。C&CG 算法的关键就是不断把新的 $u^{(k+1)}$ 和对应的 $y^{(k+1)}$ 维变量加入主问题。

子问题在给定 $x=x^*$ 时求解如下问题:

$$SP(x^): \quad \max_{u \in U} \min_{y} ; b^T y \quad \text{s.t.} \quad y \in F(x^, u)$$

把内层取极小值的问题写成 LP,然后取其对偶。因为内层是连续线性规划,强对偶成立,子问题等价于一个只含最大化的问题:

$$SP(x^): \quad \max_{u \in U, \lambda \in \Lambda} ; b^T y + \lambda^T (g - A(x^) - B u)$$

其中 $\lambda$ 是内层约束的对偶变量,$A(x^*)$ 是第一阶段参数固定后形成的常数矩阵项。这个变换把三层问题压成了两层:外层仍然搜索 $u$,内层对偶变量随 $u$ 一起作为优化变量。储能 SOC 递推是等式约束,对应的对偶变量没有符号约束,在代码里体现为lb=None, ub=None,这部分很容易写错。

3.3 C&CG 的完整 Python 代码框架

下面给出一个基于 Pyomo + Gurobi 的 C&CG 实现骨架。这个骨架刻意省略了具体的约束展开,重点展示主问题与子问题的交互逻辑:

def c_and_cg(data, tol=1e-3, max_iter=30): scenarios = [data['nominal']] # 预置名义场景 LB = -1e9 UB = 1e9 for it in range(max_iter): # ---- 主问题 ---- mp = build_master_problem(scenarios) res = solve(mp) LB = res['obj'] # 主问题给出下界 x_star = res['x'] # 当前投资方案 # ---- 子问题 ---- sp = build_subproblem(x_star, data) res_sp = solve(sp) worst_cost = res_sp['obj'] u_worst = res_sp['u'] UB = min(UB, investment_cost(x_star) + worst_cost) gap = (UB - LB) / abs(UB) print(f"iter={it}, LB={LB:.4f}, UB={UB:.4f}, gap={gap:.4f}") if gap < tol: break # 把最坏场景加入场景池 scenarios.append(u_worst) return x_star, LB, UB

主问题的目标函数包含 $c(x)+\tau$,而 $\tau$ 的约束来自每个场景的运行成本,因此每轮迭代主问题的规模都会增加。在使用 Gurobi 求解主问题时,可以考虑传入上一轮求解的热启动文件,节约前几个阶段反复求解的时间,尤其是遇到 8760 时段或 8760 缩减成的 20 个典型日时。

3.4 子问题求解时最容易踩的数值与对偶坑

子问题求解不收敛或对偶不稳定的情况下,结果会以 UB 不下降或 gap 震荡的形式出现。常见原因有两个。第一个是储能 SOC 的等式约束造成对偶矩阵奇异。解决办法包括统一能量单位到 MWh,以及避免让 SOC 初始值、能量上限等参数的相对尺度差异超过 10 的 5 次方。第二个原因是子问题中约束两边存在数量级差距,比如购电价格用元/MWh 而惩罚项用元/kWh,会让最优解里的松弛变量异常活跃。

解决方法是把价格基准统一,惩罚系数显式写出而不是用 1e6 这类魔法数字;同时在求解结束后检查子问题最优解是否真的满足所有约束,而不是只读取目标函数值。下面的代码展示了如何固定 $x$ 并构造子问题:

def build_subproblem(x_star, data): m = pyo.ConcreteModel() # ---- 变量:确定场景下的第二阶段变量 / 偏差变量 ---- m.delta = pyo.Var(range(T), bounds=(-1, 1)) m.p_charge = pyo.Var(range(T), bounds=(0, P_max)) m.p_discharge = pyo.Var(range(T), bounds=(0, P_max)) m.p_buy = pyo.Var(range(T), bounds=(0, P_line_max)) m.p_curtail_pv = pyo.Var(range(T), bounds=(0, x_star['pv'])) # ---- 不确定集预算约束 ---- m.budget = pyo.Constraint(expr=sum(abs(m.delta[t]) for t in range(T)) <= Gamma) # ---- 储能SOC递推 ---- m.soc_next = pyo.Constraint(range(T-1), rule=lambda m, t: m.soc[t+1] == m.soc[t] + m.p_charge[t] * eta_c - m.p_discharge[t] / eta_d) return m

真实项目中,建议用数组表达式一次性构造m.soc的所有约束,避免循环推导中把时间索引搞错。子问题求解时如果遇到不可行,再额外检查功率平衡约束是否允许切负荷,以及系统初始 SOC 是否设置在安全区间。

4. 两阶段鲁棒优化参数整定与微网容量配置算例

4.1 算例数据设置

以一个并网型园区微网为例,调度周期 T=24,单位时段 1 小时。光伏预测出力按夏季晴天曲线折算,峰值容量系数 0.85,负荷侧典型日峰谷差约 40%,风电出力按三类风区经验曲线取均值。成本参数如下表:

参数数值单位
光伏单位容量投资3500元/kW
风电单位容量投资6800元/kW
储能单位容量投资1200元/kWh
储能单位功率投资850元/kW
购电电价峰值/谷值1.05/0.38元/kWh
年运行维护费率2%1/年

实际工程里的成本参数应当从可研报告取值,而不是论文里的典型值。特别是储能,单位容量投资必须包含电池、BMS、PCS 和集装箱的整套成本,否则第二阶段调度会把储能容量放大到不合理的程度。另一点是购电电价不要只用峰值谷值简单平均,而应该按分时电价表构造 24 时段序列,这样第二阶段模型才会合理地引导储能进行峰谷套利。

4.2 不确定预算 $\Gamma$ 的敏感性分析

使用上面的参数集,将 $\Gamma$ 分别设置为 0、4、8、12、16、24,运行完整的 C&CG 得到归一化配置结果。表头中“相对值”以 $\Gamma=0$ 时的配置结果为基准。

Γ光伏容量风电容量储能容量总成本相对值
01.001.001.001.00
41.061.031.101.04
81.141.071.221.08
121.221.111.351.12
161.291.161.441.15
241.371.221.521.18

这张表的典型规律是总成本的前半段增长斜率明显大于后半段。实际规划中,把 $\Gamma$ 定在斜率由陡变缓的位置即可,继续增加只会让投资额上升而可靠性提升不明显。这种“边际成本拐点”是两阶段鲁棒容量配置方案比选的核心指标,也是汇报材料里最有说服力的图表之一。

4.3 收敛曲线与异常回退排查

运行 C&CG 时,我会同时记录每一轮的主问题目标、子问题最坏场景成本和投资成本。一个正常的收敛曲线通常是:第一轮主问题只含名义场景,获得的投资容量偏小,UB 非常大;第二轮加入第一个最坏场景后 LB 大幅上升,UB 下降;此后 gap 单调收敛。如果出现 gap 在某一轮反而增大,多半是数值精度或子问题求解异常。

排查时先打印本轮次发现的最坏场景的出力曲线和 SOC 轨迹。若 SOC 轨迹出现明显跳变,比如从 0.2 瞬间到 0.85,那说明 SOC 的递推约束在子问题中被错误松弛了。另一个高发问题是在主问题里复制场景时忘了把储能 SOC 初值也一起复制,导致不同场景共享一套 SOC 变量,产生物理上不可能同时存在的交叉调度。

提示:把每轮子问题的目标函数值保存成列表,如果两轮之间波动超过 10%,优先检查 Gurobi 的FeasibilityTol设置,而不是直接加大迭代次数。

5. 微网容量配置结果后验与工程加速技巧

5.1 用蒙特卡洛模拟验证鲁棒配置的真实效果

C&CG 收敛后得到的容量配置,其“最坏情况成本”是在不确定集 $U$ 内搜索的结果,并不等于真实世界中的 95% 分位数成本。因此在交付前,我会固定容量配置,改用蒙特卡洛生成 5000 组符合实际概率分布的风光和负荷序列,逐一求解确定性调度,统计年运行费用的期望值和 p95 值。这个过程验证的是“不确定集设计得是否准确”。如果 p95 成本明显高于鲁棒模型给出的最坏场景成本,说明 $\Gamma$ 偏小;如果 p95 成本远低于最坏场景成本,说明 $\Gamma$ 偏保守,还有压缩投资的空间。

def validate(x_star, weather_samples, price_curve): cost_list = [] loss_list = [] for w in weather_samples: sp = build_deterministic_dispatch(x_star, w, price_curve) res = solve(sp) cost_list.append(res['total_cost']) loss_list.append(res['loss_prob']) return ( np.mean(cost_list), np.percentile(cost_list, 95), np.max(loss_list) )

其中weather_samples建议用历史气象年数据重采样,而不是用简单的正态分布随机生成。光伏和风电的出力具有自相关性,简单的独立随机序列会把最坏情况人为放大,导致后验结论失真。

5.2 主问题热启动与场景池初始化

一段值得写的加速技巧:C&CG 从空场景池开始时,第一轮主问题没有任何实际运行约束,投资容量会系统性偏小,首个子问题要花更多轮次把容量补回来。我的常规做法是初始场景池中加入名义场景和 1~2 个历史最差场景,例如“连续三天阴雨+晚峰荷载”这样的复合场景。这样第一轮主问题得到的是一个基本合理的容量配置,后续迭代只需微调。

另一个加速点是主问题求解完成后保留上一轮基解作为热启动。Gurobi 的warmstart对线性规划有效,但对含整数变量的主问题效果有限,因此通常只对第二阶段全为连续变量的问题生效。如果主问题引入了表示“是否投建某台机组”的 0-1 变量,热启动收益就不明显。

5.3 多资源不确定预算的拆分思路

当模型中同时存在光伏、风电和负荷三类不确定变量时,不要把三者的偏差加进同一个 $\Gamma$,因为不同资源的最坏情况很少同时出现。工程上常见的写法是各自独立预算,再增加一个总预算约束把三者绑定:

$$\Gamma_{pv} + \Gamma_{wt} \le \Gamma_{total}$$

这样做的好处是可以量化光伏与风电的互补性。如果某地区夜间风电大、白天光伏大,两者在时间上天然错峰,联合约束的收紧空间就大,总体方案更经济。不过要注意,这会让子问题的不确定变量数量膨胀,Gurobi 求解时间可能翻倍,建议先分别做单资源敏感性分析,再决定是否用联合预算。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 22:51:05

LSTM门控机制与时间序列预测实战:从原理到调参、交叉验证

简介&#xff1a;面向股票价格涨跌幅度预测&#xff0c;这份资源给出了一套基于长短期记忆网络&#xff08;LSTM&#xff09;的完整项目方案。项目以上证50ETF&#xff08;510050&#xff09;为研究对象&#xff0c;将历史交易信息作为特征输入&#xff0c;通过多值量化分类把预…

作者头像 李华
网站建设 2026/9/11 22:50:59

Kernel 视角:循环、线程与带宽的世界

概述 图做全局优化&#xff08;融合、布局、内存复用&#xff09;&#xff0c;Kernel 视角看到的是循环、线程、向量化、带宽&#xff0c;负责局部优化&#xff1a;向量化、tiling、寄存器分配&#xff1b;。两者在"kernel 的输入输出接口 这段话精准地划定了AI编译器中…

作者头像 李华
网站建设 2026/9/11 22:48:24

校园外卖跑腿系统设计与实现:Android四端架构与订单状态机解析

简介&#xff1a;基于Android的校园外卖跑腿系统毕业设计项目&#xff0c;覆盖用户端、商家端、骑手端、管理员端四个角色模块&#xff0c;实现从用户点餐、订单支付、商家接单、骑手派送到后台管理的完整业务闭环&#xff0c;面向计算机相关专业毕业生及Android/Java课程设计学…

作者头像 李华
网站建设 2026/9/11 22:47:14

用Python和FastAPI打造超市管理系统:表设计、事务与并发控制

简介&#xff1a;一份基于Python开发的超市管理系统毕业设计资料包&#xff0c;面向计算机相关专业在校学生&#xff0c;可用于毕业设计、课程设计、项目初期演示&#xff0c;也适合新手学习Python项目从设计到落地的完整流程。资源覆盖系统设计、功能实现与文档整理&#xff0…

作者头像 李华
网站建设 2026/9/11 22:45:51

跨境电商运营是什么?核心逻辑、关键指标与 2026 最新趋势

摘要&#xff1a;跨境电商运营说简单点&#xff0c;就是把产品卖到海外、并让这门生意持续赚钱的一整套动作。本文讲清它的完整链路、核心指标&#xff0c;以及 2026 年全链路数字化、海外仓本地化、品牌化升级这三个正在发生的关键变化&#xff0c;帮你建立系统认知。 跨境电…

作者头像 李华