news 2026/9/11 20:16:54

电动汽车充电调度论文复现:从数学模型到Python工程实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
电动汽车充电调度论文复现:从数学模型到Python工程实现

这个标题一看就是很多电动汽车方向研究者的入门刚需。我在做智能电网相关课题时,也接过类似的项目:论文里数学公式写得漂亮,但真要把它变成能跑、能复现实验曲线的代码,中间隔着大量隐式假设和工程细节。尤其是“考虑不同充电需求”这几个字,直接决定了调度模型复杂度,也决定了代码不能是“一个贪心算法打天下”。

这篇复现笔记我会按自己的实现顺序来写,核心思路是把原论文的逻辑还原成可运行的Python工程,包括数学模型怎么落代码、数据集怎么构造、约束怎么处理、实验图怎么复现,以及我实际踩过的几个坑。适合正在复现类似论文、刚接触电动汽车充电调度、或者想把这套方法迁移到自己研究场景里的朋友。

1. 首先理解原论文解决的真实场景:为什么“不同充电需求”是关键前提

复现论文代码之前,最忌讳的就是拿着公式直接翻译。你得先搞清楚这个模型到底在解决什么现场问题。这篇论文的核心场景是:一个充电站或一个区域内,有大量电动汽车需要充电,但配电网容量和充电桩数量有限,如果所有车都“插上就满功率充”,高峰期变压器会过载,电价高时用户也多花钱,到了晚上却有一堆车已经充满在占着桩。

所以论文提出了“协调充电调度”:由调度中心统一安排每辆车在什么时间、以多大功率充电,满足充电需求的同时,压低负荷峰值或充电费用。

“不同充电需求”这个前提,是为了让模型更贴近现实。我梳理了一下,大多数同类论文会把车辆分成这么几类:

需求类型典型场景充电紧急程度可调度灵活性
应急快充网约车、急救车辆,停留时间短很高,必须在短时间内补到指定SOC低,基本按接入即充
常规通勤上下班通勤车辆,白天停在公司中等,离场前充满即可高,可以在工作时间段内灵活分配功率
过夜慢充居民区车辆,晚上停一整个晚上低,次日早上取车时充满很高,可以平移到凌晨低价时段

如果模型不区分这些需求,统一用“最晚离场时间”作为唯一约束,那应急车辆可能会被排到后面,造成用户体验极差;反过来,如果所有车都按应急需求处理,那调度就退化成无序充电,论文也就没有创新点了。所以,“考虑不同充电需求”本质上是在模型中引入用户类型这个维度,并给每类车辆附加不同的优先级或约束。

1.1 协调调度的本质:在“满足用户”和“电网安全”之间找解

用大白话解释,协调调度就是一个“资源分配问题”。资源是每个时间段的充电功率,分配对象是每一辆车,约束条件是用户的充电需求和电网的容量上限,优化目标一般是总费用最低、峰值负荷最小或用户满意度最高。

从数学上看,这最终落成一个混合整数线性规划(MILP)问题。车辆接入/离场时间是0-1变量或者边界条件,充电功率一般是连续变量,而“某辆车在某个时段是否充电”这种判断需要整数变量。对于小规模场景可以直接用求解器求精确解,对于大规模场景论文通常会改用启发式算法或分解算法。

1.2 复现前必须做好的心理准备

复现这类论文要有一个清醒认识:原文未必把所有参数都给了。很多时候论文只给目标函数和约束的数学表达,不给你每辆车的到达时间分布、电池容量、充电功率上限这些数据。这在你开始写第一行代码前,就变成了一个需要“设计实验数据”的任务。所以我的建议是,先通读论文的实验部分,看它用了什么数据的描述。如果用了真实数据集,就直接找对应数据集;如果是随机生成的,就尽量从图里反推参数范围,比如“测试车辆数量为100辆,电池容量30~60kWh,充电功率3.5~22kW”这种描述,已经足够构筑一个可复现的实验环境了。

2. 数学模型逐条拆解:目标函数、约束条件和参数设计

通读完场景,接下来就是啃公式了。这一步不能跳过,因为代码里的每一个数组索引、每一个约束条件,都对应着公式里的一个符号。而且很多论文符号写得比较省略,特别是时间索引,这里需要自己补齐细节才能写代码。

2.1 参数定义部分:先把符号系统统一起来

