news 2026/9/6 3:45:25

粒子群算法优化一次调频PID参数:从建模到工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
粒子群算法优化一次调频PID参数:从建模到工程实践

简介:这份PDF资料聚焦电力系统一次调频参数优化问题,面向电气工程、电力系统自动化方向的研究生、工程师及算法应用人员。内容以区域电网一次调频仿真模型为基础,系统梳理调差系数与调节死区对机组频率响应灵敏度、负荷分配及煤耗经济性的影响,并引入粒子群算法(PSO)对参数进行寻优,给出兼顾频率稳定性与运行经济性的参数配置思路。文中包含数学建模、仿真实验与结果分析,适合作为相关课题的参考文献或专业指导材料。压缩包内为1个PDF文件,共约606KB,内容紧凑,便于直接阅读与归档。当前已有87人学习浏览,说明该主题具有一定关注度。读者通过本文可了解粒子群算法在一次调频参数整定中的具体应用流程,掌握调差系数、死区等关键参数的优化逻辑,并借鉴作者构建区域电网调频模型、评价经济性目标的实验方法,为后续开展同类优化研究或工程实践提供参考。

1. 一次调频参数优化,到底在优化什么

做电力系统或者火电机组控制的朋友,对“一次调频”这三个字肯定不陌生。电网频率一旦偏离额定值(50Hz),汽轮机调速器就得快速动作,通过改变调门开度来调整进汽量,让发电机出力跟上负荷变化,把频率拉回正常范围。这个过程就是一次调频,它是电网频率稳定的第一道防线。

一次调频的控制效果,核心取决于调速器的PID参数,也就是比例系数、积分系数、微分系数。这组参数定得好不好,直接决定机组在频率扰动下是“快准稳”还是“又慢又晃”。很多电厂在实际运行中会遇到这样的问题:参数按经验整定,调门动作慢,频率偏差迟迟拉不回来;或者参数调得过猛,功率超调严重,调门来回振荡,反而影响设备寿命。传统工程上常用的试凑法、临界比例度法,本质上是靠经验和反复试验,面对多变量耦合、非线性约束时效率很低,而且很难找到真正意义上的最优解。

最近我做了一个基于粒子群算法的一次调频参数优化研究,说白了就是让算法帮我们自动搜索一组最优的PID参数,替代“拍脑袋+反复试”的老路子。做完之后的效果比较明显:频率偏差恢复时间缩短了大约30%,功率超调量明显下降,调门动作也更平稳。这篇文章我就把这个项目的完整思路、建模过程、粒子群算法实现细节、碰到的问题和解决办法都梳理一遍,给正在做类似调频优化、参数整定或者刚接触粒子群算法的朋友一个可以直接参考的实操样板。

需要提前说明的是,这个项目用MATLAB完成仿真验证,算法思路完全兼容Python等其他平台,关键代码我会贴出来,大家按自己的习惯迁移即可。

2. 一次调频系统的建模思路与优化目标

2.1 被控对象的模型怎么搭

做参数优化,第一步必须把被控对象的数学模型搭出来。一次调频系统说白了是一个闭环反馈系统:频率偏差作为输入信号,经过调速器PID运算后输出调门开度指令,调门开度变化影响汽轮机进汽量,进而改变机械功率,机械功率和电磁功率的差值决定了频率的变化。

我用的模型是典型火电机组的一次调频简化模型,包含几个核心环节:

  • 调速器环节:输出调门开度指令,本质是一个带PID控制律的传递函数,还有调门开度限幅和速率限幅。
  • 汽轮机环节:用一阶惯性环节模拟,时间常数反映蒸汽容积效应,一般取0.2~0.5s。
  • 发电机及负荷环节:用一阶惯性环节描述转子运动方程,时间常数和机组惯量、负荷频率调节效应系数有关。

更直白一点说,这个闭环系统可以理解为“用频率偏差驱动调门,调门改变出力,出力反过来影响频率”。频率偏差就是系统误差信号,PID参数就是我们要优化的对象。

模型建好之后,用MATLAB的Simulink搭框图,或者直接写成传递函数形式配合sim函数做仿真,两种方式我都试过。如果要做批量寻优,建议写成脚本形式,不要每次都在Simulink里手动改参数,否则算法迭代几百次你能点鼠标点到崩溃。

