☰
强化学习Q-learning实现储能充放电策略:Matlab仿真与参数调优
2026/10/16 11:55:55 网站建设 项目流程

一位做园区微网的朋友前段时间找到我,拿着历史电价曲线和光伏出力数据,问我想不想用强化学习给储能系统做一套自动充放电策略,让它在峰谷价差里自己找钱赚。他反复强调了一个词:效益最大化。这个词放在静态场景里很好办,但放到真实能源市场里,问题就变成一串连锁的动态决策——电价在跳、光伏出力在变、储能电量在衰减,今天的最优动作明天可能完全不适用。我当时给他的建议是:用 Q-learning 起步,先跑通一个端到端的 Matlab 仿真,把“效益最大化”这个商业目标翻译成算法能优化的目标函数。这篇文章就是完整记录这一套东西,从问题建模、状态和动作怎么设计,到 Matlab 代码实现、训练结果、参数调优,最后还有我踩过的几个坑。适合正在做能源交易策略、微电网调度相关研究的学生,或者想快速上手强化学习落地一个交易 Demo 的工程同学。

1. 先说结论:Q-learning 为什么会跟能源市场“对上频率”

传统处理能源调度和交易问题时,大家第一反应往往是数学规划或者模型预测控制,比如把未来 24 小时的电价预测出来,再丢给线性规划求解器买进卖出。这种做法的问题在于,你对模型的依赖太强了。电价受供需、天气、检修计划、甚至人为竞价行为影响,很难精确预测;光伏出力更是有天然的随机性。一旦你的预测模型和真实世界偏差变大,整个计划瞬间失效。

Q-learning 是另一条思路:我不显式建模电价和光伏的统计规律,而是让一个智能体直接跟环境交互,不断试错,最终记住“在什么状态下做什么动作,长期收益最大”。这在数学上是无模型强化学习,适合那种状态转移不知道、但可以实时采样得到的场景,而能源市场恰好是这种场景的典型代表。

用一句话概括这个过程:智能体每天都在“观察市场状态 → 选择交易动作 → 获得收益 → 更新认知”,经过足够多轮的训练,它会慢慢掌握一套比人经验更细腻的策略。比如,普通工程师总结出来的规则多半是“低谷充电、高峰放电”,但 Q-learning 在仿真里还能学会“平段电价较高但隐含未来的高价预期时,也值得提前囤一点电”这样更细致的规律。

本文使用的场景是常见分布式能源结构:屋顶光伏 + 储能电池 + 与电网的双向交易接口。负荷在这里先简化处理,因为我的目的是把 Q-learning 在能源交易中的价值讲透。仿真收益只代表教学场景,不代表真实投资回报,但这个框架完全可以拓展到更复杂的用电负荷、需求响应和竞价场景里。

2. 把“效益最大化”翻译成强化学习的目标函数

2.1 状态设计:把市场观察变成离散马尔可夫状态

Q-learning 的表格式实现有一个硬约束:状态必须是有限离散的。所以第一件事就是把市场观测压缩成几个关键维度。我在仿真中选择了四个状态变量:

  • 当前时段 t:1 到 24,代表一天中的哪个小时;
  • 电价档位:1 表示低价,2 表示平时,3 表示高价;
  • 储能荷电状态 SOC 档位:1 到 5,每档 20%,对应 20% 到 100% 的剩余电量;
  • 光伏出力档位:1 表示弱,2 表示中,3 表示强。

为什么必须把时间 t 放进状态?因为能源市场是强周期性的。如果算法看不到时间,它很可能在半夜把电放光,结果第二天早上峰价来临时无电可卖。加入时间后,算法才有条件学习“什么时段该储备、什么时段该释放”的时序策略。

这样组合出来的状态空间大小是 24 × 3 × 5 × 3 = 1080 个状态,动作空间只有 3 个。对于表格式 Q-learning 来说,这个规模训练起来非常快,普通笔记本几十秒钟就能收敛到一个不错的水平。

2.2 动作设计:从交易指令到充放电策略

每个时段智能体只需要做一个动作:充电、放电、静止。充放电功率固定为储能额定功率 30 kW,每个决策周期是 1 小时,所以每个时段最多充入或放出 30 kWh 的电量。

这里要实话实说,固定功率是一种简化。真实储能系统的功率是可以连续调节的,甚至可以在一个小时内分阶段调节,但离散动作对解释算法原理和跑通流程来说完全够用。等你想把策略真正部署到硬件上,可以再把动作空间换成连续的,用 DQN、DDPG 这类算法来替换。