这类论文通常存在多个时间尺度,一个是“调度周期”T(比如24小时),一个是“时间间隔”Δt(比如15分钟或1小时)。我建议在代码里先定义一个全局配置类,把所有的参数集中管理,避免后期改起来麻烦:

@dataclass class EVChargingConfig: T: int = 24 # 调度周期内的时段数 delta_t: float = 1.0 # 每个时段的时长,单位小时 num_evs: int = 100 # 电动汽车数量 grid_capacity: float = 250.0 # 变压器或充电站总功率上限,单位kW max_charging_power: float = 22.0 # 单台充电桩最大功率 min_charging_power: float = 0.0 # 最小充电功率,通常可为0 # 电池参数范围 battery_capacity_range: tuple = (30.0, 60.0) # 单位kWh initial_soc_range: tuple = (0.2, 0.8) # 初始荷电状态比率 target_soc: float = 0.9 # 离场目标SOC price_profile: list = None # 分时电价,长度为T

这个配置类看起来不复杂,但它解决了一个很现实的问题:论文里的符号体系跟代码不一定一一对应。你肯定不想在写目标函数时,发现还要满代码找某个常量定义在哪个文件里。

2.2 目标函数为什么这样构造

大多数充电调度论文的目标函数都是单目标或者加权多目标。常见的有这么几类:

  • 最小化总充电费用:min sum(p_i_t * price_t * delta_t)
  • 最小化峰值负荷:min max(sum(p_i_t))
  • 最大化用户满意度:max sum(soc_i_departure),或者最小化SOC缺额。

很多论文都会做“加权和”,例如:

min cost + lambda * peak_penalty + mu * unsatisfied_penalty

复现的时候要特别注意权重系数的取值。原文如果给了最好;如果没给,就需要自己去标定。一个简单的做法是跑几次基线(比如无序充电)得到费用的量级,再根据你希望突出哪个目标来定权重,确保量级匹配。比如费用是几千元,峰值为几百kW,那lambda如果取0.1,峰值项对目标贡献就太小了,等于没有优化峰值。

如果原文没有明确写出权重,你可能需要在复现说明里标注“此处为复现时自行设定的取值”,这在学术复现中是完全合理的,但要在文档里写清楚。

2.3 约束条件的现实意义

论文里的约束看起来多,其实可以分三组来理解。

第一组:单台车的充电功率约束。每个时段内,充电功率必须在0到最大功率之间。如果支持有序充电的功率可调,这就是连续变量边界;如果只支持开/关式充电,这就是0-1整数变量。

第二组:电池SOC状态转移约束。即:

soc_i_{t+1} = soc_i_t + (p_i_t * delta_t * eta) / battery_capacity_i

其中eta是充电效率。这里很多新手会漏掉除以电池容量这一步,导致SOC直接飞到天上。

第三组:电网或充电站总功率约束。即任一时刻所有在充车辆的功率之和不能超过站点的容量上限,同时还要考虑变压器或线路的负载上限。

还有一个容易忽略的约束:如果车辆在某个时段还没有接入或者已经离场,充电功率必须强制为0。这个在代码里一般通过接入时间索引和离场时间索引来实现,在约束里表现为变量上界乘以一个0/1的可用标志位。

3. 代码结构设计与数据准备:从论文符号到可运行工程

数学公式拆清楚了,下面讲代码怎么写。很多复现项目毁就毁在“代码结构混乱,一个 Notebook 堆到底”。我自己的经验是,即便你只是短期实验,也要分模块写,这样后面调参数、换算法、出图都会快很多。

3.1 总体模块划分

我建议至少分成这几个文件:

  • config.py:全局配置和默认参数;
  • data_generator.py:随机生成车辆到达、离场、初始SOC、电池容量等数据;
  • model.py:构建MILP模型,包含目标函数和约束;
  • solver.py:调用求解器,并输出结果到结构化数据(比如DataFrame);
  • analysis.py:计算指标、出图;
  • run_experiment.py:主流程,串联以上模块。

这种划分的好处很明显:如果你想换一个求解器或启发式算法,只需要替换solver.py里的部分函数;如果你想换数据集,只需要换data_generator.py;如果你想用真实电网负荷曲线,也只需要改配置里读数据的逻辑。

3.2 数据生成的细节设计

