做混合动力整车能量管理的人,大概率都绕不开一件事情:把发动机和电动机各自的“脾气”摸清楚。所谓脾气,就是外特性曲线、效率MAP图,以及全局最优工作曲线。这三个东西是整个控制策略的底层地基,前期算不明白,后面所有功率分配、模式切换都是在沙子上盖楼。过去两年我自己写了好几版发动机和电动机组的Matlab计算程序,从最早只会画单张万有特性图,到后来能输出一条可以直接进控制器查表的最优工作线,中间踩了不少坑。这篇就把整个计算程序的设计思路、数据准备、核心实现和常见问题一次讲透,适合正在做混动能量管理策略、整车仿真或者刚接触台架数据的同学参考。
1. 为什么先要把外特性、MAP图和最优工作曲线放在一起算
很多刚接触这个领域的人容易把这三样东西当成彼此独立的任务:测个外特性、画个MAP图、找条最优曲线。但实际上它们是一个完整链条,外特性是边界条件,MAP图是全局效率分布,最优工作曲线是从这个分布里“长”出来的结果。分开算很容易出现边界不统一、最优线跑到外特性外面这类低级错误。
1.1 外特性:先把动力装置的“天花板”画出来
外特性曲线指的是发动机节气门全开(WOT)时,扭矩或功率随转速变化的极限曲线。电机的对应概念是峰值外特性,也就是在额定电压、峰值电流工况下,电机在某一转速区间能输出的最大扭矩。发动机的外特性一般呈现“先升后降”的山丘形,低速段扭矩爬不起来,高速段因为进气、摩擦损失加大,扭矩又开始掉。电机则不一样,它是典型的“恒扭矩区+恒功率区”两段式:基速以下扭矩恒定为峰值扭矩,基速以上进入弱磁控制,扭矩按功率恒定原则下降。
这俩形态差别决定了后续寻优策略完全不同。发动机最优工作曲线搜索时,外特性就是上边界,任何计算结果一旦越过这条线,程序就该报错或用NaN截断;电机的最优曲线则要在恒扭矩/恒功率两个区分别处理,不能混在一起找。我后来把外特性统一预计算成一条插值函数,所有后续搜索都调用它,避免在多个模块里各写一份边界判断逻辑。
外特性的数据来源通常是台架试验。发动机在测功机上稳定运行到指定转速后,油门加到全开,等扭矩读数稳定下来记录。转速间隔建议控制在200-500rpm之间,间隔太大会导致后续插值后的边界曲线明显拐折。电机的峰值外特性数据如果拿不到实测值,也可以根据额定功率P_max和峰值扭矩T_max推算基速:n_base = 9550 × P_max / T_max,基速以下扭矩平直,基速以上按P_max/n衰减即可。
1.2 MAP图:效率的“等高线地形图”
MAP图是转速-扭矩平面上效率分布的等高线图。发动机的MAP图通常叫“万有特性图”,等高线表示燃油消耗率BSFC,单位是g/(kW·h);电机的叫“效率MAP图”,等高线表示系统效率η,用百分比表示。为什么用等高线而不是三维曲面?因为在能量管理策略里,我们关心的是“在某一个转速下,给定扭矩时油耗是多少”,二维平面可以直接叠加最优工作线、等功率线,看图决策非常直观。三维曲面好看,但没法直接落在控制策略图纸上。
发动机BSFC的分布大致规律是:低转速低扭矩区油耗极高,因为泵气损失和摩擦损失占比大;中等转速(最高转速的50%-70%)加中高扭矩(最大扭矩的70%-90%)区域是经济区,最低比油耗点基本都落在这个矩形范围里;再往高转速或者逼近外特性极限的区域走,传热损失和机械摩擦急剧增加,油耗率又快速反弹。整体看,BSFC等高线在地图上呈扁椭圆形分布,最低点周围一圈圈向外扩大,像地形图上的山谷盆地。
电机效率MAP的形态完全不同。电机高效区一般覆盖较宽的转速和扭矩范围,从额定转速附近延伸到较高转速,低转速低扭矩区因为控制器损耗和铁损占比高,效率掉得特别明显。此外电机在驱动和发电两个象限的效率分布不对称,发电效率通常稍低一两个百分点,这两个象限的数据要单独测、单独画,不能拿驱动效率去替代发电效率。
1.3 最优工作曲线:从MAP图里提出来的“谷底线”
最优工作曲线的物理含义很直接:在每一个转速下,沿着扭矩轴扫描,找效率最高(发动机就是油耗最低)的那个扭矩点,把所有转速下的最优点连起来,就得到一条曲线。可以把它理解成MAP图这个“地形”里最凹的那条谷底线。
但要注意,所谓“最优”在不同目标函数下有不同答案。如果只优化发动机本体,那就是每个转速取BSFC最小值点,这条线完全落在万有特性图的谷底,控制策略里叫“发动机最优曲线”。如果考虑发动机加电机组成的混动系统,最优线就不一样了,因为发动机某个转速扭矩点对应的机械功率与整车需求功率之差,需要由电池通过电机来补偿,而电机的效率、电池的充放电损失都变了,最优解因此会被整体拉向另一个工作点。博文第3.4节会展开这个联合寻优的过程。
从数学上看,最优工作曲线可以等价为“一族等功率线与BSFC曲面的切点包络”。在转速-扭矩平面上,等功率线是双曲线T = 9550 × P / n,沿每条等功率线找到BSFC最小的点,这些切点连成的轨迹就是发动机侧的最优线。程序里既可以对每个转速做纵向扫描,也可以沿等功率线求切点,两种方法结果一致,但前者更简单直观,我推荐先把前者写通。
2. 程序要喂什么数据:台架数据、电机效率数据与网格约定
写程序之前先把数据准备好。这一步看似简单,实际最花时间。我见过不少同事故意跳过数据整理直接写算法,最后算出来的图自己都不敢用。数据源的质量直接决定最优线的可信度,程序技巧再花哨也弥补不了原始数据里的坑。
2.1 发动机台架数据长什么样
发动机台架稳态试验的记录格式一般是一个三列表格:转速n(rpm)、扭矩T(N·m)、燃油消耗率bsfc(g/(kW·h))。有些台架给的是燃油消耗量B(g/h或kg/h),那就需要再换算成功率后求得BSFC:bsfc = B × 1000 / P,其中P = T × n / 9550。
下面给一个示意数据表,代表某款1.5T涡轮增压发动机的典型测量值(模拟数据,仅用于说明格式):
| 转速(rpm) | 扭矩(N·m) | 功率(kW) | BSFC(g/(kW·h)) |
|---|---|---|---|
| 1200 | 40 | 5.0 | 285 |
| 1200 | 120 | 15.1 | 248 |
| 2000 | 80 | 16.8 | 240 |
| 2000 | 140 | 29.3 | 216 |
| 2400 | 160 | 40.2 | 206 |
| 3000 | 150 | 47.1 | 212 |
| 3600 | 120 | 45.2 | 231 |
| 4500 | 100 | 47.1 | 256 |
| 5500 | 80 | 46.1 | 288 |
测试工况点的覆盖范围直接影响插值质量。转速至少要覆盖怠速到最高转速,扭矩点要覆盖从低负荷到外特性极限。按经验,最起码要保证12个以上转速断面、每个断面8个以上扭矩点,也就是120组以上的有效稳态点。数据网格再密一些更好,插值出来的BSFC面才不会出现明显的棱角。
还有个容易被忽略的细节:同一转速下,扭矩从小往大和从大往小测的数据会有迟滞,发动机水温和油温不同时数据也不一样。处理原则是统一工况条件,等水温、油温都到80℃以上并稳定五分钟后再开始采数,每个测点至少稳定30秒以上再记录平均值。暖机过程的数据、发动机失火冒烟区附近的数据都要剔除,否则后面等值线图会出现奇怪的闭合圈。
2.2 电机效率数据的获取与处理
电机效率数据从台架测功机来,也可以从厂商提供的效率矩阵或者仿真模型生成。数据格式类似,但多了一个维度信息:驱动和发电两个方向要分开。电机效率定义为输出机械功率与输入电功率之比,驱动工况下η = P_mech / P_elec,发电工况下η = P_elec / P_mech。注意这里的P_elec一般指直流母线侧功率,包含了控制器和逆变器损耗,不是你拿万用表量出来的理想电压电流乘积。
电机效率MAP的形状大致是:在额定转速附近、扭矩在中高区间时效率最高,通常能到93%-96%;低转速低扭矩区很可能掉到80%以下,因为控制器损耗和铁耗占比重;高转速弱磁区效率也会下降几个点。发电工况的整体效率会比同工况驱动低1-3个百分点,这是因为电流流向不同导致控制器损耗分配略有差异,做能量管理策略时千万别用平均效率糊弄过去。
如果拿不到电机实测MAP数据,可以用一个简化模型先撑起来:η(n, T) = η_max × (1 - k1 × ((n - n_opt)/n_opt)² - k2 × ((T - T_opt)/T_opt)²),把η_max设为0.94,n_opt设为额定转速,T_opt设为中等扭矩,k1、k2按经验调整到高效区宽度合理即可。这个模型不能用于精确标定,但用于早期策略框架开发和最优线算法验证完全够用。
2.3 网格和单位统一:别在第一行代码就埋雷
程序里的坐标约定建议统一为:横坐标永远是转速n(rpm),纵坐标永远是扭矩T(N·m),等高线数值发动机为BSFC(g/(kW·h)),电机为效率(%)。功率统一用kW,这样T和n换算功率就直接套公式P = T × n / 9550,不需要来回乘除一堆系数。BSFC和效率之间的“沟通”需要把电功率折算成等效油耗:1 kWh电量按热值换算成燃油质量,约等于3600 kJ / 44 MJ/kg ≈ 0.082 kg,也就是82克汽油。但是考虑到发电和电传动链条的损失,实际在整车策略里每千瓦时电量通常折算成120-250克燃油,具体取多少由等效因子λ决定,这个参数会在联合寻优里反复调。
网格划分的粗细也要提前统一。台架原始测量点是不规则的散点,画MAP图前需要用griddata或interp2做规则网格插值。网格建议细到转速方向200-400个点、扭矩方向300-500个点,太粗了等值线锯齿严重,太细了内存占用大而且没必要。插值算法选'linear'或者'cubic',不要用'nearest',那个会画出马赛克一样的台阶。
3. Matlab实现的整体框架与核心代码
程序整体不算复杂,我拆成四个模块:数据读入与清洗、网格化插值、外特性边界提取、最优工作曲线寻优。每个模块独立成函数,调试起来方便,也方便以后换数据源。
3.1 程序总体框架
主脚本流程是这样:
%% 主脚本:发动机MAP + 最优工作曲线 % 1. 读入台架数据 bench = readmatrix('engine_bench.csv'); n_raw = bench(:, 1); T_raw = bench(:, 2); bsfc_raw = bench(:, 3); % 2. 建立规则网格并插值 n_interp = linspace(1000, 6000, 200); % 转速网格 T_interp = linspace(20, 240, 300); % 扭矩网格 [nG, TG] = meshgrid(n_interp, T_interp); bsfcG = griddata(n_raw, T_raw, bsfc_raw, nG, TG, 'linear'); % 3. 提取外特性边界(每个转速取最大扭矩) % 方法:按转速分组找最大值,再对边界插值 n_boundary = unique(n_raw); T_boundary = arrayfun(@(x) max(T_raw(n_raw == x)), n_boundary); T_ext = interp1(n_boundary, T_boundary, n_interp, 'linear', 'extrap'); % 4. 掩蔽不可达区域 [~, TG_mesh] = meshgrid(n_interp, T_interp); % 注意行/列布局 mask = TG_mesh > repmat(T_ext, length(T_interp), 1); bsfcG(mask) = NaN; % 5. 绘制MAP与外特性叠加图 figure; contourf(nG, TG, bsfcG, 20, 'LineColor', 'none'); hold on; plot(n_interp, T_ext, 'r-', 'LineWidth', 2); xlabel('转速 (rpm)'); ylabel('扭矩 (N·m)'); colorbar; title('发动机MAP图与外特性曲线');这里有个经常翻车的细节:meshgrid生成矩阵的维度与T_interp和n_interp的顺序有关。用[nG, TG] = meshgrid(n_interp, T_interp)时,nG每一行是一样的一组转速值,TG每一列是一样的一组扭矩值,两个矩阵都是length(T_interp)行、length(n_interp)列。mask计算时repmat要按列扩展,方向搞反的话掩蔽区域会乱套,画出来的图像块状撕裂。
3.2 用contourf画MAP图并叠加外特性
contourf画填充等值线是首选,它直接展示整个效率分布,颜色深浅一眼能找到经济区。叠加外特性曲线用plot画在图上即可。等值线层级数建议取15-25个,层级数太少看不出经济区边界,层级太多颜色过渡又显得杂乱。控制层级用:
levels = 200:10:320; [C, h] = contourf(nG, TG, bsfcG, levels); clabel(C, h, 'FontSize', 8);clabel给等值线标注数值,读图方便得多,特别适合出工程报告。如果觉得等值线标注太密,可以只标几条关键值:比最低油耗高5、10、15、20%的线。
有一个我后来才注意到的地方:Matlab默认的colormap是jet或者parula,画BSFC图看起来彩色斑斓,但一到黑白打印就分不清高低了。做成内部论文或者工程评审材料时,建议用turbo色图,颜色渐进更均匀,转灰度后层次感也好。另外colorbar的单位一定要标清楚,g/(kW·h),经常有人漏标。
3.3 最优工作曲线寻优算法
求最优工作曲线之前先要确定搜索的扭矩范围。直观做法是在每个转速下,从最小测试扭矩到外特性极限之间取一列扭矩向量,插值出BSFC序列,然后找最小值的下标。实现如下:
%% 最优工作曲线:逐转速寻优 n_query = 1200:200:6000; % 查询转速点 T_opt_list = zeros(size(n_query)); bsfc_opt_list = zeros(size(n_query)); n_upper = 1500:200:6200; T_upper = interp1(n_boundary, T_boundary, n_upper, 'linear', 'extrap'); T_max_at_query = interp1(n_upper, T_upper, n_query, 'linear', 'extrap'); for k = 1:length(n_query) % 当前转速下的搜索扭矩向量 T_search = linspace(0.05 * T_max_at_query(k), 0.97 * T_max_at_query(k), 400); n_search = n_query(k) * ones(size(T_search)); bsfc_search = interp2(nG, TG, bsfcG, n_search, T_search, 'cubic'); bsfc_search(isnan(bsfc_search)) = 1000; % 不可达点惩罚为大值 [bsfc_opt, idx] = min(bsfc_search); T_opt_list(k) = T_search(idx); bsfc_opt_list(k) = bsfc_opt; end搜索范围为什么上限取0.97倍外特性而不是贴着边界取?因为逼近外特性那几个点数据稳定性很差,转速波动或者水温变化都会让扭矩读数明显漂移,而且发动机在极限边界附近持续运行容易过热。留出3%的余量,寻优结果更稳健,也方便后续查表控制器留执行裕量。
如果你用Matlab的fminbnd做连续寻优也可以,速度快,但要注意fminbnd有时候会卡在局部极值,尤其BSFC曲线在低负荷段比较平缓时。我的做法是先做网格粗扫描确定大致位置,再用fminbnd细化,这样两全其美。
3.4 双动力源联合最优线的计算思路
发动机单独最优线做完只是第一步。在混动系统里,发动机输出的机械功率并不一定完全等于整车需求功率,多出来的部分要带动发电机给电池充电,不足的部分由电机从电池取电补上。这样一来,优化的目标就不再是单纯发动机BSFC最小,而是系统等效油耗最小。
等效油耗目标函数可以写成:
%% 系统联合最优:发动机+电机+电池 % 假设需求功率 P_req (kW),发动机工作点 (n_e, T_e) % 电机补偿功率 P_elec = P_req - P_e,其中 P_e = T_e * n_e / 9550 % 电池取放电方向:P_elec > 0 表示电机从电池取电(助力) % P_elec < 0 表示电机给电池充电(发电) % 等效油耗率 m_eq (g/h) = 发动机实际油耗 + 电池电量变化折算油耗 % m_eq = bsfc_eng * P_e + lambda * P_elec % (P_elec 中已包含电机/逆变器效率影响)具体操作是:对每个需求功率点,在发动机转速-扭矩平面上枚举所有可行工作点,用电机效率MAP插值得到电机实际电功率,再代入上面的等效油耗公式,选m_eq最小的那个工作点。把不同需求功率下的最优点连起来,就是系统层面真正的“最优工作曲线”。
λ这个参数很关键,它把电池电量折算成燃油消耗,物理含义近似于“当前1kWh电池电量相当于多少克燃油”。λ大,系统会更倾向于少用电、多烧油,最优线偏向发动机高负荷点;λ小,系统倾向用电,最优线偏向低负荷点。实际调试中λ一般取150-250 g/kWh之间,随着SOC变化实时调整:SOC低时调高λ,惩罚用电;SOC高时调低λ,鼓励用电。这个参数对整体油耗的影响非常敏感,值得在仿真里做一张λ扫描图再定标。
3.5 最优线的平滑处理
网格寻优直接得出来的最优点序列通常会有抖动,相邻转速之间最优点扭矩差个10-20N·m比较常见,原因主要是台架数据本身含噪声。控制策略查表时如果曲线跳变,会导致发动机扭矩指令忽大忽小,影响驾驶平顺性。所以最后要加一步平滑。
平滑可以用滑动平均,也可以用带约束的二次优化。简单一点用Matlab的smoothdata即可:
T_opt_smooth = smoothdata(T_opt_list, 'movmean', 5);但如果某个转速处的最优扭矩特别离谱,滑动平均会被拉偏。我的习惯是先算一阶差分,把单点跳变量超过阈值(比如相邻转速差超过40N·m)的点标记为野值,用相邻点线性插值替换,再做滑动平均。另外也可以把平滑约束放进目标函数里:min ∑bsfc + α·∑(T_k - T_{k-1})²,α值按经验取0.5-2,这样得到的曲线天然连续,不需要事后处理。
4. 常见问题与排查技巧实录
写程序和调数据的过程里,我踩过的坑列出来几乎能出一本“避坑手册”。问题集中在数据质量、插值边界、寻优不稳三个方面,下面按症状-原因-解决办法的形式整理成表。
4.1 常见问题速查表
| 症状 | 可能原因 | 解决办法 |
|---|---|---|
| MAP等值线出现锯齿状折线 | 台架测点太稀疏 | 增加转速/扭矩测点,或改用'cubic'插值 |
| 最优线在某个转速突然跳到外特性附近 | 该转速点附近原始数据BSFC异常低 | 核对台架记录,删除异常点后重新插值 |
| 外特性曲线末端下坠或上翘 | 高转速段测试点不足,边界外推失真 | 补充高转速测试点,或截除外推超出范围的区域 |
| 插值后BSFC出现负值 | griddata外推到了数据区域外 | 用NaN掩蔽不可达区域,不要在包络外插值 |
| 电机低转速区效率低得离谱 | 控制器损耗权重过高,数据本身没错 | 这是正常现象,策略上尽量避开该区域即可 |
| 系统联合最优线与发动机最优线完全重合 | λ取值过小或过大 | 调整等效因子λ,并检查P_elec方向是否搞反 |
第一行的问题最常见。转速间隔超过500rpm的网格,插值出来的BSFC曲面在测点之间的变化规律全靠算法脑补,等高线自然会凹凸不平。如果台架补测成本高,可以用区域加权插值先在Matlab里加密,或者干脆对原始BSFC网格做样条平滑。
第二行的“最优线跳变”要特别警惕。这往往不是算法问题,而是原始数据里某个测点因为工况没稳定记录了一个偏低的BSFC值,正好被寻优算法选上。我处理这类问题时会先画一张散点BSFC图,对异常点做个交叉验证:把该点相邻转速同扭矩附近的值拉出来对比,如果孤立地偏低超过8%,直接剔除重插值。
4.2 最优线乱跳的后续处理:滞回与滤波
就算做了平滑,最优线在某些功率段仍然可能出现“振荡敏感区”——两个相邻功率点对应的最优扭矩差出100N·m以上,导致策略在这个区域频繁来回切换。原因是发动机MAP在某个区域内近乎平缓,BSFC差个1-2g/(kW·h)对最优位置影响却很大。
工程上处理这个问题的常规手段是滞回和滤波。具体做法是:对功率需求方向做一个滞回区间,比如需求功率在某个窗口内上升时用低功率曲线,下降时用高功率曲线,两条曲线之间的功率差取3-5kW;同时在扭矩指令输出前加一阶低通滤波,时间常数取0.5-1秒,既能保证响应速度,又能消除抖动。这样最优线表格即便有少量阶梯,实际执行起来也平稳。
4.3 数据采集阶段最容易踩的坑
关于数据采集,我再多说几句。台架测BSFC时,很多人只盯着油耗仪读数,却忽略了冷却水温对数据的影响。同一台发动机,水温从70℃升到90℃,BSFC能差5-8g/(kW·h),低负荷区尤其明显。外特性测试时发动机长时间全油门,水温很容易飙升到100℃以上,这时候采集的数据整体偏高,最后算出来的最优工作线会偏向低负荷——这显然不符合真实意图。我的习惯是测一个转速断面之前先确认水温稳定在85±2℃,油温稳定在100±3℃,每个工况点稳定至少30秒,取平均数记录。宁可测得慢,也不能采到漂移数据。
另一个容易忽视的点是冒烟边界。柴油机或者某些直喷汽油机在大扭矩低转速区域有烟限,台架测量点如果落在冒烟区,油耗数据虽然能读出来,但实际整车标定时这些点根本不会用。建议拿到原始数据后先对照烟限图,把冒烟区的点剔除或者标记,再进入网格化插值流程。
5. 程序输出怎么落地到实车策略
算出来的最优工作曲线最终要变成控制策略里的查表数据。这一步很多人觉得简单,实际上工程落地的坑一点不比算法少。
5.1 把最优线输出成控制表
程序最后建议输出一张Excel或CSV表,包含转速、最优扭矩、最优功率、对应BSFC四列。转速点间隔不要直接用寻优时的200rpm,建议重采样成250、500这样的整间隔,方便控制器标定工具导入。控制器实际判断转速是离散的,查表时相邻点之间用线性插值,不需要高阶插值——嵌入式MCU算力有限,线性插值足够。
输出扭矩值还要做一次量化。控制器里扭矩指令通常以0.5N·m为分辨率,表格里保留一位小数即可,多了反而误导标定工程师以为精度很高。最优功率那一列主要用于能量管理策略里的功率跟随判断,比如判断当前需求功率落在哪一段最优线附近,决定要不要切入串联模式。
5.2 与能量管理策略的衔接方式
最优工作曲线在混动策略里最常见的用法是“功率跟随”逻辑。整车控制器根据当前需求功率和SOC状态,先查表找到这个功率对应的工作点(转速+扭矩),然后控制发动机沿着这条线走;发动机实际输出的机械功率与需求功率之差,由电机补足或吸收。听起来很直接,但要注意两点。
第一,发动机最优工作线给出的是一个扭矩随转速变化的一维函数,但在行车过程中转速是连续变化的,如果直接按实时转速查表,会出现扭矩指令和转速循环互相耦合的问题。工程上一般改成先按功率需求查表得到目标工作点,再让发动机沿这个目标点做闭环控制。
第二,串联模式(发动机只发电不直驱车轮)和并联模式(发动机直驱车轮)下同一个功率对应的最优工作点实际是不同的,因为机械传动路径损失不一样。如果只用一条通用最优线,模式切换瞬间会有明显的扭矩跳动。要么分别算两条线,要么在切换时刻做扭矩斜坡过渡。
5.3 多转速区间重采样技巧
有些发动机MAP的经济区相对平坦,最优线在2000-3000rpm范围内BSFC只差2-3g/(kW·h)。这时候其实不必强制锁死在“唯一最优点”,可以把最优线变成一个“最优带”,带内任意点等效油耗差异不超过1%。这样做的好处是策略自由度大幅提升,可以让发动机工作点兼顾振动噪声、催化剂温度等其他约束。程序上实现也不难:在每个转速下找BSFC最小值,然后向外扩张等值线,取高出最小值1%的等高线内的区域,输出上下边界两条线。后续策略在做点选择时就有了取舍空间,效果远好于单线查表。
我在实际项目里后来把这套“最优带”逻辑用上了,发动机模式切换频次明显下降,NVH问题也更好处理。如果你只是做仿真研究,单条最优线已经够用;但真往实车场平推,建议一开始就把最优带算法写出来,省得后面返工。
最后再分享一个小技巧。算完最优工作曲线之后,一定把原始数据的散点、插值后的MAP、外特性边界、最优曲线、最优带这五层信息同时画在一张总图上。每次调整数据或者改插值参数,都对照这张总图看差异,能省掉大量排查时间。我自己踩过几次“数据更新了但图没更新”的坑之后,把主脚本里的绘图部分单独拎出来做成一个固定函数,每次重算完自动生成总图,这样至少保证看到的永远是当前数据的结果。整个程序算下来,从数据准备到出图加输出控制表,半天时间就能跑一轮,迭代效率非常高。