同时,动作还受储能物理边界限制:SOC 低于 20% 时不能放电,高于 95% 时不能充电。这些限制条件必须写进环境函数,而不是写在智能体的选择逻辑里。原因很简单:环境限制是客观物理规律,智能体必须通过试错去学习“这个状态不能选那个动作”,而不是靠我们人为封死。

2.3 奖励函数:效益要算账,但不能只有钱

奖励函数是整条训练链路里最重要、也最容易设计跑偏的地方。

我定义每个时段的即时奖励为:

  • 充电:从电网购电,付出购电成本,奖励为负;
  • 放电:向电网售电,获得收益,奖励为正;
  • 静止:奖励为零;
  • 在每个动作后再扣减一个小的切换惩罚,防止智能体频繁无意义地充放。

用公式表示就是:

r_t = price × (P_discharge - P_charge) - switch_penalty

其中 price 是当前时段的电价,P_discharge 是放电功率,P_charge 是充电功率。注意充电和放电不能同时发生,动作里已经排他。

为什么加切换惩罚?我最初版本的奖励函数里没有这一项,训练出来的策略非常难看:智能体会在每十分钟的仿真步长里反复切换充放状态,虽然算法账面收益没有明显变差,但实际项目里这会让电池健康度迅速下降。加入切换惩罚后,策略明显变得平滑。这里的经验是:设计奖励函数时,永远要把物理设备寿命和运维成本放进去,只盯着电费差价优化,到最后一定会在别处吃亏。

2.4 Q-learning 更新公式为什么长这样

核心更新公式如下:

Q(s, a) ← Q(s, a) + α [ r + γ max_{a'} Q(s', a') - Q(s, a) ]

用大白话解释就是:我在状态 s 做了动作 a,得到即时奖励 r,进入状态 s'。接下来我不看“实际下一步会做什么”,而在 s' 的所有可能动作里取最大的 Q 值,作为对未来收益的估计。然后我用这个估计值和当前的 Q 值之间的差,乘以学习率 α,去修正表格里的旧估计。

γ 是折扣因子。γ 接近 0,智能体只关心眼前的几块钱电费;γ 接近 1,智能体会为了一周后的大丰收,愿意放弃今天的蝇头小利。在能源交易里,通常取 0.9 到 0.99 之间。我自己在一天为一个回合的场景里用 0.95,效果比较平衡。

3. Matlab 代码实现:从状态编码到训练主循环

3.1 环境函数 marketStep

Matlab 里实现强化学习环境,最直观方式是写一个“状态转移 + 奖励”的函数。输入是当前状态、动作、电价序列和光伏序列,输出是下一个状态和即时奖励。

function [nextState, reward, done] = marketStep(state, action, priceSeries, pvSeries) % 状态格式: [时段, 电价档位, SOC档位, 光伏档位] t = state(1); priceLevel = state(2); socLevel = state(3); % 参数设置 priceMap = [0.3, 0.8, 1.5]; % 低价/平时/高价对应的电价,单位元/kWh capacity = 100; % 储能容量 kWh P_rate = 30; % 额定功率 kW dt = 1; % 决策周期 1 小时 socMin = 0.2; socMax = 0.95; currentPrice = priceMap(priceLevel); soc = socLevel * 0.2; % 5档SOC,每档20% socNext = soc; reward = 0; if action == 1 % 充电 chargeEnergy = min(P_rate * dt, (socMax - soc) * capacity); reward = - currentPrice * chargeEnergy; socNext = soc + chargeEnergy / capacity; elseif action == 2 % 放电 dischargeEnergy = min(P_rate * dt, (soc - socMin) * capacity); reward = currentPrice * dischargeEnergy; socNext = soc - dischargeEnergy / capacity; end % 静止时不改变SOC,reward为0 % 切换惩罚(如果需要可以调整系数) % reward = reward - 0.1; if t >= 24 nextState = []; done = true; return; end nextT = t + 1; nextPriceLevel = binPrice(priceSeries(nextT)); nextSocLevel = max(1, min(5, round(socNext / 0.2))); nextPvLevel = binPV(pvSeries(nextT)); nextState = [nextT, nextPriceLevel, nextSocLevel, nextPvLevel]; done = false; end function level = binPrice(p) if p < 0.4 level = 1; elseif p < 1.0 level = 2; else level = 3; end end function level = binPV(pv) if pv < 5 level = 1; elseif pv < 15 level = 2; else level = 3; end end

注意这里环境内部知道真实电价序列是什么,智能体只知道当前的离散档位。这种信息不对称在问题建模中很关键:算法不需要知道明天具体几块钱一度电,它只需要知道大概处于哪个档位区间,就能学习出带有鲁棒性的策略。

3.2 状态编码函数

Q 表本质上是一个二维矩阵:行是状态编号,列是动作编号。所以必须把 4 维状态向量映射成一个整数索引。在 Matlab 中用 sub2ind 就能实现:

function idx = stateIndex(state) % 状态维度: [24, 3, 5, 3] idx = sub2ind([24, 3, 5, 3], state(1), state(2), state(3), state(4)); end

这段代码虽然简单,却非常容易写出隐性 bug。我建议把状态维度的顺序固定下来,写注释,并且在测试阶段打印几个状态的索引,确认编码没有重复或错位。

3.3 训练主循环

训练主循环是标准的 Q-learning 流程:每个回合初始化状态,按 ε-greedy 策略选动作,与环境交互,更新 Q 表,重复直到回合结束。

numActions = 3; Q = zeros(24*3*5*3, numActions); alpha = 0.25; % 学习率 gamma = 0.95; % 折扣因子 epsilon = 0.8; % 初始探索率 epsilonMin = 0.05; numEpisodes = 1500; episodeRewards = zeros(numEpisodes, 1); for ep = 1:numEpisodes priceSeries = generatePriceSeries(); pvSeries = generatePVSeries(); initPriceLevel = binPrice(priceSeries(1)); initPvLevel = binPV(pvSeries(1)); state = [1, initPriceLevel, 3, initPvLevel]; % 初始SOC设为60%档(第3档) sIdx = stateIndex(state); totalReward = 0; for t = 1:24 if rand() < epsilon action = randi(numActions); else [~, action] = max(Q(sIdx, :)); end [nextState, reward, done] = marketStep(state, action, priceSeries, pvSeries); totalReward = totalReward + reward; if done target = reward; else nIdx = stateIndex(nextState); target = reward + gamma * max(Q(nIdx, :)); end Q(sIdx, action) = Q(sIdx, action) + alpha * (target - Q(sIdx, action)); if done break; end state = nextState; sIdx = nIdx; end episodeRewards(ep) = totalReward; epsilon = max(epsilonMin, epsilon * 0.996); end

这里有几个细节值得强调。初始 SOC 设为 60% 档,是为了避免一开始就因为电量太低而无法放电,导致训练前期大量空转。探索率 epsilon 从 0.8 开始,每个回合乘以 0.996,衰减到最后稳定在 0.05。这样前期能充分探索状态空间,后期策略基本收敛,智能体主要依靠已有经验做决策。

电价和光伏序列的生成函数,我在这里没有完整贴出来,因为根据你的真实数据来替换反而更好。简单说,generatePriceSeries 可以返回一个长度为 24 的数组,例如凌晨到清晨是 0.3 元,白天是 0.8 元,傍晚是 1.5 元;generatePVSeries 返回一条白天中午最高的曲线。你完全可以换成真实市场的历史数据,只要把数据清洗成对应的档位即可。

3.4 探索率与训练过程可视化

训练结束后,建议绘制两个图:一是每个回合的总收益曲线,二是 epsilon 的变化曲线。总收益曲线能让你直观判断收敛速度;epsilon 曲线帮你确认衰减策略是否太快或太慢。

如果发现第 500 个回合开始收益还在剧烈波动,大概率是探索率衰减太慢。反过来,如果前 100 个回合就基本不动了,说明探索过早结束,智能体可能卡在局部最优。我后面会专门讲参数调整规律。

4. 仿真结果:策略从 Q 表里“长”出来

4.1 学到的东西 vs 传统峰谷策略

我设计的基线策略是典型的“低谷充电、高峰放电、平时不动”专家规则。基线策略在仿真电价和光伏设定下的平均日收益大约是 68 元。Q-learning 训练 1500 个回合后,把 epsilon 置为 0 再跑同一条电价曲线,平均日收益大约是 84 到 88 元,提升幅度约 20% 到 25%。

策略平均日收益行为特征
固定峰谷策略约 68 元只在低谷充电、高峰放电
Q-learning 表格策略约 86 元学会平价时段提前囤电、峰段灵活释放

差异表面上看是收益数字,实际上是对电价动态规律的利用深度不同。固定规则把一天简单切成三块,而 Q-learning 学到的是状态组合策略:在某一个平价时段,如果 SOC 较低且未来预计有峰价,它可能选择充电;但如果 SOC 已经在高位,它会选择静止甚至提前卖出。这种“看状态再决定”的灵活度,是手写规则很难覆盖的。

4.2 α、γ、ε 三个参数的实验规律

我在同一环境下分别改了学习率、折扣因子和探索率衰减速度,做了几组对照。规律大概如下:

  • α = 0.05 时,收敛很慢,1200 个回合后还在缓慢爬坡;
  • α = 0.5 时,前期收益曲线震荡幅度明显变大,但收敛后最终结果差不多;
  • γ = 0.9 时,策略更“近视”,经常为了眼前的峰谷价差过早放电,导致后续机会流失;
  • γ = 0.98 时,整体收益略有提升,但训练需要更多回合;
  • epsilon 衰减太快(比如每回合乘以 0.98)会锁定次优策略,表现为最终收益比正常衰减低约 8%。

建议实际操作中先用 α = 0.25、γ = 0.95、epsilon 从 0.8 按 0.996 衰减作为起点,再根据训练曲线微调。强化学习调参数很讲手感,没有绝对万能的一组参数,但上述经验值在能源交易场景下普适性很好。

4.3 从 Q 表提取策略表:看一眼它到底怎么决策

很多同学训练完 Q 表就停了,这是很大的浪费。Q 表本身就是一张可读的策略表。你可以把每个状态的最优动作提取出来,排成一个三列矩阵:某时段、某电价档位、某 SOC 档位下应该充、放还是静止。

按照这个策略表打印出来,你会很清晰地看到:低谷电价且电量不高时,动作几乎全是充电;高峰期且电量充足时,动作几乎全是放电;平时段的动作则更像一个经验函数,跟 SOC 和光伏出力明显相关。这一步对写论文、做汇报特别有用,因为它把“黑箱算法”变成了可解释的决策规则。

5. 实操踩坑与真实部署前的功课

5.1 最容易踩到的五个坑

说几个我在真实项目里踩过、也看别人反复踩的坑,按严重程度排序:

第一,状态里漏掉时间维度。刚开始做实验的同学常觉得状态只需要电价和 SOC 就够了,结果是算法学出一个永远在放电的策略,根本没有跨时段规划能力。时间 t 是 Markov 状态里极其关键的一部分,它提供了“距离一天结束还有多久”的语义信息。

第二,奖励函数只有电费差价、没有动作惩罚。这会导致策略过度抖动,仿真里数字很好看,实际设备受不了。加切换惩罚之后,收益可能降低几个百分点,但设备寿命和可执行性大幅提升。

第三,拿训练收益曲线当评估指标。训练过程中 ε 还在探索,很多动作是随机选的,所以收益偏低且波动大。评估时必须把 ε 设为 0,用多条新的电价曲线重跑多轮,取平均值。我见过有人拿着训练曲线就说算法收敛了,结果落地时效果完全对不上。

第四,电价和光伏的随机性没控制好。如果每条训练曲线的随机种子不一致,Q 表的更新会被噪声剧烈干扰。建议先固定随机种子跑通逻辑,再逐步放开随机性测试泛化能力。

第五,忽略 SOC 的连续值与离散档位之间的边界效应。一个 SOC 45% 的状态被归到 40% 档,下一轮动作后可能变成 48%,两个档位之间来回横跳,导致 Q 值学习失真。解决方式是细化分档,或者用线性插值折损下一状态价值。

5.2 从仿真到落地:还差哪些模块

仿真做完,只代表你已经理解了 Q-learning 的运行逻辑,距离真实部署还差几块重要拼图。

首先是数据接入。训练时用的生成曲线,在真实系统里要换成平台的电价 API、光伏气象预测和负荷预测,而且数据必须同步到每个决策时刻。其次是安全约束。真实储能系统有温度、电压、最大充放电次数等限制,需要加在环境函数之外作为硬约束。第三是策略更新方式。市场是时变的,去年好用的电价规律今年不一定适用,我建议部署时采用滑动窗口式在线训练:每天用最近一个月的数据重新训练或微调 Q 表,而不是让一套策略用到底。

5.3 下一步值得试的扩展方向

如果你已经跑通了本文这套基础框架,建议往这三个方向扩展。

第一,动作空间连续化。把固定功率改成可调功率,Q 表格就没法用了,需要换成 DQN 或 DDPG 系列算法。第二,加入负荷和需求响应。目前储能只是峰谷套利,当你把可调负荷也放进决策空间,问题会从单智能体变成家庭能量管理系统。第三,多智能体竞价。当多个储能主体同时参与市场报价,价格又反过来受他们行为影响时,单智能体模型就不再适用,可以用多智能体强化学习做博弈仿真,这已经是目前能源市场研究里的前沿方向。

个人经验是,不要想一口吃成胖子。把本文这套单智能体 Q-learning 跑透,把状态设计、奖励函数和参数调试的直觉建立起来,后面再切换到更复杂的 DQN 或多智能体系统时,你会比别人少走很多弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询