新闻详情

新闻详情

首页 / 资讯中心 / 详情

遗传算法求解带爬坡约束与网损的电力系统经济调度Matlab实现

发布时间:2026/10/2 3:49:45来源:尧图网络
遗传算法求解带爬坡约束与网损的电力系统经济调度Matlab实现
做电力系统经济调度的同学应该都遇到过这个尴尬单时段问题用经典的λ迭代法算起来非常顺不考虑爬坡约束不考虑网损几行代码就能收敛。可一旦把场景换成“24小时动态经济调度”相邻两个时段机组出力不能跳变线路上的损耗还得计入传统方法的公式推导立刻变得繁琐还要小心处理各种不等式约束的耦合。我在实际做这个课题时最大的体会是这类问题用遗传算法配合合理的编码和约束修复策略反而比传统解析法更省心。这篇文章就把从建模到Matlab代码实现的全流程讲透包括爬坡约束怎么落到数学公式里、B系数法怎么算输电损耗、遗传算法的种群初始化怎么避开那些“一开始就报废”的个体以及我调参和跑实验时踩过的几个坑。不管你是电力方向的研究生、做调度算法开发的工程师还是刚接触遗传算法想找典型案例练手的Matlab用户这篇文章都能给你一份可以照着抄的完整方案。1. 先把模型建对目标函数、爬坡约束与损耗如何落到数学上很多初学者拿到这个题目第一件事就是打开Matlab写遗传算法这是典型的顺序搞反。优化问题里模型的重要性远大于算法。模型建错算法再花哨也是白搭。1.1 经济调度的基本目标函数与三个基础约束经济调度的目标很直接在满足负荷需求的前提下让所有机组的燃料成本总和最小。每台火电机组的成本函数通常写成关于出力P的二次多项式[ F_i(P_i) a_i P_i^2 b_i P_i c_i ]为什么要用二次函数因为汽轮机的耗量特性曲线在运行区间内近似是一条上凸的二次曲线而且二次函数求导方便各种控制理论里处理起来也顺手。实际工程中也有用分段线性函数的但科研和教学中二次成本函数是绝对主流。基础约束有三个功率平衡所有机组出力之和等于系统总负荷先忽略损耗 [ \sum_{i1}^{n} P_i P_D ]出力上下限每台机组都有技术最小出力和最大出力 [ P_{i,\min} \le P_i \le P_{i,\max} ]机组自身的物理限制也就是爬坡约束这个后面单独说。如果是单一时段的静态经济调度这个模型用拉格朗日乘子法就能解。把所有机组出力对λ求偏导令每一台机组的边际成本相等再迭代修正λ直到满足功率平衡这就是经典的等微增率法。但问题是现实世界中调度员看的绝不是单独一个时段而是未来24小时甚至更长时间尺度。1.2 爬坡约束为什么说它是“时间耦合”约束爬坡约束指的是机组出力在两个相邻调度时段之间的变化速率不能超过物理极限。锅炉和汽轮机系统有热惯性蒸汽参数不可能瞬间改变所以机组从300MW升到350MW需要时间这个速率限制就是爬坡率。写成数学式设调度间隔为Δt机组i的向上爬坡速率和向下爬坡速率分别是UR_i和DR_i那么[ P_{i,t} - P_{i,t-1} \le UR_i \cdot \Delta t ][ P_{i,t-1} - P_{i,t} \le DR_i \cdot \Delta t ]注意这里的下标有两个i是机组编号t是时段编号。也就是说决策变量从单时段的n个变成了n×T个。这带来一个质变变量之间出现了跨时段耦合。你今天这台机组的出力直接影响明天这个时段能调到多少。经典λ迭代法在这种时间耦合约束面前非常吃力因为不能再逐时段独立求解。在Matlab代码里爬坡约束一般不用写成单独的等式或不等式矩阵而是在约束修复函数里直接做判断和裁剪。这个思路后面会展开先记住一句话爬坡约束的本质是“相邻时段之间的出力差有界”代码里就是P(:,t) - P(:,t-1)这个差值的检查。1.3 输电损耗的B系数建模简单但够用输电损耗是电力系统里绕不开的现实问题。功率从发电厂送到负荷中心线路电阻会产生有功损耗。如果调度时完全忽略这部分那么实际运行中总发电出力会小于负荷加损耗系统频率就会往下掉。工程上计算输电损耗有几种方式精确法需要做潮流计算反复迭代计算量大工程近似法里最经典的就是B系数法也叫 Kron 损耗公式[ P_L \sum_{i1}^{n}\sum_{j1}^{n} P_i B_{ij} P_j \sum_{i1}^{n} B_{0i} P_i B_{00} ]写成矩阵形式更简洁[ P_L \mathbf{P}^T \mathbf{B} \mathbf{P} \mathbf{B}0^T \mathbf{P} B{00} ]B系数法的核心思想是把整个网络的损耗近似表示成各机组出力的二次函数。B矩阵是对称的通常由潮流计算或网络分析得到在求解前是已知常数。它的好处是计算量极小精度在中等规模系统里够用缺点是当系统运行点变化很大时固定B系数的近似误差会变大。不过对于经济调度研究和教学演示B系数法是性价比最高的选择。我们把损耗放进功率平衡约束[ \sum_{i1}^{n} P_{i,t} P_{D,t} P_{L,t} ]注意这个约束右侧的损耗本身又是出力的函数。这就意味着等式约束里出现了二次项可行域不再是简单凸的。此时再用经典的等微增率迭代公式推导会变得极其繁琐。这正好是遗传算法发挥优势的地方——它压根不在乎目标函数和约束是什么形式只要能算出适应度值就行。2. 遗传算法求解编码设计、种群初始化与约束修复模型建好之后进入算法设计环节。遗传算法求解这个问题的关键不在算法本身而在于怎么把问题映射成遗传算法能操作的数据结构以及怎么处理那些硬约束。2.1 为什么不用牛顿法或拉格朗日法而选遗传算法先说结论不是传统方法不能用而是遗传算法在这个场景下更省事。考虑输电损耗后目标函数虽然仍是二次的但功率平衡约束里出现了出力的二次项拉格朗日函数对λ的偏导已经不是线性方程求解需要嵌套迭代。再加上爬坡约束形成的时间耦合传统方法每一步都要重新推导公式工程实现极其痛苦。遗传算法属于启发式智能优化算法不依赖梯度信息。它的工作方式是维护一群候选解通过选择、交叉、变异不断进化用适应度函数引导搜索方向。你只需要把约束通过某种方式转成适应度的一部分剩下的交给迭代。对于非凸、非线性、含耦合约束的调度问题GA天然合适。当然GA的代价是计算量大、结果有随机性。但在离线调度场景中这些都不算致命。做研究更是如此重点是快速搭建一个能跑的框架把问题研究透。2.2 实数编码与“爬坡可行化”初始化遗传算法里一个核心决定是编码方式。二进制编码在简单的函数优化里常见但对经济调度这种连续变量问题二进制编码有两个问题一是精度受位长限制二是交叉变异后很容易产生不可行解。我强烈建议用实数编码也就是一个个体直接就是一组连续数值。具体到这个题目决策变量是所有机组在所有时段的出力总维数是 nGen × nT。个体x就是一个行向量长度为 nGen × nT。为了方便后续处理在目标函数或修复函数里把这个向量reshape成 nGen 行、nT 列的矩阵 P第 i 行第 t 列就是机组i在时段t的出力。初始化时一个常见的错误是直接用上下限之间的均匀随机数生成整个种群。如果是单时段问题这样没问题多时段问题这样做的后果是几乎每个个体在相邻时段上的出力差都超过爬坡限制种群质量极差罚函数压力巨大进化过程非常慢。我的做法是“爬坡可行化初始化”第一个时段在每台机组的出力上下限内随机生成。后续时段基于上一个时段的出力在爬坡允许的变化范围内随机生成。具体是 [ P_{i,t} \sim U(\max(P_{i,\min}, P_{i,t-1} - DR_i), \quad \min(P_{i,\max}, P_{i,t-1} UR_i)) ]检查上下限和爬坡约束是否同时满足。这样初始化出来的每一个体天然满足出力上下限和爬坡约束只剩下功率平衡约束需要处理。这个细节对收敛速度的影响巨大我实测过同样的迭代次数下爬坡可行化初始化比纯随机初始化最终成本能低好几千美元。2.3 约束修复函数比单纯罚函数好用得多的方案遗传算法处理约束教科书里讲得最多的是罚函数法在目标函数后面加一个大数乘以违反量。这个方法实现简单但如果罚系数设得太小最终解会明显违反约束设得太大适应度函数会出现很深的“峡谷”种群难以收敛。我推荐的策略是“修复为主罚函数兜底”。在每次评估适应度之前先调用一个Repair函数把个体强行拉回可行域附近。Repair函数的逻辑分三步第一步上下限裁剪。把超过上下限的出力直接clip到边界上。第二步爬坡修复。从第2个时段开始逐时段检查如果 (P_{i,t} P_{i,t-1} UR_i)则令 (P_{i,t} P_{i,t-1} UR_i)如果 (P_{i,t} P_{i,t-1} - DR_i)则令 (P_{i,t} P_{i,t-1} - DR_i)。这里的顺序是从前往后扫。有读者可能会问从后往前扫会不会更好理论上可以双向扫描但实际中从前往后更符合物理时间顺序而且实现简单。一步就能让整个序列满足爬坡约束。第三步功率平衡修复。计算当前个体在各时段的出力总和对比该时段负荷与损耗之和求出不平衡量。如果出力不足就在还有向上爬坡余量和最大出力余量的机组中补足如果出力过多就在还有向下调节空间的机组中减掉。补功率的时候选哪台机组工程直觉是选边际成本最低的机组优先加出力。严格来说这又是个子优化问题但代码里不必太精细随机选一台有余量的机组多迭代几轮通常就能把不平衡量压到很小。极少数情况下修复后仍有微小不平衡比如所有机组都顶上界了这时候再交给罚函数兜底。这套“修复罚函数”的组合方案比纯罚函数稳健得多。我可以负责任地说如果只写罚函数不改个体遗传算法在爬坡约束下很容易陷入“所有个体都被罚分、选择压力失去意义”的死局。3. Matlab代码逐段拆解从主循环到核心算子模型和算法思路清楚了现在上代码。下面这段流程我在多个版本里试过结构清晰适合扩展。无论你用的是哪个版本的Matlab主代码都不用改GA的底层逻辑和工具箱版本没太大关系。3.1 算例参数与数据结构准备我用的测试系统是经典的三机组系统机组参数是电力系统文献里的常用数据方便和其他算法结果对照。参数如下机组a ($/MW²h)b ($/MWh)c ($/h)Pmin (MW)Pmax (MW)UR/DR (MW/h)G10.0015627.9256115060050G20.0019407.8531010040040G30.0048207.97785020030调度周期取24小时Δt1小时所以UR和DR的数值直接代表每小时的MW变化能力。负荷曲线取一条典型日负荷序列白天高、深夜低最低500MW最高740MW。B系数矩阵取三机系统的经典值B [0.000030 0.000030 0.000020; 0.000030 0.000060 0.000020; 0.000020 0.000020 0.000060]; B0 zeros(3, 1); B00 0;有了这些数据就可以开始写代码。我习惯把所有参数放在一个结构体里后续函数都从结构体取数清爽不易出错。%% 数据与参数 clear; clc; rng(42); % 固定随机种子方便复现和对比 nGen 3; nT 24; nPop 200; % 种群规模 MaxIt 500; % 最大迭代次数 pc 0.85; % 交叉概率 pm 0.08; % 变异概率 nElite 2; % 精英保留个数 lambda_pen 1e6; % 罚函数系数 data.gen [ 0.001562 7.92 561 150 600 50 50; 0.001940 7.85 310 100 400 40 40; 0.004820 7.97 78 50 200 30 30; ]; data.PD [520 510 500 505 515 550 600 650 705 720 730 740 735 730 720 710 700 680 655 645 630 610 580 550]; data.B B; data.B0 B0; data.B00 B00; data.nGen nGen; data.nT nT;3.2 修复函数与适应度函数怎么实现修复函数是整个程序里最关键的产出。这里给出一个完整可跑的版本框架function P Repair(P, data) nGen data.nGen; nT data.nT; Pmin data.gen(:,4); % 列顺序按参数表 Pmax data.gen(:,5); UR data.gen(:,6); DR data.gen(:,7); % 第一步上下限裁剪 P min(max(P, repmat(Pmin, 1, nT)), repmat(Pmax, 1, nT)); % 第二步爬坡约束修复从前往后 for t 2:nT P(:,t) min(P(:,t), P(:,t-1) UR); P(:,t) max(P(:,t), P(:,t-1) - DR); end % 第三步功率平衡修复逐时段补偿不平衡量 for t 1:nT PL P(:,t) * data.B * P(:,t) data.B0 * P(:,t) data.B00; imbalance sum(P(:,t)) - (data.PD(t) PL); cnt 0; while abs(imbalance) 0.5 cnt 50 cnt cnt 1; if imbalance 0 % 需要减出力选有下调余量的机组 candidate find((P(:,t) - Pmin) 0.1 (P(:,t-1) DR - P(:,t) 0.1), 1, first); % t1时没有前一时段跳过爬坡只按上下限考虑 if t 1 candidate find((P(:,t) - Pmin) 0.1, 1, first); end if isempty(candidate) break; end delta min(imbalance, P(candidate,t) - Pmin(candidate)); P(candidate,t) P(candidate,t) - delta; else % 需要加出力选有上调余量的机组 candidate find((Pmax - P(:,t)) 0.1 (P(:,t-1) UR - P(:,t) 0.1), 1, first); if t 1 candidate find((Pmax - P(:,t)) 0.1, 1, first); end if isempty(candidate) break; end delta min(-imbalance, Pmax(candidate) - P(candidate,t)); P(candidate,t) P(candidate,t) delta; end PL P(:,t) * data.B * P(:,t) data.B0 * P(:,t) data.B00; imbalance sum(P(:,t)) - (data.PD(t) PL); end end end这个修复函数写得比较实在没有过度优化。实际应用中你会发现大部分个体的不平衡量在第一轮就能压到0.5MW以内少数个体需要循环几次。循环次数上限设50防止个别极端个体死循环。适应度函数就简单了总成本加罚函数function cost Fitness(x, data) P reshape(x, data.nGen, data.nT); a data.gen(:,1); b data.gen(:,2); c data.gen(:,3); totalCost sum(sum(a .* P.^2 b .* P c)); % 各时段的损耗 PLoss zeros(1, data.nT); for t 1:data.nT PLoss(t) P(:,t) * data.B * P(:,t) data.B0 * P(:,t) data.B00; end % 功率平衡违反量修复后应接近0但保险起见仍保留罚函数 violation sum(max(0, abs(sum(P,1) - (data.PD PLoss)))); cost totalCost lambda_pen * violation^2; end为什么要在修复之后还保留罚函数因为修复函数是启发式的极端情况下可能无法把不平衡量完全降到0。罚函数作为兜底可以保证那些修复不彻底的个体不会被选中从而推动种群向“可修复”区域进化。3.3 选择、交叉、变异和精英保留的具体写法主循环的结构是这样的%% 初始化种群 for i 1:nPop P InitIndividual(data); % 用爬坡可行化初始化 x reshape(P, 1, []); pop(i).X x; pop(i).X reshape(Repair(reshape(x, data.nGen, data.nT), data), 1, []); pop(i).Cost Fitness(pop(i).X, data); end bestCosts zeros(MaxIt, 1); %% 主循环 for it 1:MaxIt % 精英保留 [~, idx] sort([pop.Cost]); newpop pop(idx(1:nElite)); % 生成子代 while length(newpop) nPop % 锦标赛选择两个父代 p1 pop(TournamentSelect(pop, 4)); p2 pop(TournamentSelect(pop, 4)); % 交叉算术交叉 if rand pc alpha rand; c1.X alpha * p1.X (1 - alpha) * p2.X; c2.X alpha * p2.X (1 - alpha) * p1.X; else c1.X p1.X; c2.X p2.X; end % 变异高斯变异 if rand pm sigma 0.05 * (repmat(max(reshape(c1.X, data.nGen, data.nT), [], 2) - ... % 简化写法 min(reshape(c1.X, data.nGen, data.nT), [], 2), 1, data.nT)); c1.X c1.X sigma(:).* randn(size(c1.X)); end if rand pm c2.X c2.X 0.05 * (c2.X - min(c2.X)) .* randn(size(c2.X)); end % 修复并计算适应度 c1.X reshape(Repair(reshape(c1.X, data.nGen, data.nT), data), 1, []); c1.Cost Fitness(c1.X, data); c2.X reshape(Repair(reshape(c2.X, data.nGen, data.nT), data), 1, []); c2.Cost Fitness(c2.X, data); newpop [newpop c1 c2]; end % 截断到种群规模 pop newpop(1:nPop); bestCosts(it) min([pop.Cost]); if mod(it, 50) 0 fprintf(Iteration %d, Best Cost %.2f\n, it, bestCosts(it)); end end锦标赛选择函数function idx TournamentSelect(pop, k) candidates randi([1 numel(pop)], 1, k); [~, best] min([pop(candidates).Cost]); idx candidates(best); end这个主循环里有一个细节变异部分我用了两种写法示意实际工程中建议统一用repmat构造每台机组的变异步长向量核心思想是变异幅度应该和该变量的取值范围匹配而不是用全局统一步长。三台机组的Pmin/Pmax差异很大G1能到600MWG3最大只有200MW如果用统一步长小机组很容易被扰动得过狠。交叉概率0.85、变异概率0.08、种群规模200这套参数在我的实验里表现比较均衡。那500次迭代在三机24时段问题里大概十几秒跑完完全可接受。4. 结果分析、参数调优与踩坑记录代码能跑通只是第一步。更重要的能力是判断结果是否合理、是否还能优化。这一节把我实际跑实验时的分析思路和问题记录整理出来。4.1 收敛曲线和出力曲线怎么看跑完遗传算法第一时间画收敛曲线figure; plot(bestCosts, LineWidth, 2); xlabel(迭代次数); ylabel(最优总成本 ($)); title(GA收敛曲线); grid on;正常情况下前50代成本下降最快之后逐渐趋于平稳。如果曲线在迭代后期还剧烈震荡大概率是变异率太大或罚函数系数不合适。如果曲线很早就不再下降可能是种群早熟也就是所有个体在几代之内变得过于相似失去了探索能力。还要把最优个体的出力矩阵画出来横轴时段纵轴出力三条线分别代表三台机组。这一步非常重要因为它能直接暴露模型问题。有一次我发现G3在夜间阶段一直贴在50MW下限但G1、G2也都没有满发理论上G3这种高成本机组压在下限是对的但我仔细看了一眼负荷发现凌晨负荷511MW三台机组总出力却是560MW损耗才20MW那这多出来的30MW哪来的检查之后发现是修复函数第三步在t1时选机组逻辑有bug导致补偿循环提前break。这类问题只有看出力曲线才能发现。只看收敛曲线和总成本很容易把错误结果当成最优解。4.2 几组对比实验的设计思路做研究不能只跑一组参数就交差。我建议至少跑四个场景场景A既不考虑损耗也不考虑爬坡约束最原始的静态经济调度场景B只考虑输电损耗不考虑爬坡场景C只考虑爬坡约束不考虑损耗场景D损耗和爬坡都考虑完整模型我在同一个随机种子下跑完的典型结果如下场景总成本 ($)总损耗 (MWh)爬坡约束说明A约 185,300忽略不满足各时段独立最优但不物理B约 192,800约 680不满足成本上升约4%损耗代价明显C约 187,500忽略满足爬坡约束迫使调度提前安排成本略升D约 195,200约 720满足完整场景成本最高但结果最真实注意成本数值会因随机种子不同有几百分之一的浮动关键是看趋势。损耗带来的成本增量大约是几个百分点这个量级和真实系统的经验数据是吻合的——因为平均负荷600MW左右时网损大约占负荷的2%~5%。爬坡约束看起来增加的成本不大但它会改变所有机组的出力轨迹尤其在高负荷爬坡时段如果不提前增发后半段就来不及。4.3 常见问题排查速查表现象可能原因解决方案收敛曲线剧烈震荡变异率过大或罚函数系数过小调低变异率到 0.03~0.05增大罚系数最终结果功率不平衡修复函数没生效罚函数兜底不够检查Repair第三步循环罚系数设到 1e6 以上爬坡约束反复被破坏交叉或变异后没有调用Repair确保所有新个体在计算适应度前都经过Repair早熟收敛结果很差种群太小多样性不足nPop 至少100加大交叉率到0.9运行时间过长嵌套循环太多没有向量化损耗计算改用矩阵乘法多时段并行独立计算每次运行结果差异大随机性导致用 rng 固定种子或跑20次取最优和统计均值这里的每一条都是我实际遇到过的。尤其是“交叉变异后忘记Repair”这是刚写GA时最容易犯的错误。你写好了Repair函数也在初始化时调用了但子代生成阶段没调用结果就是最优个体在每一代重新出现爬坡超标而成本看起来还挺低实际是个假解。4.4 我实测过程中踩过的几个坑第一个坑是损耗公式写错。B系数矩阵是对称的损耗表达式是(\mathbf{P}^T\mathbf{B}\mathbf{P})一开始我图省事把它写成sum(sum(B .* P .^2))结果损耗被严重低估。矩阵二次型展开后有很多交叉项逐元素乘法完全不是一回事。后来凡是涉及B系数的函数我都会先在单点手工验证一遍比如假设所有机组出力都是100MW手算损耗值再和代码输出对比。第二个坑是成本函数的量纲。三台机组的a、b、c系数跨度很大a是10的负3次方量级c是几百量级。罚函数系数如果只设1000单位不匹配结果就是约束形同虚设。我后来统一把罚系数设为1e6并检查功率平衡违反量的量纲确保罚项在数值上显著大于正常成本波动。第三个坑是变异步长的全局统一问题。前面提过G1和G3的范围差异很大用同样的sigma产生随机扰动G3很容易被推到边界然后又被clip回来实质上丢失了变异效果。后来改成按每台机组的Pmax-Pmin比例生成sigma效果立刻改善收敛速度提高了接近一倍。第四个坑是调试效率。24时段问题的解空间很大每次调完参数跑完整500次迭代发现问题再改很费时间。我的经验是先从3机3时段的迷你case开始把输出矩阵打出来一行行检查爬坡差值。迷你case跑通了再扩展到24时段出错的概率会低很多。这个小技巧帮我省了至少一周的调试时间。最后分享一个实用的小技巧算是给已经读到这里的读者一个额外收获。遗传算法跑完一次最优解通常只是一个局部最优因为GA本质是随机搜索。我一般会固定随机种子跑5次保存每次的最优成本和最优个体然后取成本最低的那次作为最终结果。如果5次结果相差很大说明参数没调好而不是跑的次数不够。反之如果5次结果非常接近那基本可以确认解的稳定性没问题可以放心写进论文或报告里。另外如果后续想把这个方法扩展到更大的系统比如几十台机组或考虑机组组合问题代码框架不用大改主要是把数据部分扩充再加一个机组启停的0-1变量编码。遗传算法对这类扩展的容忍度很高这也是它在这个领域比传统方法好用的原因之一。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