论文数据没公开时,自己生成随机数据也要讲究合理性,不能随便乱取。下面是我用过的生成逻辑:

  • 车辆的到达时间:用泊松过程生成一天内的到达时刻,考虑到早晚高峰会形成聚集,可以设置分段到达率。比如早上7~9点到达率较高,下午17~19点到达率较高,其他时间相对稀疏。
  • 初始SOC:取0.2到0.8之间的均匀分布或者截断正态分布。可以设定早上到的车初始SOC偏低(过夜消耗大),下午到的车初始SOC相对高一些。
  • 电池容量:按30kWh到60kWh均匀分布,对应市面上主流的纯电车型。
  • 充电功率上限:家用慢充桩一般7kW,公共快充桩一般60kW。数学模型里可以统一设为某个最大功率,实现时再在约束里限制。但注意,如果你的论文场景是小区慢充,那最大功率就是7kW左右,而不是22kW。
  • 最晚离场时间:通勤车一般是当天18:00,过夜车是次日08:00,应急车辆可能是接入后1~2小时。
  • 分时电价:可以采用峰谷电价,比如峰时1.2元/kWh、平时0.8元/kWh、谷时0.4元/kWh。

生成后最好做一次可视化,比如画一下“每个时段的在网车辆数”和“总充电需求”分布。如果数据生成不合理,比如过夜车辆数量过多,可能导致夜间所有车辆同时充电,即便调度也压不住峰值,这时候模型就自然不可行。可视化能帮你提前发现这种问题。

3.3 关键数据结构设计

在Python里,我习惯用Pandas DataFrame来存车辆基本信息和每个时段的充电计划结果。车辆信息表长这样:

ev_id arrival_time departure_time battery_capacity initial_soc max_power type priority 0 7.0 18.0 50.0 0.65 7.0 通勤 1 1 8.0 9.5 40.0 0.40 60.0 应急 3 ...

充电计划结果表长这样:

ev_id time_slot power 0 7 6.5 0 8 7.0 ...

这种“长表”格式对于后续聚合和画图非常方便。如果用numpy二维数组[num_evs, T]来存,也不是不行,但最后做数据分析时还是要转成DataFrame,不如一开始就直接用。

4. 核心调度算法实现:分群、排序与冲突消解

这里进入真正的算法实现环节。根据原论文思路,“不同充电需求”主要通过两步落进模型:第一步是对车辆进行分群/分级;第二步是在调度求解时给不同车辆分配不同优先级或约束。

4.1 充电需求分类:简单而有效的手写逻辑

如果论文没有用复杂的聚类算法,通常是根据停留时间、充电紧急程度、SOC需求三个维度做规则分类。我复现时直接写了阈值判断:

def classify_ev(row): # row包含 arrival_time, departure_time, initial_soc, target_soc stay_hours = row['departure_time'] - row['arrival_time'] soc_gap = row['target_soc'] - row['initial_soc'] required_energy = soc_gap * row['battery_capacity'] max_achievable_energy = row['max_power'] * stay_hours * 0.9 if stay_hours <= 1.5 or max_achievable_energy < required_energy * 0.8: return 'urgent' # 应急 elif stay_hours >= 6: return 'overnight' # 过夜慢充 else: return 'commute' # 常规通勤

这里的关键是“可调度性”判断:如果在最大功率下连续充都完不成目标,那这辆车必须优先充电,调度必须优先满足它,不能让它参与优化排队。这种规则分类看着简单,但它已经体现了论文“不同充电需求”的核心逻辑。

需要注意的是,分类之后不要只用类名来标记,还要给每个类分配一个数值优先级。应急车辆设为最高优先级,比如3;通勤车辆其次,比如2;过夜车辆最低,比如1。后面的求解器里,这个优先级会用来构造加权目标函数或者作为硬性约束的判定依据。

4.2 用线性规划求解器实现协调调度

以PuLP为例,我们可以很清晰地构建出MILP模型。下面是一个简化的调度实现,完整版本我在自己的项目里扩展了更多约束:

import pulp def build_scheduling_model(ev_info, price, grid_capacity, T, delta_t): prob = pulp.LpProblem("EV_Coordination_Scheduling", pulp.LpMinimize) # 决策变量:第i辆车在第t时段的充电功率 power = {} for i in ev_info.index: for t in range(T): power[(i, t)] = pulp.LpVariable( f"p_{i}_{t}", lowBound=0, upBound=ev_info.loc[i, 'max_power'] ) # 目标函数:总充电费用 + 峰值惩罚 cost_expr = pulp.lpSum( power[(i, t)] * price[t] * delta_t for i in ev_info.index for t in range(T) ) # 峰值可以用一个辅助变量近似 peak = pulp.LpVariable("peak", lowBound=0) for t in range(T): prob += pulp.lpSum(power[(i, t)] for i in ev_info.index) <= peak prob += cost_expr + 0.05 * peak # 权重需根据实验标定 # 约束1:可用时间窗口内才能充电 for i in ev_info.index: a = int(ev_info.loc[i, 'arrival_time'] / delta_t) d = int(ev_info.loc[i, 'departure_time'] / delta_t) for t in range(T): if t < a or t >= d: prob += power[(i, t)] == 0 # 约束2:SOC需求必须满足 for i in ev_info.index: prob += pulp.lpSum( power[(i, t)] * delta_t * 0.9 for t in range(T) ) >= (ev_info.loc[i, 'target_soc'] - ev_info.loc[i, 'initial_soc']) * ev_info.loc[i, 'battery_capacity'] # 约束3:任意时刻的总功率不能超过站点容量 for t in range(T): prob += pulp.lpSum(power[(i, t)] for i in ev_info.index) <= grid_capacity # 约束4:优先保障应急车辆 urgent_ids = ev_info[ev_info['type'] == 'urgent'].index for t in range(T): prob += pulp.lpSum(power[(i, t)] for i in urgent_ids) >= 0 # 占位 # 实际项目中可以给应急车辆单独设置最小充电功率约束 return prob, power

这段代码里,峰值惩罚项我用的是一个辅助变量peak。这在实际求解中非常常见,比直接定义max函数更优雅。约束2用“充电量 >= 需求电量”而不是逐时段计算SOC,是因为线性规划里逐时段SOC计算会让模型多出很多变量,性能变差。

4.3 求解与结果落地

构建好模型之后,直接调用prob.solve()就行。默认是CBC求解器,对小规模问题已经够用。求解完成后,要把决策变量提取回DataFrame:

result_records = [] for (i, t), var in power.items(): if var.varValue and var.varValue > 0: result_records.append({ 'ev_id': i, 'time_slot': t, 'power': var.varValue }) result_df = pd.DataFrame(result_records)

提取这一步还有一个细节:如果是整数变量,要把结果取整;如果是连续变量,最好保留两位小数,避免后面画图时出现密集的毛刺。另外,var.varValue在求解失败时是None,所以要做好判空。

4.4 程序执行流程串联

整个主流程其实很短:

  1. 加载配置;
  2. 生成或读取车辆数据;
  3. 对车辆进行分类,打上优先级标签;
  4. 调用build_scheduling_model构建模型;
  5. 求解,提取结果;
  6. 运行后验检查(后面专门讲);
  7. 画图,计算指标。

跑完后你会发现,程序的核心逻辑不过一两百行。但为了得到这个简单的核心,前面数学建模和数据准备花掉了绝大多数时间,这是完全正常的。

5. 实验复现与结果验证:关键指标、对比图表和一致性检查

模型跑通之后,接下来要回答的问题是:结果对不对?原论文的图能不能复现出来?这里不只是对数值,还要对趋势、对相对关系。

5.1 必须构建的基准对比

没有对比,调度结果就没有说服力。我在复现时至少对比了三种策略:

  1. 无序充电:车辆接入后立刻以最大功率充电,直到充满或离场。
  2. 定时充电:所有车统一在电价低谷时段启动充电,通常是夜间23:00到次日7:00。
  3. 论文协调充电:本文模型的结果。

通过对比这三种策略,可以看出协调充电在费用、峰值、充电完成率三个指标上的差异。这也是论文里最常见的三个图:费用柱状图、负荷曲线图、SOC分布图。

一个有效的复现实验,要做到论文中的结论性趋势在你的代码里重现,例如:相比无序充电,协调充电使总费用降低10%~20%,负荷峰值降低15%~30%,并且没有车辆完不成充电。

5.2 指标计算要统一口径

指标这块有太多复现者踩过坑,我自己也踩过。我建议一开始就明确规定:

  • 总费用 = 所有车辆在各时段结算的电费之和,单位元;
  • 峰值负荷 = 所有时段中,总充电功率的最大值,单位kW;
  • 充电完成率 = 到达目标SOC的车辆数 / 总车辆数,单位百分比;
  • 用户平均满意度 = 离场时实际SOC与目标SOC比值的平均值。

其中充电完成率这个指标,如果模型中设置了“SOC需求必须满足”的硬约束,那理论上应该始终是100%。但如果求解器告诉你不可行,你就得松绑约束或者提高站点容量。所以我还建议在模型里加入一个“未满足电量”的软性变量,方便观察哪些车被牺牲了。