2.2 目标函数怎么定才合理

粒子群算法本质上是一个搜索最优解的过程,所以要先把“什么是好参数”转化成数学表达式,也就是目标函数。这个目标函数必须能反映一次调频性能的真实需求。

一次调频性能评价通常看三个指标:

  • 频率偏差峰值(动态偏差最大值),越小说明系统抑制扰动能力越强。
  • 调节时间(频率恢复到允许范围内所需时间),越短说明响应越快。
  • 超调量(功率或调门开度超过目标值的幅度),超调大说明稳定性差,也容易造成调门机构疲劳。

我最终采用的目标函数是这三项指标的加权组合。具体形式是这样的:

J = w1 * ITAE + w2 * Mp + w3 * Ts

其中ITAE是时间乘以绝对误差积分,Mp是超调量,Ts是调节时间。权重w1、w2、w3根据工程优先级设定,我实测下来取0.5、0.3、0.2效果比较好,因为ITAE本身综合反映了响应速度和误差大小,权重给高一点是合理的。

目标函数值越小,代表这组PID参数下的一次调频性能越好。粒子群算法每一轮迭代就是在参数空间里不断搜索,让J值不断下降,直到收敛到最优或接近最优的参数组合。

3. 粒子群算法的原理与参数选择策略

3.1 粒子群算法到底在干什么

粒子群算法(Particle Swarm Optimization,PSO)是一种模拟鸟群觅食行为的群体智能优化算法。鸟群在寻找食物的过程中,每只鸟都有自己的位置和速度,它们会根据自己历史找到过的最好位置(个体最优)和整个群体找到过的最好位置(全局最优)来调整飞行方向和速度,最终整个群体聚集到食物源附近。

对应到参数优化问题上,每个“鸟”就是一个粒子,一个粒子代表一组候选PID参数。粒子在参数空间里的位置就是PID参数的具体数值,粒子的“飞行速度”就是参数调整的方向和幅度。通过不断迭代,粒子群会逐渐收敛到全局最优解附近。

核心的更新公式是:

v[i] = w * v[i] + c1 * r1 * (pbest[i] - x[i]) + c2 * r2 * (gbest - x[i]) x[i] = x[i] + v[i]

其中:

  • w是惯性权重,控制粒子保持原来运动趋势的能力。w大,全局搜索能力强;w小,局部搜索能力强。
  • c1、c2是学习因子,分别控制粒子向个体最优和全局最优学习的强度。
  • r1、r2是0到1之间的随机数,引入随机性避免粒子陷入局部最优。
  • pbest和gbest分别是个体历史最优位置和全局历史最优位置。

这个算法最吸引人的地方在于不需要计算梯度,对目标函数是否可导、是否连续没有要求。对于一次调频这种被控对象特性复杂、目标函数可能非光滑的工程优化问题,这个特性非常关键。

3.2 关键参数的经验取值

粒子群算法的参数设置直接影响收敛速度和优化质量。我在这次研究中经历了不少试错,最终采用的参数如下:

  • 种群规模:30个粒子。太小容易早熟,太大计算量成倍增加,30是个比较均衡的选择。
  • 迭代次数:100次。多数情况下50次左右就已经收敛,100次保险起见,同时也能观察收敛曲线是否稳定。
  • 惯性权重w:从0.9线性递减到0.4。前期w大,粒子大步探索全局空间;后期w小,精细搜索最优区域。这是一个非常经典的动态调整策略,比固定w效果明显好。
  • 学习因子c1、c2:都取2.0。这是PSO文献里最经典的取值,让粒子在个体经验和群体经验之间保持平衡。
  • 粒子速度上限Vmax:设置为参数范围的20%,防止粒子飞出搜索空间造成震荡。

粒子位置范围的设定也很关键。PID三个参数量纲不同,取值范围差异很大,我建议每个维度单独设置边界。比如Kp的范围可以设0.5到5,Ki设0.01到1,Kd设0到2,具体要根据实际被控对象的物理特性来定。范围设宽了搜索效率低,设窄了可能错过最优解,这个需要结合工程经验。

4. 粒子群算法优化一次调频参数的代码实现