基于CLIP的1750个AI创业公司首页视觉风格聚类与检索 2026/10/2 5:34:54

基于CLIP的1750个AI创业公司首页视觉风格聚类与检索

1. 从1750个AI创业公司首页里,我到底想看出什么门道第一次冒出"把上千个AI创业公司首页摆在一起看"这个念头,是在连续刷了几十个同类产品落地页之后。那种感觉很奇怪——明明是不同的公司、不同的赛道、不同的创始人,但页面滑下来&…

阅读更多 →
LangGraph多Agent协作实战:TradingAgents架构拆解与工程落地 2026/10/2 5:34:54

LangGraph多Agent协作实战:TradingAgents架构拆解与工程落地

1. 从"10.7万Star"说起:这个多Agent炒股项目到底在解决什么问题第一次看到"TradingAgents"这个项目的时候,我的反应和大多数人一样——又是一个蹭AI炒股热度的玩具。但翻完它的架构文档和源码之后,我改主意了。这个项目真…

阅读更多 →
瑞利、莱斯与Jakes模型推导及Python仿真实现 2026/10/2 5:34:48

瑞利、莱斯与Jakes模型推导及Python仿真实现

简介:这份文档面向无线通信、移动信道建模方向的学习者与研究人员,系统梳理多径衰落中瑞利分布、莱斯分布与Jakes模型的数学推导过程。内容从多径传播的物理成因切入,逐步推导包络概率密度函数,并结合MATLAB仿真验证理论曲线&…

