2025年电工杯数学建模竞赛 选题分析
A题 光伏电站发电功率日前预测问题
A题聚焦光伏电站发电功率的日前预测问题,要求基于历史功率数据和数值天气预报(NWP)信息,建立不同复杂度的预测模型。题目从基础特性分析逐步深入到多因素融合预测,最终探讨气象数据空间降尺度对预测精度的影响。该问题结合了时间序列分析、机器学习、气象学等多学科知识,强调数据驱动建模和预测精度优化。
选题分析:
- 对时间序列预测和机器学习有扎实基础,熟悉LSTM、XGBoost等算法;
- 能够处理多源异构数据(气象数据、功率数据等)的融合与特征工程;
B题 城市垃圾分类运输的路径优化与调度
B题针对城市垃圾分类运输的路径优化问题,从单一车辆类型的基础路径规划,扩展到多车型协同调度,最终结合中转站选址和时间窗口约束形成综合优化模型。题目涉及车辆路径问题(VRP)的多种变体,要求考虑载重约束、时间窗口、碳排放等多目标优化,具有鲜明的运筹学特色。
选题分析:
- 熟悉组合优化和路径规划算法,如节约算法、遗传算法等;
- 能够处理复杂约束条件下的数学建模,擅长线性/整数规划;
- 对物流调度或城市管理问题感兴趣,具备空间分析能力;
综合建议:
- 偏好数据分析和预测建模的团队更适合选择A题,该题侧重算法选择和模型优化。
- 擅长数学建模和组合优化的团队更适合选择B题,该题侧重约束处理和路径规划。
2025年电工杯数学建模竞赛A题
赛题分析
问题1:基于历史功率的光伏电站发电特性分析
- 目标:分析光伏电站的长周期(季节性)和短周期(日内)发电特性
- 关键点:理论可发功率计算、实际与理论功率偏差分析
- 数据需求:历史发电功率数据、地理位置信息、时间序列数据
问题2:基于历史功率的日前发电功率预测模型
- 目标:仅使用历史功率数据建立预测模型
- 关键点:时间序列预测方法选择、模型训练与评估
- 数据需求:历史发电功率数据
问题3:融入NWP信息的日前发电功率预测模型
- 目标:结合数值天气预报(NWP)信息提高预测精度
- 关键点:多变量时间序列预测、NWP信息融合、场景划分
- 数据需求:历史发电功率数据+NWP数据
问题4:NWP空间降尺度对预测精度的影响
- 目标:研究更高分辨率气象数据对预测的影响
- 关键点:空间降尺度方法、精度对比分析
- 数据需求:不同分辨率的NWP数据
求解思路与模型
问题1求解思路
- 理论功率计算:基于地理位置和太阳位置模型计算理论辐照
- 季节性分析:按月/季节聚合功率数据,分析趋势
- 日内波动分析:按小时分析功率波动模式
- 偏差分析:计算实际功率与理论功率的偏差
Python代码
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pvlib import solarposition, irradiance
# 1. 理论功率计算
def calculate_theoretical_power(lat, lon, times, tilt=30, azimuth=180):
solpos = solarposition.get_solarposition(times, lat, lon)
dni_extra = irradiance.get_extra_radiation(times)
airmass = irradiance.get_relative_airmass(solpos['apparent_zenith'])
poa_irrad = irradiance.get_total_irradiance(
tilt, azimuth,
solpos['apparent_zenith'], solpos['azimuth'],
dni=1000, ghi=800, dhi=200, dni_extra=dni_extra,
airmass=airmass)
return poa_irrad['poa_global'] # 假设与功率成正比
# 2. 季节性分析
def seasonal_analysis(power_data):
monthly = power_data.resample('M').mean()
monthly.plot(title='Monthly Average Power')
plt.show()
# 3. 日内波动分析
def diurnal_analysis(power_data):
hourly = power_data.groupby(power_data.index.hour).mean()
hourly.plot(title='Hourly Average Power')
plt.show()
# 4. 偏差分析
def deviation_analysis(actual, theoretical):
deviation = actual - theoretical
deviation.resample('D').mean().plot(title='Daily Deviation')
plt.show()
MATLAB代码
% 1. 理论功率计算
function theoretical_power = calculate_theoretical_power(lat, lon, times)
% 使用Solar Position Algorithm计算太阳位置
[zenith, azimuth] = solarPosition(lat, lon, times);
% 计算理论辐照度 (简化模型)
dni = 1000; ghi = 800; dhi = 200;
tilt = 30; surface_azimuth = 180;
poa_global = pvl_perez(tilt, surface_azimuth, zenith, azimuth, dni, ghi, dhi);
theoretical_power = poa_global; % 假设与功率成正比
end
% 2. 季节性分析
function seasonal_analysis(power_data)
monthly_mean = retime(power_data, 'monthly', 'mean');
figure;
plot(monthly_mean.Time, monthly_mean.Power);
title('Monthly Average Power');
end
% 3. 日内波动分析
function diurnal_analysis(power_data)
hours = hour(power_data.Time);
hourly_mean = groupsummary(power_data, hours, 'mean');
figure;
plot(hourly_mean.GroupCount, hourly_mean.mean_Power);
title('Hourly Average Power');
end
问题2求解思路
- 数据预处理:处理缺失值、异常值
- 特征工程:创建时间特征(小时、日、月等)
- 模型选择:LSTM、XGBoost、Prophet等时间序列模型
- 模型评估:使用MAE、RMSE等指标评估
Python代码 (LSTM模型)
import tensorflow as tf
from sklearn.preprocessing import MinMaxScaler
def lstm_model(X_train, y_train):
model = tf.keras.Sequential([
tf.keras.layers.LSTM(64, input_shape=(X_train.shape[1], X_train.shape[2])),
tf.keras.layers.Dense(1)
])
model.compile(optimizer='adam', loss='mse')
history = model.fit(X_train, y_train, epochs=50, batch_size=32, validation_split=0.2)
return model
def prepare_data(data, n_steps=24*4): # 24小时(15分钟间隔)
X, y = [], []
for i in range(len(data)-n_steps):
X.append(data[i:i+n_steps])
y.append(data[i+n_steps])
return np.array(X), np.array(y)
# 数据预处理
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(data[['power']].values)
X, y = prepare_data(scaled_data)
X = X.reshape((X.shape[0], X.shape[1], 1))
# 划分训练测试集
split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# 训练模型
model = lstm_model(X_train, y_train)
MATLAB代码 (LSTM模型)
% 准备LSTM网络
numFeatures = 1;
numHiddenUnits = 64;
layers = [ ...
sequenceInputLayer(numFeatures)
lstmLayer(numHiddenUnits)
fullyConnectedLayer(1)
regressionLayer];
options = trainingOptions('adam', ...
'MaxEpochs',50, ...
'MiniBatchSize',32, ...
'ValidationData',{XVal,YVal}, ...
'Plots','training-progress');
% 训练网络
net = trainNetwork(XTrain,YTrain,layers,options);
% 预测
YPred = predict(net,XTest);
问题3求解思路
- 数据融合:将NWP数据与历史功率数据对齐
- 特征选择:选择相关性高的气象特征
- 多变量模型:构建考虑NWP的预测模型
- 场景划分:按季节/天气类型划分场景分别建模
Python代码 (XGBoost模型)
import xgboost as xgb
from sklearn.model_selection import train_test_split
def prepare_nwp_data(power_data, nwp_data):
# 对齐时间戳并合并数据
merged = power_data.join(nwp_data, how='inner')
# 创建时间特征
merged['hour'] = merged.index.hour
merged['month'] = merged.index.month
return merged
# 准备数据
features = prepare_nwp_data(power_data, nwp_data)
X = features.drop('power', axis=1)
y = features['power']
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)
# 训练XGBoost模型
model = xgb.XGBRegressor(n_estimators=100, learning_rate=0.1)
model.fit(X_train, y_train)
# 场景划分 (按季节)
seasons = features.index.month%12 // 3 + 1
for season in range(1,5):
season_data = features[seasons == season]
# 为每个季节训练单独模型...
MATLAB代码 (随机森林模型)
% 准备数据
features = prepareNWPData(powerData, nwpData);
X = features(:, 1:end-1);
Y = features(:, end);
% 训练随机森林模型
mdl = TreeBagger(100, X, Y, 'Method', 'regression');
% 场景划分 (按天气类型)
clearWeather = features.CloudCover < 0.3;
cloudyWeather = (features.CloudCover >= 0.3) & (features.CloudCover < 0.7);
overcastWeather = features.CloudCover >= 0.7;
% 为每种天气训练单独模型
mdlClear = TreeBagger(100, X(clearWeather,:), Y(clearWeather));
mdlCloudy = TreeBagger(100, X(cloudyWeather,:), Y(cloudyWeather));
mdlOvercast = TreeBagger(100, X(overcastWeather,:), Y(overcastWeather));
问题4求解思路
- 空间降尺度方法:
- 机器学习方法:使用高分辨率地理数据训练降尺度模型
- 空间插值:Kriging、IDW等
- 精度对比:比较降尺度前后NWP数据的预测精度
- 原因分析:分析降尺度对局部气象特征的捕捉能力
Python代码 (Kriging降尺度)
from pykrige.ok import OrdinaryKriging
from sklearn.metrics import mean_squared_error
def kriging_downscale(coarse_data, fine_locs):
# coarse_data: 粗分辨率NWP数据
# fine_locs: 细分辨率位置坐标
# 准备Kriging模型
OK = OrdinaryKriging(
coarse_data.lon, coarse_data.lat, coarse_data.value,
variogram_model='linear'
)
# 在细分辨率位置插值
fine_values, _ = OK.execute('points', fine_locs.lon, fine_locs.lat)
return fine_values
# 比较预测精度
def compare_accuracy(coarse_pred, fine_pred, actual):
coarse_rmse = mean_squared_error(actual, coarse_pred, squared=False)
fine_rmse = mean_squared_error(actual, fine_pred, squared=False)
print(f"Coarse RMSE: {coarse_rmse}, Fine RMSE: {fine_rmse}")
return fine_rmse - coarse_rmse
MATLAB代码 (IDW降尺度)
% 反距离加权插值
function fineData = idw_downscale(coarseLon, coarseLat, coarseData, fineLon, fineLat)
F = scatteredInterpolant(coarseLon, coarseLat, coarseData, 'natural');
fineData = F(fineLon, fineLat);
end
% 比较预测精度
function rmseDiff = compare_accuracy(coarsePred, finePred, actual)
coarseRMSE = sqrt(mean((actual - coarsePred).^2));
fineRMSE = sqrt(mean((actual - finePred).^2));
rmseDiff = fineRMSE - coarseRMSE;
end
模型建议
- 基础模型:
- 时间序列模型:LSTM、GRU、TCN
- 传统机器学习:XGBoost、随机森林、SVR
- 进阶模型:
- 多任务学习:同时预测多个时间点
- 注意力机制:Transformer模型
- 混合模型:LSTM+CNN组合
- 集成方法:
- 模型堆叠:基础模型预测作为新特征输入到元模型
- 加权平均:不同模型预测结果的加权组合
- 误差修正:
- 残差模型:对基础模型预测的误差进行建模
- 后处理方法:基于历史误差分布的校正
2025年电工杯数学建模竞赛B题
赛题分析
问题1:单一车辆类型下的基础路径优化与调度
- 目标:最小化每日总行驶距离
- 约束:车辆载重限制、单一起止点、允许分批运输
- 特点:经典车辆路径问题(VRP)变种,单车型单类型垃圾
问题2:多车辆协同与载重约束下的优化
- 目标:最小化每日总运输成本
- 约束:多车型(4类)、多垃圾类型、各自载重/容积限制
- 特点:多车型车辆路径问题(MDVRP)变种,考虑不同类型垃圾
问题3:含中转站选址与时间窗口的综合优化
- 目标:最小化运输成本与中转站建设成本之和
- 约束:中转站容量、时间窗口、碳排放限制、非对称路网
- 特点:选址-路径问题(LRP)与绿色车辆路径问题(GVRP)结合
求解思路与模型
问题1求解思路
- 模型建立:转化为带容量约束的车辆路径问题(CVRP)
- 算法选择:节约算法(Clarke-Wright)或遗传算法
- 求解步骤:
- 计算所有点间距离矩阵
- 构建初始解(每点单独往返)
- 合并路径满足容量约束
- 复杂度分析:O(n²)~O(n³)取决于具体实现
Python代码
import numpy as np
from scipy.spatial import distance_matrix
def solve_vrp(points, demands, capacity):
"""使用节约算法求解CVRP"""
n = len(points)
dist = distance_matrix(points, points)
# 初始解:每点单独往返
routes = [[0, i, 0] for i in range(1, n+1)]
savings = []
# 计算所有节约值
for i in range(1, n+1):
for j in range(i+1, n+1):
sav = dist[0,i] + dist[0,j] - dist[i,j]
savings.append((sav, i, j))
# 按节约值降序排序
savings.sort(reverse=True, key=lambda x: x[0])
# 合并路径
for sav, i, j in savings:
route_i = find_route(routes, i)
route_j = find_route(routes, j)
if route_i != route_j and sum(demands[k-1] for k in route_i) + sum(demands[k-1] for k in route_j) <= capacity:
# 合并两条路径
new_route = merge_routes(route_i, route_j, i, j)
routes.remove(route_i)
routes.remove(route_j)
routes.append(new_route)
return routes
def find_route(routes, node):
"""找到包含指定节点的路径"""
for route in routes:
if node in route:
return route
return None
MATLAB代码
function routes = solve_vrp(points, demands, capacity)
% 使用节约算法求解CVRP
n = size(points, 1);
dist = pdist2(points, points);
% 初始解:每点单独往返
routes = cell(n,1);
for i = 1:n
routes{i} = [1, i+1, 1]; % 假设1是处理厂
end
% 计算节约值
savings = [];
for i = 1:n
for j = i+1:n
sav = dist(1,i+1) + dist(1,j+1) - dist(i+1,j+1);
savings = [savings; sav, i, j];
end
end
% 按节约值降序排序
savings = sortrows(savings, -1);
% 合并路径
for k = 1:size(savings,1)
sav = savings(k,1);
i = savings(k,2);
j = savings(k,3);
route_i = find_route(routes, i);
route_j = find_route(routes, j);
if ~isequal(route_i, route_j) && sum(demands(route_i(2:end-1)-1)) + sum(demands(route_j(2:end-1)-1)) <= capacity
% 合并两条路径
new_route = merge_routes(route_i, route_j, i, j);
routes = [routes; {new_route}];
routes(find_route_index(routes, route_i)) = [];
routes(find_route_index(routes, route_j)) = [];
end
end
end
问题2求解思路
- 模型建立:多车型车辆路径问题(MDVRP)
- 算法扩展:将问题1算法按垃圾类型分解
- 求解步骤:
- 按垃圾类型分组收集点
- 对每种类型独立求解VRP
- 考虑车辆类型特定约束(载重、容积、成本)
- 时间约束处理:添加路径时间计算和约束
Python代码
def solve_mdvrp(points, demands, vehicle_specs):
"""多车型车辆路径问题求解"""
solutions = {}
for k, spec in vehicle_specs.items():
# 筛选当前类型垃圾需求>0的点
mask = demands[:,k] > 0
sub_points = points[mask]
sub_demands = demands[mask, k]
# 调用VRP求解器
solutions[k] = solve_vrp(sub_points, sub_demands, spec['Q'])
return solutions
def add_time_constraint(routes, speed=40, max_hours=12):
"""添加时间约束验证"""
valid_routes = []
total_distance = 0
for route in routes:
route_dist = calculate_route_distance(route)
route_time = route_dist / speed
if route_time <= max_hours:
valid_routes.append(route)
total_distance += route_dist
else:
# 需要拆分路径
split_routes = split_route(route, speed, max_hours)
valid_routes.extend(split_routes)
return valid_routes
MATLAB代码
function solutions = solve_mdvrp(points, demands, vehicle_specs)
% 多车型车辆路径问题求解
solutions = struct();
for k = 1:length(vehicle_specs)
% 筛选当前类型垃圾需求>0的点
mask = demands(:,k) > 0;
sub_points = points(mask,:);
sub_demands = demands(mask,k);
% 调用VRP求解器
solutions(k).routes = solve_vrp(sub_points, sub_demands, vehicle_specs(k).Q);
end
end
function valid_routes = add_time_constraint(routes, speed, max_hours)
% 添加时间约束验证
valid_routes = {};
for i = 1:length(routes)
route = routes{i};
route_dist = calculate_route_distance(route);
route_time = route_dist / speed;
if route_time <= max_hours
valid_routes{end+1} = route;
else
% 需要拆分路径
split_routes = split_route(route, speed, max_hours);
valid_routes = [valid_routes, split_routes];
end
end
end
问题3求解思路
- 两阶段模型:
- 阶段1:中转站选址(设施选址问题)
- 阶段2:带时间窗的车辆路径问题(VRPTW)
- 算法设计:
- 阶段1:使用聚类或整数规划确定选址
- 阶段2:改进的遗传算法或禁忌搜索
- 非对称处理:构建有向图距离矩阵
Python代码
def two_phase_solver(points, demands, candidates, vehicle_specs):
"""两阶段求解器"""
# 阶段1:中转站选址
selected_stations = select_stations(points, candidates)
# 分配收集点到最近中转站
allocations = allocate_points(points, selected_stations)
# 阶段2:路径优化
solutions = {}
for station in selected_stations:
station_points = points[allocations == station]
station_demands = demands[allocations == station]
for k, spec in vehicle_specs.items():
mask = station_demands[:,k] > 0
sub_points = station_points[mask]
sub_demands = station_demands[mask, k]
solutions[(station, k)] = solve_vrptw(sub_points, sub_demands, spec)
return solutions
def solve_vrptw(points, demands, vehicle_spec):
"""带时间窗的车辆路径问题求解"""
# 实现基于遗传算法的VRPTW求解
pass
MATLAB代码
function solutions = two_phase_solver(points, demands, candidates, vehicle_specs)
% 两阶段求解器
% 阶段1:中转站选址
selected_stations = select_stations(points, candidates);
% 分配收集点到最近中转站
allocations = allocate_points(points, selected_stations);
% 阶段2:路径优化
solutions = struct();
for s = 1:length(selected_stations)
station = selected_stations(s);
mask = allocations == station;
station_points = points(mask,:);
station_demands = demands(mask,:);
for k = 1:length(vehicle_specs)
type_mask = station_demands(:,k) > 0;
sub_points = station_points(type_mask,:);
sub_demands = station_demands(type_mask,k);
solutions(s,k).routes = solve_vrptw(sub_points, sub_demands, vehicle_specs(k));
end
end
end
模型建议
- 基础模型:
- 节约算法(Clarke-Wright):适合小规模问题,实现简单
- 最近邻法:快速构建初始解
- 扫描算法:适合有空间聚集性的问题
- 进阶模型:
- 遗传算法:适合中大规模问题,可处理复杂约束
- 禁忌搜索:避免局部最优,适合VRPTW变种
- 蚁群算法:适合路径优化,可并行化
- 精确算法:
- 分支定价:适合小规模精确求解
- 动态规划:适合点数量有限的情况
- 混合策略:
- 先聚类再路径优化:适合含中转站的问题
- 多阶段启发式:分解复杂问题为多个子问题