4.1 算法主流程代码框架

下面这段代码是粒子群算法的核心框架,我整理成比较通用的形式,目标函数部分会调用一次调频系统的仿真模型。完整代码里还包括参数文件、被控对象模型函数和结果分析部分。

%% PSO主程序 clear; clc; % 一次调频仿真参数 simulation_time = 30; % 仿真时长(s) frequency_step = 0.1; % 频率阶跃扰动(Hz) % PSO算法参数初始化 dim = 3; % 优化变量维度:Kp, Ki, Kd nParticles = 30; % 种群规模 maxIter = 100; % 最大迭代次数 w_max = 0.9; % 惯性权重上限 w_min = 0.4; % 惯性权重下限 c1 = 2.0; % 个体学习因子 c2 = 2.0; % 群体学习因子 % 参数边界 [min, max] Kp_range = [0.5, 5]; Ki_range = [0.01, 1]; Kd_range = [0, 2]; param_ranges = [Kp_range; Ki_range; Kd_range]; % 初始化粒子位置和速度 positions = zeros(nParticles, dim); velocities = zeros(nParticles, dim); for i = 1:nParticles for j = 1:dim positions(i,j) = param_ranges(j,1) + ... rand * (param_ranges(j,2) - param_ranges(j,1)); velocities(i,j) = 0.1 * (param_ranges(j,2) - param_ranges(j,1)) * ... (rand - 0.5); end end % 初始化个体最优和全局最优 pbest_positions = positions; pbest_values = zeros(nParticles, 1); for i = 1:nParticles pbest_values(i) = objective_function(positions(i,:), ... simulation_time, frequency_step); end [gbest_value, gbest_index] = min(pbest_values); gbest_position = pbest_positions(gbest_index, :); % 迭代寻优 convergence_curve = zeros(maxIter, 1); for iter = 1:maxIter w = w_max - (w_max - w_min) * iter / maxIter; for i = 1:nParticles r1 = rand(dim, 1); r2 = rand(dim, 1); % 更新速度 velocities(i,:) = w * velocities(i,:) + ... c1 * r1' .* (pbest_positions(i,:) - positions(i,:)) + ... c2 * r2' .* (gbest_position - positions(i,:)); % 速度限幅(按边界范围的20%限幅) velocity_limits = 0.2 * (param_ranges(:,2) - param_ranges(:,1))'; velocities(i,:) = max(min(velocities(i,:), velocity_limits), ... -velocity_limits); % 更新位置 positions(i,:) = positions(i,:) + velocities(i,:); % 位置越界处理:越界粒子拉回边界 for j = 1:dim if positions(i,j) < param_ranges(j,1) positions(i,j) = param_ranges(j,1); elseif positions(i,j) > param_ranges(j,2) positions(i,j) = param_ranges(j,2); end end % 计算适应度 fitness = objective_function(positions(i,:), ... simulation_time, frequency_step); % 更新个体最优 if fitness < pbest_values(i) pbest_values(i) = fitness; pbest_positions(i,:) = positions(i,:); end end % 更新全局最优 [min_value, min_index] = min(pbest_values); if min_value < gbest_value gbest_value = min_value; gbest_position = pbest_positions(min_index, :); end convergence_curve(iter) = gbest_value; fprintf('迭代次数: %d, 全局最优值: %.4f, PID: [%.4f, %.4f, %.4f]\n', ... iter, gbest_value, gbest_position(1), gbest_position(2), gbest_position(3)); end % 保存结果 save('pso_result.mat', 'gbest_position', 'gbest_value', 'convergence_curve');

4.2 目标函数怎么和仿真模型联动

目标函数是PSO和一次调频仿真之间的桥梁。每次粒子更新位置后,需要把这组PID参数送入仿真模型,运行一次完整的仿真,再计算性能指标。代码实现有两种方式:

方式一,直接调用Simulink模型。用sim命令传入参数,仿真结束后从输出变量中提取频率偏差曲线,计算ITAE、超调量、调节时间。这种方式适合模型复杂、包含非线性环节的情况,但每次仿真都要启动Simulink引擎,速度较慢。100次迭代乘以30个粒子,就是3000次仿真,实际跑下来大概需要二十分钟左右。

