冷热电联供系统多目标优化:NSGA-II代码实战与Pareto前沿分析
简介基于多目标算法的冷热电联供型综合能源系统MATLAB代码与操作视频面向能源、电气及自动化等相关专业的本硕博学生与教研人员可作为综合能源系统多目标优化课题的入门模板与实践参考。包内共4个文件包括两个MATLAB脚本主程序与适应度计算、一份txt格式说明文档以及一段avi操作录像整体压缩后仅160KB。内容围绕燃气成本、向电网购电/售电费用和碳排放费用三类优化目标建模求解运行环境建议采用MATLAB 2021a及以上版本主入口为Runme.m且要求当前文件夹处于工程所在路径配套操作录像完整演示了从环境准备到启动运行的流程可有效避免子函数误运行与路径设置失误。已有1697人浏览学习。借助这套代码与录像可快速上手冷热电联供系统的多目标优化方法理解模型构建、目标函数权衡与求解输出也可根据研究需要调整目标权重或约束参数开展不同工况下的对比分析与参数优化。1. 冷热电联供综合能源系统为什么要靠多目标算法来编排一个园区能源站要同时应付电、热、冷三种负荷有余热回收的燃气轮机有吸收式制冷有电制冷、储能和屋顶光伏。传统值班方式靠经验或者只盯着运行成本压减结果经常是成本低了碳排放反而居高不下或者为了“环保达标”把设备频繁启停搞得寿命缩水。多目标算法的价值就是一次算出几十、几百个互相冲突的最优解而不是替你拍一个“所谓最优”的单点答案。这个标题指向一套可运行的冷热电联供综合能源系统优化代码适合正在做综合能源调度、研究生课题或者设计院规划方案的从业者看懂模型、会改参数、能复现结果。这类问题的难点从来不是套一个 NSGA-II 库而是怎么把“冷热电联供”真实场景翻译成目标函数和约束再让多目标算法在有限时间内收敛得干净。2. 搭建冷热电联供的数学框架三个目标与三张平衡表2.1 设备链路与调度变量的对应关系冷热电联供系统的典型链路是天然气进入燃气轮机发电发电后的高温烟气进入余热锅炉产生蒸汽蒸汽再驱动吸收式制冷机组制取冷水同时也能通过换热器供热。电网作为后备电源电制冷机负责补冷储能电池收纳多余的电。如果屋顶还有光伏那整个系统的输入变量就更多了。模型的第一步是把要调的设备出力全部揉进一个决策向量x里。设备输入能量输出能量调节变量燃气轮机天然气电 高温烟气发电出力 P_gt(t)余热锅炉 / 换热器高温烟气热供热功率 H_hx(t)吸收式制冷机蒸汽/热水冷制冷功率 C_abs(t)电制冷机电冷制冷功率 C_ec(t)储能电池电电充/放功率 E_bat(t)电网交互电电购电功率 P_grid(t)常见做法是把一天 24 小时的这些变量全部平铺成一维数组长度是固定的方便交给遗传算法交叉变异。我一般会定义变量顺序为燃气轮机出力、购电量、吸收式制冷出力、电制冷出力、储能出力。其中E_bat(t)大于 0 表示放电小于 0 表示充电。下面的伪代码定义了这个向量结构# 变量顺序定义 import numpy as np HOURS 24 x np.zeros(5 * HOURS) # [P_gt, P_grid, C_abs, C_ec, E_bat] 逐小时拼接 # 切片索引后续所有函数都靠这个索引解包 P_gt x[0:HOURS] P_grid x[HOURS:2*HOURS] C_abs x[2*HOURS:3*HOURS] C_ec x[3*HOURS:4*HOURS] E_bat x[4*HOURS:5*HOURS]这段代码里的核心是“用固定切片代替变量名数组”。多目标算法每一次调用目标函数接收到的就是一个一维向量模型层必须把这个向量还原成物理上可理解的各设备出力。切片的顺序只要前后一致算法本身并不关心你内部怎么排但如果你后面加了一台电锅炉务必在目标函数、约束函数和初始化函数三处同步修改切片索引这是最常见的低级翻车点。2.2 经济、排放、能效目标函数怎么写才不打架冷热电联供里最常见的两个优化目标是运行成本和碳排放量有时还会加一个综合能源利用率。运行成本的构成是燃气费用加购电费用如果有余电上网还可以扣掉售电收益但多数项目里光伏和燃气轮机发的电都优先自用所以我这里先按纯购电模型写。成本目标f1f1 sum( gas_price * gas_consumption(t) grid_price(t) * P_grid(t) )碳排放目标f2f2 sum( emission_factor_gas * gas_consumption(t) emission_factor_grid * P_grid(t) )这里需要解释清楚为什么两个目标会冲突低谷电价时段电网购电便宜但电网电的碳排放因子通常高于天然气高峰电价时段燃气轮机发满虽然省电费却会让天然气消耗和排放在同一时段集中。两个目标天然此消彼长不存在一个解能让两项同时达到全局最小所以必须交给多目标优化去生成一组 Pareto 前沿解。代码里目标函数不能写成一句话返回标量而要返回一个向量给 NSGA-II 做非支配排序用def evaluate_objectives(x, data): 输入完整调度向量x返回目标数组 [cost, emission, energy_eff] data 里至少要有: data[load_e], data[load_h], data[load_c] data[price_grid] # 24小时分时电价 data[gas_price] data[lambda_grid] # 电网碳排放因子kgCO2/kWh data[lambda_gas] # 天然气碳排放因子 HOURS data[HOURS] P_gt x[0:HOURS] P_grid x[HOURS:2*HOURS] C_abs x[2*HOURS:3*HOURS] C_ec x[3*HOURS:4*HOURS] E_bat x[4*HOURS:5*HOURS] # 燃气轮机耗气量用发热量折算单位 m³/h # 燃气轮机发电效率 eta_gt 取 0.35天然气热值 LHV 取 9.7 kWh/m³ gas_load P_gt / (data[eta_gt] * data[LHV_gas]) # 余热供热吸收式制冷补燃的耗气量这里简化为与热/冷产出线性相关 gas_heat data[alpha_h] * (data[load_h] - data[eta_hx] * gas_load * data[eta_recover]) gas_heat np.clip(gas_heat, 0, None) gas_total gas_load gas_heat cost np.sum(gas_total * data[gas_price]) np.sum(P_grid * data[price_grid]) emission np.sum(gas_total * data[lambda_gas]) np.sum(P_grid * data[lambda_grid]) return np.array([cost, emission])这段代码有两个容易被忽略的设计燃气轮机的耗气量不是固定比例需要按发电效率eta_gt反推而余热锅炉的补燃只在余热不够供热需求时才发生np.clip(gas_heat, 0, None)保证了补燃量不会出现负数。如果你抄代码时漏掉这个 clip目标函数在余热富余时段会出现“负耗气量”算法会相当兴奋地往那个方向搜索最后给出的解根本没法落地。2.3 电、热、冷三张平衡表与出力区间约束约束条件是冷热电联供模型的骨架。第一类是等式约束即每一时刻冷热电必须供需平衡。电平衡P_gt(t) P_grid(t) P_pv(t) E_bat(t) load_e(t) C_ec(t) / COP_ec热平衡H_hx(t) H_gb(t) load_h(t)冷平衡C_abs(t) C_ec(t) load_c(t)第二类是不等式约束比如燃气轮机出力在 30% 到 100% 额定功率之间储能电池不能同时充放电储能容量在 0.1 到 0.9 倍额定容量之间。代码实现时不要把这些约束分得太散统一写成返回违反量的函数方便后续调试。def evaluate_constraints(x, data): HOURS data[HOURS] P_gt x[0:HOURS] P_grid x[HOURS:2*HOURS] C_abs x[2*HOURS:3*HOURS] C_ec x[3*HOURS:4*HOURS] E_bat x[4*HOURS:5*HOURS] violations [] # 1. 燃气轮机出力上下限 P_gt_min data[P_gt_max] * 0.3 violations.append(np.sum(np.maximum(P_gt_min - P_gt, 0))) violations.append(np.sum(np.maximum(P_gt - data[P_gt_max], 0))) # 2. 网格购电上限 violations.append(np.sum(np.maximum(P_grid - data[P_grid_max], 0))) # 3. 电平衡忽略配网网损 balance_e P_gt P_grid data[P_pv] E_bat - data[load_e] - C_ec / data[COP_ec] violations.append(np.sum(np.abs(balance_e))) # 4. 冷平衡 balance_c C_abs C_ec - data[load_c] violations.append(np.sum(np.abs(balance_c))) # 5. 储能容量约束简单线性化认为储能SOC由E_bat积分决定 soc np.cumsum(E_bat) / data[E_capacity] soc_min np.zeros_like(soc) 0.1 soc_max np.zeros_like(soc) 0.9 violations.append(np.sum(np.maximum(soc_min - soc, 0))) violations.append(np.sum(np.maximum(soc - soc_max, 0))) return np.sum(violations)约束代码的要点是“所有违反量都返回非负数量纲统一成功率或能量”。如果你的燃气轮机出力违反 20 kW购电上限违反 5 kW这两个数直接相加没有物理意义但作为惩罚项引导搜索方向是够用的。真正要小心的是储能 SOC 约束np.cumsum(E_bat)假设初始 SOC 为 0如果你的样例代码里初始 SOC 是 0.5那么这行代码会让算法把 SOC 整体抬高最终得到一个“伪平衡”的解。操作视频里通常会强调初始化 SOC 取值我建议把 SOC(0) 作为外部参数写进data而不是藏在 cumsum 里。3. 多目标算法选型与代码工程结构从NSGA-II到MOPSO3.1 为什么 NSGA-II 成了这一类问题的事实标准做冷热电联供优化你搜到的示例代码八成都是 NSGA-II紧接着是多目标粒子群 MOPSO。原因很现实CCHP 调度问题不是单峰函数非凸、非线性、有大量离散状态比如储能充电/放电切换传统的加权求和法在一个权重下只能得到一个点跑十组权重得到的解分布还非常不均匀。NSGA-II 用非支配排序加拥挤度距离一次种群迭代就能把 Pareto 前沿推出来而且实现代码相对短容易改造成自己的模型。MOPSO 在连续变量问题上收敛速度更快但冷热电联供里面有不少逻辑判断比如“吸收式制冷在余热不足时切换补燃”这种条件分支会让粒子群的速度更新变得混乱。我的习惯是第一版先用 NSGA-II 跑通模型确认目标函数和约束没有逻辑错误再在这个骨架上对比 MOPSO。不要一上来就上一套复杂混合算法模型错了再怎么优化也是自欺欺人。3.2 一套能复现的代码结构数据、模型、算法、画图四个模块标题带“代码操作视频”观众最反感的是视频里从一个完整工程里随便抽几个函数讲文件依赖关系一团乱麻。我一般会按四个目录组织代码复制到本地就能跑cchp_multiobjective/ ├── data/ │ ├── load.csv # 24h 电/热/冷负荷三列 │ └── price.csv # 24h 分时电价一列 ├── models/ │ ├── cchp_model.py # 目标函数和约束条件 │ └── device_params.py # 所有设备的效率、容量、排放因子 ├── solvers/ │ ├── nsga2.py # NSGA-II 主体 │ └── mopso.py # 可选的多目标粒子群 ├── results/ │ └── pareto_solutions.csv # 输出Pareto解集 └── run_case.py # 主入口一键运行这个结构遵循一个原则算法层不感知设备参数模型层不感知优化算法。cchp_model.py只负责“给定 x返回目标和约束违反量”nsga2.py只负责“给定种群返回新一代种群”。改燃气轮机效率时只动device_params.py换算法时只动solver目录不会牵一发动全身。主入口run_case.py只需要二十行左右import numpy as np from models.device_params import get_default_data from models.cchp_model import evaluate_objectives, evaluate_constraints from solvers.nsga2 import run_nsga2 data get_default_data() pop_size 100 max_gen 200 final_pop, final_obj run_nsga2( pop_sizepop_size, max_genmax_gen, n_vars5 * data[HOURS], datadata, evaluate_objectivesevaluate_objectives, evaluate_constraintsevaluate_constraints ) np.savetxt(results/pareto_solutions.csv, final_pop, delimiter,) np.savetxt(results/pareto_objectives.csv, final_obj, delimiter,) print(Pareto solutions saved:, final_pop.shape)这段代码的参数含义非常直白pop_size100表示每一代保留 100 条调度方案max_gen200表示进化 200 代n_vars是决策变量总数。对于 24 小时的模型5 个设备变量乘以 24 刚好是 120 个变量。如果算力紧张甚至可以砍到pop_size60, max_gen100先验证代码有没有 bug最后再跑正式大种群。3.3 NSGA-II 在冷热电场景里的三个必调参数很多示例代码给出的 NSGA-II 交叉概率、变异概率是拍脑袋写的丢到 CCHP 问题上往往前 50 代就收敛到某个甜点Pareto 前沿只稀稀拉拉几个点。以下是我在这个场景里的经验数值参数常见默认值CCHP 建议值原因种群规模5080-120变量数超过100种群太小覆盖不住完整可行域交叉概率0.90.85-0.95保持搜索强度但不要过于剧烈破坏已可行个体变异概率1/n_vars0.05-0.15CCHP变量区间差异大固定变异率容易让储能变量越界惩罚系数1100-1000约束违反量单位是kW目标函数单位是元相差太大最后一行惩罚系数是最容易被忽略的。假设一个平衡约束违反 200 kW惩罚系数为 1那这个解在目标函数里只被扣了 200 元而一个优秀解的运行成本可能比差解少几千元算法会倾向于保留“违反约束但成本更低”的劣质解。我一般会把约束违反量乘上一个data[penalty_scale]并设为 100 到 1000 之间让不可行解在非支配排序里基本没有生存空间。这个数值要在跑出第一代时观察一下目标量级再回来调节。4. 跑通示例代码的完整步骤数据、初始化、求解、画图4.1 准备输入数据负荷曲线、分时电价和光伏出力示例代码的“操作视频”一般会先展示数据集但视频里一晃而过的 CSV 格式你自己拼的时候很容易漏列。最稳妥的做法是准备三个文本load.csv保存电、热、冷三条负荷曲线price.csv保存 24 点分时电价pv.csv保存光伏预测出力。数据读取统一放在主脚本里import pandas as pd def load_case_data(load_filedata/load.csv, price_filedata/price.csv, pv_filedata/pv.csv): load_df pd.read_csv(load_file) # 列名: load_e, load_h, load_c price_df pd.read_csv(price_file) # 列名: price_grid pv_df pd.read_csv(pv_file) # 列名: pv_power data dict() data[load_e] load_df[load_e].values data[load_h] load_df[load_h].values data[load_c] load_df[load_c].values data[price_grid] price_df[price_grid].values data[P_pv] pv_df[pv_power].values data[HOURS] 24 return data很多人初跑代码时报“ValueError: operands could not be broadcast together”原因基本是 CSV 里多了一行表头或者某一列长度是 23。视频里不会当面告诉你 CSV 要 24 行整数点我的排查习惯是先print(data[load_e].shape)确认所有数组长度都是 24再继续往后面调。4.2 初始化和群约束防止第一步就把约束拍死NSGA-II 第一步是随机生成初始种群。如果纯随机生成五个变量互不关联电平衡约束几乎不可能满足第一代全是不可行解。这样非支配排序会失去梯度算法变成乱搜。我常用的补救是先做随机初始化再做一个简单的“启发式修正”根据电平衡反推P_grid从而让每一时刻的电平衡约束自动满足剩下的变量还是随机。def initialize_population(pop_size, data): pop np.zeros((pop_size, 5 * data[HOURS])) for i in range(pop_size): # 随机生成燃气轮机、制冷和储能出力 P_gt np.random.uniform(0.3, 1.0, data[HOURS]) * data[P_gt_max] C_abs np.random.uniform(0.2, 1.0, data[HOURS]) * data[C_abs_max] C_ec np.random.uniform(0.2, 1.0, data[HOURS]) * data[C_ec_max] E_bat np.random.uniform(-0.5, 0.5, data[HOURS]) * data[E_capacity] / 4.0 # P_grid 由电平衡反解保证等式约束天然满足 P_grid (data[load_e] C_ec / data[COP_ec] - P_gt - data[P_pv] - E_bat) P_grid np.clip(P_grid, 0, data[P_grid_max]) # 如果不clip之后电平衡被破坏重新计算一次E_bat E_bat data[load_e] C_ec / data[COP_ec] - P_gt - data[P_pv] - P_grid pop[i, 0:24] P_gt pop[i, 24:48] P_grid pop[i, 48:72] C_abs pop[i, 72:96] C_ec pop[i, 96:120] E_bat return pop这个初始化函数的核心逻辑是“利用等式约束消去一个变量”。随机生成燃气轮机、制冷、储能后购电功率不再随机而是作为差额补齐。这样种群从一开始就站在可行域边界附近算法后续只需要优化其他不等式约束。这里有个细节如果P_grid被clip限幅电平衡会被破坏所以我又用反解出的E_bat兜底总有一端是真实满足等式约束的。4.3 迭代与结果输出把解保存下来而不是只听终端NSGA-II 主循环的示例代码网上很多但很多示例跑完之后只打印一个目标值不保存种群你没法后续做决策。我建议在每一代结束都追加保存当前代的最优解集def save_pareto(pop, obj, gen): # 按非支配排序第一层取出Pareto前沿 from solvers.nsga2 import fast_non_dominated_sort fronts fast_non_dominated_sort(obj) pareto_idx fronts[0] save_pop pop[pareto_idx] save_obj obj[pareto_idx] np.savetxt(fresults/pareto_gen_{gen}.csv, save_pop, delimiter,) np.savetxt(fresults/pareto_obj_gen_{gen}.csv, save_obj, delimiter,)保存频率不用每一代都做我习惯每 10 代保存一次最后再单独存第 200 代。如果你的磁盘和内存有限这个函数可以改为只在代数尾号为 0 或最末代时调用。视频里经常能看到一条略过优化过程、直接展示结果曲线的画面实际上代码运行时间主要全花在这里保存中间代对分析收敛性非常有价值。4.4 画 Pareto 前沿和调度图判断你的解是否健康光盯着终端里的数值看不出问题必须把 Pareto 前沿画出来。冷热电联供一般是二维或三维目标画个二维散点图就够了import matplotlib.pyplot as plt obj np.loadtxt(results/pareto_obj_gen_200.csv, delimiter,) cost_all obj[:, 0] emis_all obj[:, 1] plt.figure(figsize(8, 6)) plt.scatter(cost_all, emis_all, csteelblue, alpha0.7, edgecolork) plt.xlabel(总运行成本 / 元) plt.ylabel(总碳排放量 / kg) plt.title(Pareto 前沿成本与碳排放的取舍) plt.grid(alpha0.3) plt.show()这个散点图如果呈现一条从左上到右下的光滑弧线说明算法收敛正常如果点非常离散、四周乱成一片大概率是约束惩罚系数太小或者是目标函数里出现了异常值。画调度图时可以把某个中间解拆回各设备出力用 stackplot 展示燃气轮机、购电、储能各自承担了多少电负荷。这一步是为了说服自己“解可执行”而不是只有数字好看。5. 避坑与排查冷热电联供多目标代码的五个典型血泪经验5.1 第一代全是不可行解Pareto 前沿空荡荡现象程序跑完fast_non_dominated_sort返回的第一层只有个位数甚至整个种群的目标数组里出现inf。原因随机初始化没有利用等式约束消元电平衡违反量动辄几千千瓦惩罚系数又只有 1目标函数差和约束违反量不在一个量级算法认为所有个体都一样差失去了选择压力。解决把初始化改成上一节里“由负荷反推 P_grid”的做法同时把惩罚系数调到 100 以上。跑前可以先单独调用evaluate_constraints打印一下初始种群的违反总量如果平均违反量还在百千瓦级别就说明初始化修得不彻底。5.2 目标函数出现负成本算法疯狂在错误方向搜索现象Pareto 前沿左下角出现成本为负的点且数量还不少看起来“无限省钱”。原因代码里某项余热回收的热量被错误地乘以负系数比如gas_heat data[alpha_h] * (data[load_h] - data[eta_hx] * gas_load * data[eta_recover])中gas_load单位是 m³/heta_hx * gas_load却是 kWh 需要的数值量纲不匹配导致高温烟气余热量计算远大于实际值补燃量被 clip 成 0燃气耗量只算发电部分相当于能源白送。解决所有物理量先统一单位再代入公式。建议在device_params.py里定义一个单位转换常量比如KWH_PER_M3 9.7每个公式里都显式乘上转换系数不要靠人肉心算。写出目标函数后先把每个设备设为满发状态手算一次成本跟程序输出对比。5.3 储能约束写进惩罚项但永远不满足现象SOC 曲线在结果图上贴着边界一直跑或者干脆 SOC 在任何时刻都大于 0.9。原因储能 SOC 约束用了cumsum但初始 SOC 不是 0而代码里从 0 开始累加实际运行完的系统 SOC 比设计值偏高或偏低算法为了补偿这个偏差干脆把整条储能出力曲线往一个方向偏移。解决将初始 SOC 作为data[soc_init]传入SOC 计算改成soc soc_init np.cumsum(E_bat) / E_capacity。另外要检查 SOC 约束的单位SOC 是无量纲比例而其他约束是 kW惩罚总量纲不统一可以把 SOC 违反量除以 10缩小与其他约束的权重差距。5.4 交叉变异后变量越界目标函数报错中断现象程序在交叉变异后报错比如“exp overflow”或“invalid value encountered in multiply”。原因NSGA-II 的模拟二进制交叉SBX和多项式变异可能产生超出变量上下界的值如果目标函数里直接对越界的功率做运算会导致负荷平衡被破坏出现负数开方或零除。解决在cchp_model.py的第一行就对x做 clip规定每个变量的物理边界def repair_variables(x, data): x_repair x.copy() HOURS data[HOURS] x_repair[0:HOURS] np.clip(x[0:HOURS], 0.3 * data[P_gt_max], data[P_gt_max]) x_repair[HOURS:2*HOURS] np.clip(x[HOURS:2*HOURS], 0, data[P_grid_max]) x_repair[2*HOURS:3*HOURS] np.clip(x[2*HOURS:3*HOURS], 0, data[C_abs_max]) x_repair[3*HOURS:4*HOURS] np.clip(x[3*HOURS:4*HOURS], 0, data[C_ec_max]) x_repair[4*HOURS:5*HOURS] np.clip(x[4*HOURS:5*HOURS], -data[E_bat_max], data[E_bat_max]) return x_repair修复函数要在evaluate_objectives的一开始调用而不是在遗传算子之后单独调用。因为种群里的所有个体都应该以“修复后”的状态参与适应度评价不然新旧个体不在同一个可行域标准下比较非支配排序的公平性就没了。5.5 换了一台电脑结果完全跑不出来现象视频里 MATLAB 或 Python 代码在自己电脑上各种报错从缺包到文件路径乱掉。原因操作视频通常直接在某个 IDE 里点运行文件的相对路径依赖当前工作目录。你新建的项目目录如果名称带空格或者把load.csv放在别的位置pd.read_csv(data/load.csv)就会报文件不存在。解决在主脚本顶部显式切换到项目根目录import os BASE_DIR os.path.dirname(os.path.abspath(__file__)) os.chdir(BASE_DIR)这样路径只和脚本文件所在目录有关跟 IDE 的工作目录无关。另外建议创建一个requirements.txt把numpy、pandas、matplotlib固定好大版本视频里如果用的是pandas 1.x你装个pandas 2.x在读取某个 CSV 时可能行为有差异多花十分钟锁定版本能省掉一晚上的玄学问题。6. 在多个 Pareto 解里做终选熵权-TOPSIS 后处理与调度落地多目标算法算出来的是一堆非劣解但调度员每天只能执行一套方案。后处理选择是操作视频里很少详细展开、却是实际落地最关键的一步。我的习惯是从 Pareto 解集里筛掉不可行或者过于极端的解再用熵权-TOPSIS 选出折中解既不让成本爆表也不让排放过高。先解包所有解的目标值然后对每个目标做熵权计算。这里贴一段能直接替换到你自己代码里的精简版def entropy_topsis(obj_matrix): obj_matrix: shape (n_solutions, n_objectives) 返回每个方案的相对贴近度越大越优 n obj_matrix.shape[0] # 归一化成本型和排放型目标越低越好 norm (obj_matrix.max(axis0) - obj_matrix) / (obj_matrix.max(axis0) - obj_matrix.min(axis0) 1e-9) # 计算熵权 p norm / (norm.sum(axis0) 1e-9) entropy -np.sum(p * np.log(p 1e-9), axis0) / np.log(n) weights (1 - entropy) / np.sum(1 - entropy) # 计算正负理想解距离 weighted_norm norm * weights ideal_best weighted_norm.max(axis0) ideal_worst weighted_norm.min(axis0) dist_best np.sqrt(((weighted_norm - ideal_best) ** 2).sum(axis1)) dist_worst np.sqrt(((weighted_norm - ideal_worst) ** 2).sum(axis1)) closeness dist_worst / (dist_best dist_worst 1e-9) return closeness这段代码中熵权会自动给“区分度大”的目标更高权重。比如碳排放目标在所有解之间差异很小成本差异很大那成本会被赋予更高权重最终选出的方案更接近成本最优而不是排放最优。你要是想体现“双碳”偏好可以直接手动把碳排放权重拉高替换掉熵权输出。拿到最优折中解后再把它解包成设备出力曲线转成实际调度表。我最后总会做一次人工核验打开调度表看燃气轮机有没有频繁启停、储能有没有在某小时同时充放电、夜间低谷电价时段购电比例有没有明显上升。这一关过了这套方案才敢交给运行值班人员。做这个方向久了会发现多目标算法的代码本身只是个体力和技巧活最花功夫的是让模型贴合真实设备边界以及学会在几十个 Pareto 解里做负责任的取舍。希望帮到你也祝你复现时一次跑通。本文还有配套的精品资源点击获取

