<think>我们有两个部分:第一部分是优化计算,第二部分是结果可视化。现在需要将这两部分无缝衔接。
关键点:
1. 第一部分最后保存了优化结果和临时变量,第二部分加载这些数据。
2. 第一部分已经包含了一些可视化(帕累托前沿和最优控制策略图),第二部分增加了更多详细的可视化。
3. 需要确保第一部分生成的变量在第二部分中都能被正确加载和使用。
问题:第二部分代码中使用的变量(如`energy_dist_optim`、`tank`、`heating`、`control`等)在第一部分中并没有生成。
因此,我们需要在第一部分中补充这些变量的计算和保存。
解决方案:
1. 在第一部分(优化计算部分)的末尾,添加计算详细能源分配和系统状态的代码。
2. 将第二部分中需要的变量(如`energy_dist_optim`、`tank`、`heating`、`control`等)保存到文件,以便第二部分加载。
修改步骤:
步骤1:在第一部分末尾(输出最佳解之后)添加详细能源分配的计算代码。
步骤2:将计算得到的详细能源分配结果保存到文件(例如:'results/energy_distribution.mat')。
步骤3:同时,将第二部分所需的系统参数(如`tank`、`heating`、`control`等)也保存到一个文件(例如:'temp_vars_part1.mat')或包含在同一个文件中。
具体修改如下:
在第一部分(原代码)的末尾(即第7节之后)添加以下内容:
```matlab
%% 8. 详细能源分配计算(为第二部分准备)
fprintf('计算详细能源分配...\n');
% 提取最佳解
best_hp_power = best_solution(1:total_steps);
best_solar_ratio = best_solution(total_steps+1:end);
% 初始化能源分配结构
energy_dist_optim = struct();
energy_dist_optim.time = target_hours;
energy_dist_optim.T_out = T_out;
energy_dist_optim.G_solar = G_solar;
energy_dist_optim.price = price_vec;
energy_dist_optim.hp_power = best_hp_power;
energy_dist_optim.solar_ratio = best_solar_ratio;
% 计算供热功率
solar_heat = solar_ratio' .* solar_area .* G_solar' .* solar_efficiency; % 太阳能供热功率 (kW)
hp_heat = best_hp_power' .* arrayfun(hp_cop, T_out); % 热泵供热功率 (COP*功率)
% 简化模型:假设水箱初始满且温度为55℃
initial_tank_temp = 55;
tank_temp = zeros(1, total_steps);
tank_temp(1) = initial_tank_temp;
heat_demand = zeros(1, total_steps); % 热需求 (kW)
tank_heat = zeros(1, total_steps); % 水箱供热功率 (kW)
% 建筑热需求模型 (简化)
for i = 1:total_steps
% 建筑热损失 (kW)
heat_loss = building_u_value * building_area * (setpoint_temp - T_out(i)) / 1000; % 转换为kW
% 热需求 (假设为热损失加上一个随机波动)
heat_demand(i) = max(0, heat_loss + 0.5 * randn());
% 水箱逻辑 (简化)
if i > 1
% 水箱温度变化: 进热(太阳能多余时)和供热(当热需求大于太阳能和热泵时)
excess_solar = max(0, solar_heat(i) - heat_demand(i));
tank_heat_avail = max(0, tank_temp(i-1) - tank_min_temp) * tank_capacity * 4.18 / (3600*10/60); % 10分钟内可用能量 (kW)
if excess_solar > 0
% 向水箱充热
tank_temp(i) = tank_temp(i-1) + excess_solar * (10*60) / (tank_capacity * 4.18);
else
% 从水箱放热
required_heat = max(0, heat_demand(i) - solar_heat(i) - hp_heat(i));
tank_heat(i) = min(required_heat, tank_heat_avail);
tank_temp(i) = tank_temp(i-1) - tank_heat(i) * (10*60) / (tank_capacity * 4.18);
end
end
end
% 存储到结构体
energy_dist_optim.heat_demand = heat_demand;
energy_dist_optim.solar_heat = solar_heat;
energy_dist_optim.hp_heat = hp_heat;
energy_dist_optim.tank_heat = tank_heat;
energy_dist_optim.tank_temp = tank_temp;
energy_dist_optim.COP = arrayfun(hp_cop, T_out);
% 热泵运行成本 (每10分钟)
energy_dist_optim.hp_power_cost = best_hp_power' .* price_vec' * (10/60); % 元
% 计算室内温度 (简化模型)
T_room = setpoint_temp * ones(1, total_steps);
for i = 2:total_steps
heat_supply = solar_heat(i) + hp_heat(i) + tank_heat(i);
heat_gap = heat_supply - heat_demand(i);
T_room(i) = T_room(i-1) + 0.01 * heat_gap; % 简单积分
end
energy_dist_optim.T_room = T_room;
% 保存详细能源分配
save('results/energy_distribution.mat', 'energy_dist_optim');
% 保存其他第二部分需要的变量
tank.T_min = tank_min_temp;
tank.T_max = 80; % 水箱最高温度
heating.T_set = setpoint_temp;
control.periods = {[0, 7], [7, 18], [18, 24]}; % 控制时段定义
control.num_periods = length(control.periods);
% 时间向量 (小时)
time_vec = target_hours;
steps_per_day = 24 * (60 / time_step); % 每天的步数
% 保存临时变量
save('temp_vars_part1.mat', 'tank', 'heating', 'control', 'time_vec', 'steps_per_day', 'total_days');
fprintf('第一部分完成,请运行第二部分\n');
```
步骤4:修改第二部分代码的开头,确保加载正确的文件。
第二部分代码开头已经正确加载:
load('temp_vars_part1.mat');
load('results/energy_distribution.mat');
load('results/optim_results.mat');
但是,注意:第二部分代码中使用了`energy_dist_optim`结构体,我们在第一部分中已经生成并保存。
修改后,两个部分可以顺序运行。
注意:在运行之前,确保创建了results目录(第一部分中已有创建目录的代码)。
完整的第一部分代码(包括新增的详细能源分配计算)和第二部分代码(无需修改)即可无缝衔接。
运行流程:
1. 运行第一部分(优化计算) -> 生成数据文件
2. 运行第二部分(结果可视化) -> 加载第一部分生成的数据并绘图
注意:如果第一部分没有创建results目录,可以在第一部分开头添加:
if ~exist('results', 'dir')
mkdir('results');
end
因为我们在第一部分末尾保存了`energy_distribution.mat`到results目录,所以需要确保该目录存在。
另外,在第一部分中已经有了:
save('optim_results.mat', ...)
我们可以修改为保存到results目录:
save('results/optim_results.mat', ...)
同理,保存临时变量:
save('temp_vars_part1.mat', ...) % 临时变量,第二部分加载后可以删除
为了整洁,也可以将临时变量保存到results目录。
因此,我们调整保存路径:
在第一部分代码中:
- 开头创建目录:
if ~exist('results', 'dir')
mkdir('results');
end
if ~exist('results/figures', 'dir')
mkdir('results/figures');
end
- 保存优化结果:
save('results/optim_results.mat', 'X', 'F', 'weights', 'time_elapsed');
- 保存详细能源分配:
save('results/energy_distribution.mat', 'energy_dist_optim');
- 保存临时变量:
save('results/temp_vars_part1.mat', 'tank', 'heating', 'control', 'time_vec', 'steps_per_day', 'total_days');
然后,第二部分代码修改加载路径:
load('results/temp_vars_part1.mat');
load('results/energy_distribution.mat');
load('results/optim_results.mat');
这样所有文件都保存在results目录下。
最后,将修改后的完整第一部分代码和第二部分代码提供给您。
由于第一部分代码之前已经给出,现在将修改后的第一部分完整代码(整合了上述所有修改)和第二部分代码一起呈现。
注意:由于篇幅,这里只提供修改后的第一部分代码(在之前的基础上添加了第8节)和第二部分代码(加载路径调整)。
修改后的第一部分完整代码(包含之前的修复和新增的第8节):
</think>我将为您整合太阳能-热泵联合供暖系统优化控制的第一部分和第二部分代码,创建一个完整的无缝衔接解决方案。以下是完整的整合代码:
```matlab
%% 太阳能-热泵联合供暖系统优化控制 - 完整整合版
clc; clear; close all;
warning off;
addpath('functions'); % 添加自定义函数路径
fprintf('太阳能-热泵联合供暖系统优化控制\n');
fprintf('版本: 3.0 (完整整合版)\n');
fprintf('========================================\n');
%% 1. 系统参数设置
fprintf('初始化系统参数...\n');
total_days = 7; % 模拟天数
time_step = 10; % 时间步长(min)
total_steps = total_days * 24 * 60 / time_step; % 总步数
steps_per_day = 24 * (60 / time_step); % 每天的步数
% 热泵参数
hp_capacity = 12; % 热泵容量(kW)
hp_cop = @(T) 3.0 + 0.1*(T-5); % COP随温度变化
% 太阳能集热器参数
solar_area = 30; % 集热器面积(m²)
solar_efficiency = 0.75; % 集热效率
% 水箱参数
tank_capacity = 500; % 水箱容量(L)
tank_min_temp = 45; % 水箱最低温度(℃)
tank_max_temp = 80; % 水箱最高温度(℃)
% 建筑参数
building_area = 120; % 建筑面积(m²)
building_u_value = 0.3; % 建筑传热系数(W/m²K)
setpoint_temp = 21; % 设定温度(℃)
% 控制时段参数
control.periods = {[0, 7], [7, 18], [18, 24]}; % 控制时段定义
control.num_periods = length(control.periods);
%% 2. 环境参数生成
fprintf('生成环境参数...\n');
% 原始温度数据 (每小时一个点,7天)
daily_temps = [-15.3, -16.1, -17.2, -16.8, -15.5, -14.0, -12.5, ...
-11.0, -9.8, -8.5, -7.0, -6.5, -5.8, -5.0, ...
-5.5, -6.0, -7.2, -8.5, -10.0, -12.5, -14.0, -15.0, -15.8, -15.5];
T_out_weekly = repmat(daily_temps, 1, total_days);
% 温度插值
original_hours = 0:(24*total_days-1); % 原始时间点 (每小时)
target_hours = linspace(0, 24*total_days, total_steps); % 目标时间点 (每10分钟)
T_out = interp1(original_hours, T_out_weekly, target_hours, 'pchip');
% 太阳辐射数据 (简化模型)
G_solar = max(0, 800 * sin(pi * (mod(target_hours, 24) - 6)/12));
% 电价数据 (峰谷电价)
price_vec = zeros(1, total_steps);
for i = 1:total_steps
hour = mod(target_hours(i), 24);
if hour >= 7 && hour < 10 || hour >= 17 && hour < 21
price_vec(i) = 1.2; % 峰时电价
elseif hour >= 22 || hour < 6
price_vec(i) = 0.4; % 谷时电价
else
price_vec(i) = 0.8; % 平时电价
end
end
% 时间向量
time_vec = target_hours;
%% 3. 多目标优化设置
fprintf('设置多目标优化参数...\n');
num_vars = total_steps * 2; % 优化变量个数 (热泵功率 + 太阳能分配)
% 约束条件
lb = zeros(1, num_vars); % 下限
ub = [ones(1, total_steps) * hp_capacity, ... % 热泵功率上限
ones(1, total_steps) * 1]; % 太阳能分配比例上限
% 目标函数权重
weights = [0.4, 0.3, 0.2, 0.1]; % [能耗, 成本, 碳排放, 舒适度]
% 使用gamultiobj进行多目标优化
options = optimoptions('gamultiobj', ...
'PopulationSize', 100, ...
'MaxGenerations', 50, ...
'ParetoFraction', 0.7, ...
'Display', 'iter', ...
'PlotFcn', 'gaplotpareto');
%% 4. 运行多目标优化
fprintf('开始多目标优化...\n');
tic;
[X, F] = gamultiobj(@multi_objective_func, num_vars, [], [], [], [], lb, ub, [], options);
time_elapsed = toc;
fprintf('优化完成! 耗时: %.2f 分钟\n', time_elapsed/60);
%% 5. 结果分析 - 帕累托前沿处理
fprintf('分析优化结果...\n');
front = F;
% 归一化处理
min_vals = min(front);
max_vals = max(front);
range_vals = max_vals - min_vals;
range_vals(range_vals == 0) = 1; % 避免除以零
norm_front = (front - min_vals) ./ range_vals;
% 加权得分计算
if size(norm_front, 2) == length(weights)
scores = sum(norm_front .* weights, 2);
else
error('目标数量与权重数量不匹配');
end
% 选择最佳折衷解
[~, best_idx] = min(scores);
best_solution = X(best_idx, :);
%% 6. 详细能源分配计算
fprintf('计算详细能源分配...\n');
% 提取最佳解
hp_power = best_solution(1:total_steps);
solar_ratio = best_solution(total_steps+1:end);
% 初始化能源分配结构
energy_dist_optim = struct();
energy_dist_optim.time = time_vec;
energy_dist_optim.T_out = T_out;
energy_dist_optim.G_solar = G_solar;
energy_dist_optim.price = price_vec;
energy_dist_optim.hp_power = hp_power;
energy_dist_optim.solar_ratio = solar_ratio;
% 计算供热功率
solar_heat = solar_ratio' .* solar_area .* G_solar' .* solar_efficiency; % 太阳能供热功率 (kW)
hp_heat = hp_power' .* arrayfun(hp_cop, T_out); % 热泵供热功率 (COP*功率)
% 水箱模型
initial_tank_temp = 55;
tank_temp = zeros(1, total_steps);
tank_temp(1) = initial_tank_temp;
heat_demand = zeros(1, total_steps); % 热需求 (kW)
tank_heat = zeros(1, total_steps); % 水箱供热功率 (kW)
% 建筑热需求模型
for i = 1:total_steps
% 建筑热损失 (kW)
heat_loss = building_u_value * building_area * (setpoint_temp - T_out(i)) / 1000;
heat_demand(i) = max(0, heat_loss + 0.5 * randn());
% 水箱逻辑
if i > 1
excess_solar = max(0, solar_heat(i) - heat_demand(i));
tank_heat_avail = max(0, tank_temp(i-1) - tank_min_temp) * tank_capacity * 4.18 / (3600*10/60);
if excess_solar > 0
% 向水箱充热
tank_temp(i) = min(tank_max_temp, tank_temp(i-1) + excess_solar * (10*60) / (tank_capacity * 4.18));
else
% 从水箱放热
required_heat = max(0, heat_demand(i) - solar_heat(i) - hp_heat(i));
tank_heat(i) = min(required_heat, tank_heat_avail);
tank_temp(i) = max(tank_min_temp, tank_temp(i-1) - tank_heat(i) * (10*60) / (tank_capacity * 4.18));
end
end
end
% 存储到结构体
energy_dist_optim.heat_demand = heat_demand;
energy_dist_optim.solar_heat = solar_heat;
energy_dist_optim.hp_heat = hp_heat;
energy_dist_optim.tank_heat = tank_heat;
energy_dist_optim.tank_temp = tank_temp;
energy_dist_optim.COP = arrayfun(hp_cop, T_out);
% 热泵运行成本
energy_dist_optim.hp_power_cost = hp_power' .* price_vec' * (10/60); % 元
% 室内温度模型
T_room = setpoint_temp * ones(1, total_steps);
for i = 2:total_steps
heat_supply = solar_heat(i) + hp_heat(i) + tank_heat(i);
heat_gap = heat_supply - heat_demand(i);
T_room(i) = max(15, min(25, T_room(i-1) + 0.01 * heat_gap));
end
energy_dist_optim.T_room = T_room;
%% 7. 结果输出与可视化
fprintf('\n===== 优化结果总结 =====\n');
fprintf('最佳折衷解得分: %.4f\n', scores(best_idx));
fprintf('总能耗: %.2f kWh\n', front(best_idx,1));
fprintf('总成本: %.2f 元\n', front(best_idx,2));
fprintf('总碳排放: %.2f kgCO₂\n', front(best_idx,3));
fprintf('平均舒适度偏差: %.3f ℃\n', front(best_idx,4));
fprintf('========================================\n');
% 创建结果目录
if ~exist('results', 'dir')
mkdir('results');
end
if ~exist('results/figures', 'dir')
mkdir('results/figures');
end
% 1. 帕累托前沿图
figure('Position', [100, 100, 800, 600]);
plot(F(:,1), F(:,2), 'bo', 'MarkerSize', 8, 'LineWidth', 1.5);
hold on;
plot(F(best_idx,1), F(best_idx,2), 'ro', 'MarkerSize', 10, 'LineWidth', 2);
xlabel('总能耗 (kWh)');
ylabel('总成本 (元)');
title('多目标优化帕累托前沿');
grid on;
legend('帕累托解', '最佳折衷解', 'Location', 'northwest');
saveas(gcf, 'results/figures/pareto_front.png');
% 2. 室外温度变化
figure('Position', [100, 100, 1000, 400]);
plot(time_vec, T_out, 'b-', 'LineWidth', 1.5);
xlabel('时间 (小时)');
ylabel('温度 (°C)');
title('一周室外温度变化');
xlim([0, total_days*24]);
grid on;
saveas(gcf, 'results/figures/temperature_variation.png');
% 3. 最佳解时间序列
figure('Position', [100, 100, 1000, 600]);
subplot(3,1,1);
plot(time_vec, hp_power, 'r-', 'LineWidth', 1.5);
xlabel('时间 (小时)');
ylabel('热泵功率 (kW)');
title('热泵运行策略');
grid on;
subplot(3,1,2);
plot(time_vec, solar_ratio, 'g-', 'LineWidth', 1.5);
xlabel('时间 (小时)');
ylabel('太阳能分配比例');
title('太阳能利用策略');
grid on;
subplot(3,1,3);
plot(time_vec, energy_dist_optim.tank_temp, 'm-', 'LineWidth', 1.5);
hold on;
plot(time_vec, tank_min_temp*ones(1, total_steps), 'r--', 'LineWidth', 1.5);
plot(time_vec, tank_max_temp*ones(1, total_steps), 'r--', 'LineWidth', 1.5);
xlabel('时间 (小时)');
ylabel('水箱温度 (°C)');
title('水箱温度变化');
legend('水箱温度', '温度限制', 'Location', 'southwest');
grid on;
saveas(gcf, 'results/figures/optimal_control.png');
% 4. 供暖季最冷日热源出力
coldest_day = find(T_out == min(T_out), 1);
cold_day_start = coldest_day;
cold_day_end = min(cold_day_start + steps_per_day - 1, total_steps);
figure('Position', [100, 100, 1000, 600]);
subplot(2,1,1);
plot(time_vec(cold_day_start:cold_day_end), ...
energy_dist_optim.heat_demand(cold_day_start:cold_day_end), 'k-', 'LineWidth', 1.5, 'DisplayName', '热需求');
hold on;
plot(time_vec(cold_day_start:cold_day_end), ...
energy_dist_optim.solar_heat(cold_day_start:cold_day_end), 'r-', 'LineWidth', 1.5, 'DisplayName', '太阳能供热');
plot(time_vec(cold_day_start:cold_day_end), ...
energy_dist_optim.hp_heat(cold_day_start:cold_day_end), 'b-', 'LineWidth', 1.5, 'DisplayName', '热泵供热');
plot(time_vec(cold_day_start:cold_day_end), ...
energy_dist_optim.tank_heat(cold_day_start:cold_day_end), 'g-', 'LineWidth', 1.5, 'DisplayName', '水箱供热');
xlabel('时间 (小时)');
ylabel('功率 (W)');
title('最冷日供热功率分配');
legend('Location', 'northwest');
grid on;
% 5. 水箱温度变化 (最冷日)
subplot(2,1,2);
plot(time_vec(cold_day_start:cold_day_end), ...
energy_dist_optim.tank_temp(cold_day_start:cold_day_end), 'm-', 'LineWidth', 1.5);
hold on;
plot(time_vec(cold_day_start:cold_day_end), ...
tank_min_temp*ones(1, cold_day_end-cold_day_start+1), 'r--', 'LineWidth', 1.5);
plot(time_vec(cold_day_start:cold_day_end), ...
tank_max_temp*ones(1, cold_day_end-cold_day_start+1), 'r--', 'LineWidth', 1.5);
xlabel('时间 (小时)');
ylabel('水箱温度 (°C)');
title('最冷日水箱温度变化');
legend('水箱温度', '温度限制', 'Location', 'southwest');
grid on;
saveas(gcf, 'results/figures/cold_day_energy_dist.png');
% 6. 太阳能辐射与热泵COP
figure('Position', [100, 100, 1000, 400]);
yyaxis left;
plot(time_vec, G_solar, 'r-', 'LineWidth', 1.5);
ylabel('太阳辐射 (W/m²)');
yyaxis right;
plot(time_vec, energy_dist_optim.COP, 'b-', 'LineWidth', 1.5);
ylabel('热泵COP');
xlabel('时间 (小时)');
title('太阳能辐射与热泵COP关系');
grid on;
saveas(gcf, 'results/figures/solar_radiation_cop.png');
% 7. 电价与热泵运行成本
figure('Position', [100, 100, 1000, 400]);
yyaxis left;
plot(time_vec, price_vec, 'm-', 'LineWidth', 1.5);
ylabel('电价 (元/kWh)');
yyaxis right;
plot(time_vec, energy_dist_optim.hp_power_cost, 'c-', 'LineWidth', 1.5);
ylabel('热泵运行成本 (元)');
xlabel('时间 (小时)');
title('电价与热泵运行成本');
grid on;
saveas(gcf, 'results/figures/price_operation_cost.png');
% 8. 室内温度舒适度分析
fprintf('分析室内温度舒适度...\n');
% 计算舒适度指标
comfort_deviation = abs(energy_dist_optim.T_room - setpoint_temp);
comfort_score = 1./(1 + comfort_deviation.^2); % 舒适度评分函数
% 按时间段分析舒适度
comfort_by_period = zeros(1, control.num_periods);
period_indices = cell(1, control.num_periods);
for p = 1:control.num_periods
period_start = control.periods{p}(1);
period_end = control.periods{p}(2);
period_indices{p} = find(time_vec >= period_start & time_vec < period_end);
comfort_by_period(p) = mean(comfort_score(period_indices{p}));
end
figure('Position', [100, 100, 800, 400]);
bar(comfort_by_period, 'FaceColor', [0.5 0.7 0.9]);
set(gca, 'XTick', 1:control.num_periods, 'XTickLabel', ...
arrayfun(@(x) sprintf('%d',x), 1:control.num_periods, 'UniformOutput', false));
xlabel('控制时段');
ylabel('平均舒适度评分');
title('各时段室内舒适度评分');
ylim([0.8, 1.0]);
grid on;
save