方式二,把传递函数写成MATLAB函数,用lsimstep直接求解。速度快很多,但要求模型能写成线性时不变系统的形式。如果模型里有死区、限幅、速率限制这类非线性环节,处理起来会比较麻烦。

我这次用的是方式一,因为一次调频模型里有调门速率限幅和开度限幅这些非线性环节,Simulink建模更符合实际工况。目标函数代码如下:

function fitness = objective_function(pid_params, sim_time, step_amplitude) % pid_params: [Kp, Ki, Kd] % 将PID参数写入工作区,供Simulink模型使用 assignin('base', 'Kp', pid_params(1)); assignin('base', 'Ki', pid_params(2)); assignin('base', 'Kd', pid_params(3)); % 运行Simulink仿真 simOut = sim('frequency_control_model', 'StopTime', num2str(sim_time)); % 提取频率偏差数据 frequency_deviation = simOut.freq_deviation.Data; time_vector = simOut.freq_deviation.Time; % 计算ITAE absolute_error = abs(frequency_deviation); itae = trapz(time_vector, time_vector .* absolute_error); % 计算超调量 [max_value, ~] = max(absolute_error); overshoot = max_value - step_amplitude; if overshoot < 0 overshoot = 0; end % 计算调节时间(频率偏差进入±0.02Hz死区并保持) tolerance = 0.02; settling_time = sim_time; for k = length(absolute_error):-1:1 if abs(frequency_deviation(k)) > tolerance settling_time = time_vector(k); break; end end % 加权目标函数 fitness = 0.5 * itae + 0.3 * overshoot + 0.2 * settling_time; end

这里有个实操细节要提醒:Simulink模型里的PID模块参数必须设置成变量名(Kp、Ki、Kd),不要填固定数值,否则assignin('base', ...)写入工作区后模型不会响应。我第一次做的时候就是填了固定值,结果粒子群算法跑了半天,适应度值纹丝不动,后来发现PID模块根本没读取工作区变量,白白浪费了一晚上。

5. 优化结果分析与效果对比

5.1 收敛曲线怎么看

算法运行结束后,通过收敛曲线可以判断优化过程是否有效。我这次实验的收敛曲线显示,前20次迭代目标函数值下降非常快,从初始的1.8左右迅速降到0.9附近;20到60次迭代进入缓慢下降区间,在0.7附近波动;大约70次迭代之后基本稳定在0.68左右,说明算法已经收敛到最优解附近。

第一次跑的时候遇到过收敛曲线的下降趋势非常缓慢、甚至抖动的现象,后来排查发现是目标函数里adaptation权重不合适。ITAE、超调量、调节时间这三个指标数量级差异很大,如果不做归一化,量级大的指标会主导寻优方向,导致专利于某一项性能而牺牲其他项。我后来把三个指标先分别除以初始粒子群的平均值,再做加权,效果明显改善。这个处理大家务必重视。

5.2 优化前后的仿真对比

优化得到的PID参数为Kp=2.87,Ki=0.35,Kd=0.52。为了验证效果,我用这组参数和一组传统试凑法得到的参数分别做了一次频率阶跃响应仿真。

传统试凑参数下的频率偏差恢复过程:频率阶跃发生后,最大频率偏差约0.145Hz,调节时间约9.2秒,过程中有明显的功率超调,超调量约12%。PSO优化参数下的响应:最大频率偏差约0.112Hz,调节时间约6.4秒,超调量约5%。两个关键指标都得到明显改善,调节时间缩短了30%左右,超调量下降了超过一半。

从调门开度曲线来看,PSO优化参数的调门动作明显更平滑,没有出现来回振荡的情况。这对于实际机组来说非常有价值。调门频繁动作不仅增加液压执行机构的磨损,还会导致汽轮机进汽参数波动,影响机组运行的稳定性。

6. 粒子群算法做参数优化的三个常见坑及对策

6.1 早熟收敛,陷入局部最优

这是粒子群算法最典型的问题。表现是收敛曲线前几代快速下降,然后停滞不动,最终结果明显偏离理想最优解。我在实验中发现,当种群规模较小时(比如10个粒子),早熟现象出现概率明显增加。