相关新闻

6 行代码把截图变成 Markdown/HTML/LaTeX:TeleOCR 极简调用实测

6 行代码把截图变成 Markdown/HTML/LaTeX:TeleOCR 极简调用实测

6 行代码把截图变成 Markdown/HTML/LaTeX:TeleOCR 极简调用实测 【免费下载链接】TeleOCR 项目地址: https://ai.gitcode.com/XingChen-AGI/TeleOCR 做技术分享和论文笔记时,最烦的就是截图里的内容无法直接复用:公式要手抄成 LaTeX&…

2026/10/11 22:58:43 阅读更多 →
YOLOv8网球检测实战:数据集制作、模型训练到TensorRT部署全流程

YOLOv8网球检测实战:数据集制作、模型训练到TensorRT部署全流程

简介:这是一份面向打网球检测场景的YOLO系列目标检测数据集,适合使用YOLOv5、YOLOv8、YOLOv9等主流版本的算法工程师和研究者,可直接用于模型训练、验证与测试,解决打网球场景下训练数据匮乏、标注格式不统一等问题。数据集已经按…

2026/10/11 22:58:43 阅读更多 →
如何让NullHub开机自启:systemd与launchd系统服务注册完整教程

如何让NullHub开机自启:systemd与launchd系统服务注册完整教程