5.3 画图时的细节

复现论文图表最常见的坑是横纵轴不对齐。假设论文的负荷曲线横轴是0~24小时,纵轴是kW,你的调度时间步长是15分钟,那画图前要先按小时聚合,不能直接画96个点再去跟论文对比,那样看起来对不上。

还有就是“接入即充”的无序充电曲线,峰值往往出现得非常早,7点到8点之间可能就满了。如果你的数据生成不合理,比如早上车辆过于集中到达,那峰值会直接顶到站点容量上限,这时候协调充电的效果反而体现不出来,因为你根本没有足够的冗余。所以生成数据后一定要多检查几遍。

6. 复现过程中最容易踩的坑:完整排查链路与修复建议

这一段我写得会比较细,因为这些问题我在实际做的时候一个都没躲过,而且是反复出现。如果你正卡在某个报错或结果异常上,可以直接按下面的链路来排查。

6.1 模型不可行:先看约束条件哪个太紧

模型不可行是最让人头大的错误,因为求解器只告诉你“infeasible”,不告诉你是哪个约束出了问题。我第一次做时候直接愣住了,后来终于总结出一套排查链路。

第一步:先去掉SOC需求约束,只保留功率上下限和站点容量约束。如果可行,说明问题出在总需求大于站点供给能力。这时候你要么降低车辆数量,要么提高站点容量,要么把部分车辆的SOC需求降低。

第二步:加上一天内总电量约束,不加逐时段约束。如果这时候还不可行,说明每条车“总充电量需求”本身就超过了可行范围,可能是初始SOC设置太低,或者目标SOC过高,导致需要充电的能量超过电池容量差与充电效率的乘积。

第三步:检查时间窗口。这是最隐蔽的坑。因为论文里的到达时间和离场时间往往用小数表示,比如7:30是7.5,而你做了int()转换后,可能把可用时间窗口算错了。例如7:30到达、8:00离场,如果delta_t=1,那么可用时段是[7, 8),其实只有一个小时;如果你处理成[7, 8]两个时段,就给了它两个小时的充电量上限。这在聚合约束里会造成模型“虚胖”可行,但在逐时段调度里可能出问题。

6.2 SOC越界或未达目标:先检查效率系数和电池容量归一化

这个问题主要出在SOC转电量的换算上。模型约束通常写成“充电量 >= 需求电量”,但需求电量是(目标SOC - 初始SOC)× 电池容量,而充电量是功率 × 时长 × 效率

一个常见错误是:忘了乘效率,或者忘了除以电池容量。比如有些论文里的状态转移写的是:

soc_{t+1} = soc_t + p_t * delta_t * eta / battery_capacity

但你在约束里却写成了:

sum(p_t * delta_t) >= (target_soc - init_soc) * battery_capacity

如果把delta_t不小心写成了总调度周期T而不是单位小时时长,或者效率系数写错,就会导致模型认为“充一度电就能满足目标”,最后结果自然不达标。

6.3 求解时间过长:问题规模太大时怎么降维

用MILP求解100辆车、96个时段,变量数就接近一万,CBC可能要跑很久。如果论文里是几百辆车,精确求解基本不现实。我建议的路线是:

  • 先试试把时间步长从15分钟放大到1小时,能大幅降低决策变量数量;
  • 用“聚合充电”策略简化模型,先不管早上8点这一辆跟8点15那辆的区别;
  • 如果还想更快,可以用启发式算法替代精确求解,比如遗传算法或粒子群算法,用来跟MILP结果做交叉验证。

但是要记住,使用启发式算法的时候,必须把MILP的小规模精确解作为参照,评估启发式算法的解离最优解差距有多大,否则论文审稿人一定会问你这个差距的问题。

6.4 结果重复率低:随机种子和固定随机流

生成随机数据时一定要固定随机种子。我见过太多人跑了一次结果不错,第二次数据不一样结果又崩了,然后以为算法有bug,其实只是随机波动。建议在data_generator.py里显式写上:

np.random.seed(42)

如果要用到多组随机实验求平均,再在config.py里增加一个random_seed字段,每次实验传入不同种子,最后统计均值和方差。

7. 进一步扩展:把复现代码改造成自己的研究工具

复现本身不是终点。如果你做课题、发论文,或者想做一套实用的充电调度策略,这批代码其实是一个不错的底座。我根据自己的经验,列几个扩展方向。