对策主要有四个方向:

  • 增大种群规模,让搜索覆盖更广的参数空间。
  • 采用自适应惯性权重,比如在迭代后期w变大一点,让粒子重新获得全局探索能力。
  • 引入变异操作,每若干代随机重置部分粒子的位置,保持种群多样性。
  • 用多组随机种子重复实验,取最优结果,排除运气因素。这个最简单也最有效,我最终的结果就是跑了5组随机实验,取最优一组。

6.2 参数边界设置不合理

PID参数范围设定对优化效果影响非常大。如果边界太窄,可能直接排除真正的最优解;如果边界太宽,搜索空间过大,收敛速度慢,而且可能搜到不稳定的参数组合。更严重的是,某些参数组合会导致仿真模型不稳定,出现数值发散,适应度变成NaN,粒子群就会崩溃。

我的处理办法是:先用传统整定方法(比如Ziegler-Nichols法)估算一组基准参数,然后以基准参数为中心,上下扩展3到5倍作为搜索边界。这样既保证搜索空间覆盖足够广,又不会让粒子去探索明显不合理的区域。另外在目标函数里加了约束惩罚项,如果参数组合导致仿真发散,直接返回一个很大的适应度值,让粒子远离这个区域。

6.3 目标函数设计不合理导致“偏科”

如果只以ITAE为目标函数,优化出来的参数往往响应速度快,但超调量偏大;如果只以超调量为目标,可能响应很慢。这就是典型的目标函数设计缺陷导致的“偏科”问题。

加权目标函数虽然简单,但权重设置需要结合工程实际反复调试。我建议的做法是:第一轮先用均匀权重跑一次,看各项指标的量级;第二轮根据指标量级调整权重,让各项指标在目标函数中的贡献大致均衡;第三轮再根据实际需求微调——如果更看重快速响应,就加大ITAE的权重;如果更看重机组稳定,就加大超调量的权重。这个过程其实就是典型的“多目标优化标量化处理”,对工程应用场景完全够用。

如果你追求更严谨的多目标处理,可以上NSGA-II这类真正的多目标算法,输出一组Pareto前沿解,让决策者根据偏好选择折中方案。不过这会让算法复杂度明显上升,对于一次调频参数优化这种三个目标、三个变量的低维问题,标量化加权是投入产出比最高的方案。

7. 实操过程中的代码调试与仿真技巧

7.1 先保证仿真模型稳定,再跑优化算法

这是整个项目里我最想强调的一点。粒子群算法的每一代都要调用几十上百次仿真模型,如果模型本身存在数值问题,优化过程会变得极其痛苦。我的做法是:先在Simulink里手动给一组参考PID参数,确认仿真能稳定跑完,频率偏差曲线形态合理,再做算法集成。模型不稳定时跑算法,相当于在一栋地基没打牢的楼上往上盖层——出了问题你根本分不清是算法的问题还是模型的问题。

另外仿真步长的设置要注意,建议设置成固定步长(比如0.01s),不要用变步长。变步长在系统动态变化剧烈时会自动缩小步长,单次仿真时间非常不可控,3000次仿真下来总耗时可能翻好几倍。固定步长虽然单次仿真精度略低,但速度稳定可预期,对于优化任务来说性价比更高。

7.2 MATLAB并行计算工具箱提速

粒子群算法的适应度计算是天然可以并行的——每个粒子的仿真都是独立的,互不影响。用MATLAB的parfor替换掉主循环里的for,可以在多核CPU上把计算速度提升3到5倍。

代码改动很小,把for i = 1:nParticles改成parfor i = 1:nParticles即可。但要注意parfor循环体内部不能依赖循环变量之外的状态,所以需要把positionsvelocities这些变量传进循环体。让我特别提醒一下:第一次用parfor时遇到了工作区变量访问的坑,Simulink模型的assignin('base', ...)写入在并行worker上可能不生效。解决办法是改用set_param函数直接修改模型内的PID模块参数,或者把参数作为Simulink模型的输入端口传入。我后来改成用simIn = Simulink.SimulationInput来传参,一次搞定:

simIn = Simulink.SimulationInput('frequency_control_model'); simIn = simIn.setVariable('Kp', pid_params(1)); simIn = simIn.setVariable('Ki', pid_params(2)); simIn = simIn.setVariable('Kd', pid_params(3)); simOut = sim(simIn);

这种传参方式在parfor环境下工作正常,是并行计算下的推荐做法。

7.3 结果可复现与随机数种子设置

粒子群算法带有随机性,如果不固定随机数种子,即使同样的代码、同样的参数设置,每次运行结果都会有细微差异。在做研究或者需要给项目报告出图时,这个不确定性比较麻烦。

处理方式是在算法运行前加上rng(42);固定随机数种子。这样每次运行结果完全一致,方便复现和对比实验。我在项目里跑多组实验做对比时,会提前生成一组种子列表,循环调用主程序,并且注意区分“固定种子做可复现实验”和“随机种子做统计分析”两种使用场景,分别处理。

8. 一次调频参数优化的进一步扩展方向

这个项目的核心方法论——粒子群算法做PID参数自动寻优——不只能用于一次调频。二次调频(AGC)、励磁调节器参数、PSS电力系统稳定器参数,甚至电机控制里的电流环转速环参数,本质上都是同一个问题:给定被控对象模型和性能指标,用智能优化算法搜索最优控制参数。

我自己接下来的几个扩展方向:

一是从单机一次调频扩展到多机系统,不同机组之间的一次调频参数需要协调优化,以避免机组间出力争夺或者振荡。这时的状态变量就明显变多,模型组合的搜索空间更大,但粒子群算法天然支持多维变量,只需要把每个机组的PID参数拼接成一个超长粒子就行。

二是考虑实际机组运行中的非线性因素,比如调门死区、阀门流量特性非线性、主汽压力变化等,让优化结果更贴近实际工况。这需要在Simulink模型中加入更多非线性环节,目标函数也随之包含工况适应性评价指标。

三是把粒子群算法和深度学习或者强化学习做融合。比如用PSO优化神经网络控制器的初始权重,或者把一次调频过程建模为强化学习环境,用智能体在线自适应调整参数。这个方向目前在学术界比较热,工程落地还有距离,但已经出现一些探索性项目。

如果你正在做类似的参数优化项目,我的建议很直接:先花时间把被控对象模型做扎实,模型错了算法再高级也白搭;目标函数设计要反复和现场工程师确认,不同运行场景下对快速性和稳定性的侧重是不同的;算法参数不用追求复杂的自适应策略,标准PSO加合适的边界约束和随机种子策略已经足够应对大多数工程问题。

说到底,粒子群算法只是工具箱里的一把扳手,真正决定项目价值的,还是你对被控对象、对工程需求的理解深度。工具可以速成,领域知识需要慢慢积累。希望这篇实战记录能给你的参数优化项目提供一些直接能用的思路。

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

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

系统级思维+深度实测:猫王妙播AI智慧收音机SR2 MK2体验

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

作者头像 李华
网站建设 2026/9/6 3:43:18

perf 常用命令速查手册(建议收藏)

Linux 内核自带了一个性能分析工具叫 perf。它能做函数级和指令级的热点采样&#xff0c;也能配合 tracepoint 采集系统调用、网络事件、文件系统操作等内核事件。因为代码就在内核源码树里&#xff0c;算得上是 Linux 平台上最顺手的性能工具了。 原理 perf 基于内核的性能计…

作者头像 李华
网站建设 2026/9/6 3:40:57

直播录播系统搭建:OBS录制与FFmpeg批量处理实战

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

作者头像 李华
网站建设 2026/9/6 3:38:54

vibe coding实战:从能力边界到工具选型的完整指南

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

作者头像 李华
网站建设 2026/9/6 3:34:15

自用串口工具分享

自用串口工具分享 粘土&#xff0c;一个面向嵌入式调试的串口工具&#xff0c;支持 多串口同时连接、自定义常用命令、 自动高亮匹配行、条件触发任务&#xff0c;以及 跨端口联动&#xff08;在 A 口检测到指定字符串时&#xff0c; 向 B 口发送预置命令&#xff09;。命令模…

作者头像 李华
网站建设 2026/9/6 3:33:38

Claude Code辅助Django电力数据可视化全栈开发实践

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

作者头像 李华