阅读更多 →
onbeforeunload 离开拦截边界与未保存数据保存方案 2026/10/2 5:34:48

onbeforeunload 离开拦截边界与未保存数据保存方案

后台编辑页填了四十多分钟的东西,手一抖点了刷新,白屏回来全没了。这种事故我在三个不同的项目里都遇到过,每次复盘都会绕回同一个话题:onbeforeunload到底能不能可靠地把用户拦下来。答案是有条件能——onbeforeunload是浏览器提…

阅读更多 →
开源驾驶舱openrig:铝型材DIY模拟赛车座舱组装全攻略 2026/10/2 5:34:48

开源驾驶舱openrig:铝型材DIY模拟赛车座舱组装全攻略

如果你玩模拟赛车,早晚会碰到一个尴尬的阶段:市售成品驾驶舱,便宜的两千块,一踩刹车整个架子往前窜,方向盘基座位置飘得跟橡皮一样;靠谱点的,价格直奔五位数,本质上还是一堆铝型材加…

阅读更多 →
从零自建OpenRig:开放式测试架的设计与组装实战 2026/10/2 5:34:48

从零自建OpenRig:开放式测试架的设计与组装实战

干这行这么多年,折腾过的机箱一只手数不过来,从海景房到全塔侧透,最后反而回归到了最原始的形式——开放式测试架。也就是这次要聊的openrig项目。说白了,OpenRig就是自己搭建一个完全开放的硬件承载平台,没有侧板、没…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