7.1 从单站扩展到多站场景

原论文可能只考虑一个充电站,但实际城市里有多个站点共享同一配电网。这时候模型里需要在总功率约束那一行进行跨站聚合。代码改动其实不大,就是把grid_capacity扩展到每个站点的容量向量,并把站点ID作为决策变量索引的第三维。

不过,多站延展后计算复杂度会显著上升。我的建议是先用低精度时间步长做可行性和效果验证,再逐步细化。

7.2 加入实时滚动优化

很多论文是离线调度,也就是已知一天内所有车辆的信息后一次性求解。实际更常用的是滚动时域优化:每隔15分钟或1小时重新求解一次,只决策未来几个小时的充电计划,滚动推进。

这会对代码结构有较大改动,因为你不再需要一次生成24小时的数据,而是每轮循环读取当前状态、更新剩余车辆和剩余需求,然后重新调用求解器。这个方向做出来,论文的创新点也会更足。

7.3 与深度学习预测模块整合

现在比较热的方向是把充电需求预测、电价预测或用户行为预测模型接到调度模型前面。比如用LSTM或Transformer预测未来几小时的总充电需求,然后把预测值作为约束条件输入调度模型。这个你就可以参考网络热词里经常出现的“深度学习代码复现”“多模态模型代码复现”那些项目里对模型封装和训练的技巧,形成一套“预测+调度”的端到端流程。

我的建议是,把预测模块和调度模块之间用清晰的接口隔开,预测模块输出为一个DataFrame,调度模块只认DataFrame,不直接依赖预测模型的内部实现。这样你换预测模型的时候,调度代码一行都不用动。

7.4 加入用户行为随机性

最后一个小扩展,也是论文里比较常见的:给用户行为加入随机性,比如到达时间提前或延后、实际充电需求变化。这个在你的代码里体现为:在求解完成后,随机改一些参数,观察原调度方案的鲁棒性。我在做类似测试时发现,应急车辆占比越高,调度方案的鲁棒性越差,因为少数的到达波动就可能导致峰值越界。实际运行中要预留5%~10%的容量余量,这也是工程上非常常见的做法。

写在最后

复现这篇论文的过程中,我最大的体会是:论文代码复现的难点不在代码本身,而在“把作者的隐式假设补全”。作者可能默认了你懂电网的负荷特性,默认了你理解SOC状态转移的物理含义,默认你知道目标函数里那个权重该怎么调。这些隐含信息只能靠一遍遍读原文、一遍遍对照实验数据去逼近。

如果你现在正准备入手这个方向,我建议不要一上来就追求完美复现原论文的每一张图。先跑通一个小规模的简化模型,哪怕是20辆车、24小时、一个求解器,把整个流程走通,再逐步增加细节。有了完整流程,后面的扩展才有抓手。这是我自己绕了不少远路才总结出来的经验,希望能让你少走几步。

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

Python自动化QQ邮箱处理:提升3倍效率的实战方案

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

作者头像 李华
网站建设 2026/9/11 20:13:16

MinMax-H3音视频模型原理与ComfyUI实战指南

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

作者头像 李华
网站建设 2026/9/11 20:13:11

轻量级农业物联网平台:Modbus/LoRaWAN设备接入与农事闭环管理

简介&#xff1a;这是一套面向计算机专业本科生的智慧农业平台毕业设计与课程实践项目&#xff0c;聚焦农业物联网系统开发&#xff0c;解决设备接入、农事协同与数据可视化三大核心问题&#xff0c;适用于毕设、课设、实训及大创等场景。资源包共1603个文件&#xff0c;涵盖59…

作者头像 李华
网站建设 2026/9/11 20:12:11

【JAVA毕业设计】基于 SpringBoot+Vue 的智能家教预约服务平台的系统设计与实现 基于 Web 的智能家教预约服务一体化平台(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/9/11 20:11:43

免U盘重装系统全攻略:WinToHDD安装与克隆实战指南

某个周日的深夜&#xff0c;我拆下老笔记本里那块 256GB 的 SATA 固态&#xff0c;准备换成新买的 1TB NVMe。系统盘拆都拆了&#xff0c;才忽然想起来——手边没有 U 盘&#xff0c;之前的启动盘不知道被谁拿去装系统再也没还回来。笔记本上躺着一个刚下好的 Windows 11 镜像&…

作者头像 李华