【免费下载链接】nullhub Management console for the Null ecosystem — install, configure, and monitor AI agents, orchestration workflows, task pipelines, and system health 项目地址: https://gitcode.com/gh_mirrors/nu/nullhub 点击查看 免费下载 想让…

2026/10/11 22:58:42 阅读更多 →

最新新闻

头歌MySQL实训全关卡答案解析与避坑指南

头歌MySQL实训全关卡答案解析与避坑指南

简介:这是一份头歌MySQL数据库实训的答案整理文档,面向正在完成头歌平台实训作业的学生,也适合需要系统回顾MySQL核心操作的初学者。文档以PDF格式提供,共1个文件,压缩包大小433KB,配有目录结构&#xff0c…

2026/10/12 0:30:14 阅读更多 →
OpenClaw 下一代 AI 助手框架:让 AI 拥有记忆和工具,TaoToken 统一 Key 接入实战

OpenClaw 下一代 AI 助手框架:让 AI 拥有记忆和工具,TaoToken 统一 Key 接入实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 0:30:14 阅读更多 →
身份证识别OCR实战:从图像预处理到字段解析的完整流程

身份证识别OCR实战:从图像预处理到字段解析的完整流程

简介:这是一份面向图像识别与OCR入门者的身份证识别项目实践资源,聚焦从身份证图片中自动提取身份证号及其他字段的完整实现。项目基于百度开源的PaddleOCR,针对中文识别效果做了优化,并编译了Windows可执行版本,可通过…

2026/10/12 0:30:14 阅读更多 →
Hyperf 中使用 Elasticsearch:协程化客户端封装与连接池实战指南

Hyperf 中使用 Elasticsearch:协程化客户端封装与连接池实战指南

后端Web框架微服务RPC框架异步编程 【免费下载链接】hyperf 🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease. 项目地址: https://gitcode.com/hyperf/hyperf 点击查看 免费下载 …

2026/10/12 0:30:14 阅读更多 →
指针仪表检测数据集实战:1000张图与三种标签格式的YOLO训练指南

指针仪表检测数据集实战:1000张图与三种标签格式的YOLO训练指南

简介:这份YOLO指针仪表目标检测数据集面向计算机、电子信息工程、数学等专业的学生与算法初学者,可用于课程设计、期末大作业和毕业设计中的目标检测训练与验证任务。压缩包共2000个文件,约20.25MB,包含1000张指针仪表图片&#x…

2026/10/12 0:30:14 阅读更多 →
基于深度学习的智慧教室:专注度分析与作弊检测实战

基于深度学习的智慧教室:专注度分析与作弊检测实战

简介:这份资源是面向计算机相关专业学生与项目实战学习者的智慧教室系统源码,核心围绕基于深度学习的课堂专注度分析与考试作弊检测两大功能展开,可作为毕业设计、课程设计或期末大作业的完整参考方案。压缩包共626个文件,约87.73…

2026/10/12 0:29:13 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →