这题是一个光伏角的优化问题, 模型问题不再赘述, 我是负责算法部分, 所以在这里重述一下算法的思路.

题目

太阳能是一种清洁能源,它的应用正在世界范围内快速地增长。目前建设一个太阳能发电系统成本较高,从我国现阶段的太阳能发电成本来看,其花费在太阳电池组件的费用大约为60%左右。为了更好地利用太阳能电池板发电,从安装的角度来看,也有可以挖掘的潜力。

涉及到的几何参数

  1. 太阳能电池板的倾角(Module tilt):太阳能电池板平面与水平面的夹角
  2. 太阳能电池板的方位角(Module azimuth):此角度为太阳能电池板的法线在水平面上的投影与正南方向的夹角。并按如下方法规定角度:如果一个太阳能电池板朝向正南,那么它的方位角为零度; 如果一个太阳能电池板朝向正东,那么它的方位角为-90度; 如果一个太阳能电池板朝向正西,那么它的方位角为+90度。
  3. 太阳高度角:对于地球表面上的某个点,太阳高度角是指太阳光的入射方向和地平面之间的夹角。
  4. 太阳方位角:在地球表面某点,建立以球面外法线方向为z轴正方向,以向东方向为x轴,向北方向为y轴的坐标系。太阳在这个坐标系中,北偏东的角度为方位角。
  5. 经度、纬度、海拔高度

latitude: in degrees, north of equator is positive
longitude :in degrees, positive for east of Greenwich
altitude: in meters ,above mean sea level

具体背景

一般情况下,电池板朝向正南(即=0°)时,太阳电池发电量最大。在偏离正南(北半球)30°度时,发电量将减少约10%~15%;在偏离正南(北半球)60°时,发电量将减少约20%~30%。但是,在晴朗的夏天,太阳辐射能量的最大时刻是在中午稍后,因此电池板方阵的方位稍微向西偏一些时,在午后时刻可获得最大的发电功率。 一年中的最佳倾角与当地的地理纬度有关,当纬度较高时,相应的倾角也大。因此,为了更加有效地利用太阳能,铺设安装时,选取太阳电池板的方位角与倾角是一个十分重要的问题。

太阳能电池板平面所能获得的太阳光强与倾角和方位角等参数有关,直接影响电池板的产能。现有一实际工况,见如下俯视图(图1),其中标示数据为几何尺寸 (长度、高度【单位:米】和角度(单位:度))

一般实际工况中,太阳能电池板是以一定倾角和方位角安装在屋顶上,前排电池板不可避免的会对后排电池板造成遮蔽【注:如果太阳电池不能被日光直接照射,那么只有散射光用来发电,此时的发电量比无阴影的要减少约10%~20%】,因此,在太阳能电池板大小一定的情况下,为了尽可能多的获得太阳的照射而增加产能,安装之前,有必要根据房屋的情况对太阳能电池板的安装间距D、倾角和方位角等参数进行设计。请解决如下问题【注:对于需要使用,而未给定的参数,可以按实际情况,自行合理设定; 参数具体含义可以查阅文献】


(1) 请以屋顶的几何参数和太阳能电池板各几何参数【,因为可以拼接,其中可以任意】,并假设太阳高度角和太阳方位角。以此时刻点参数的具体值,请设计安装间距D、倾角和方位角等参数,使之获得最大瞬时光照面积。

(2) 太阳的高度角随时间和空间变化,如果以某一天为例,以武汉某地【longitude = 114.3556,latitude =30.5286,altitude = 183m】为对象,设计安装间距D、倾角和方位角等参数,使获得最大日产能【附件数据文件data1给出如下系列数据:时间点,高度角和方位角等离散数据】。

(3) 如果在一个月的时间里考虑,设计安装间距D、倾角和方位角等参数,使获得最大月产能【附件数据文件data2: 年、 月、 日、时、分、高度角和方位角等离散数据】。

(4) 如果将散射光也考虑在内,对问题(3)进行讨论。
为了方便工程施工人员铺设安装太阳能电池板,请设计一个应用程序(图形用户界面),为在任一地点铺设安装提供参数支持(此时可以使用附件中提供的MATLAB程序:sun_position.m)。
第一题是个固定解, 不再赘述,

第二题

由于所给的数据中太阳的方向角与高度角均为离散的值, 因此在求解该模型时无法直接给出解析的解, 因此选用数值解法. 而本题由于数据量较大, 所以采用遗传算法与粒子群算法相结合的方法搜索最优解.利用遗传算法各染色体互相共享信息的特点,使得整个种群逼近parato前沿.利用粒子群算法粒子会记忆保存邻域内最好解的特点, 使种群加快收敛.

GA_PSO算法步骤也不赘述了, 程序如下

clear
lenchrom=2;    %字符串长度(个体长度),染色体编码长度
pc=0.7;        %设置交叉概率,本例中交叉概率是定值,若想设置变化的交叉概率可用表达式表示,或从写一个交叉概率函数,例如用神经网络训练得到的值作为交叉概率
pm=0.3;        %设置变异概率,同理也可设置为变化的
h = waitbar(0, 'couting...');
data = xlsread('/Users/xuguodong/Desktop/4/4/data1.xlsx');
tilt = 5.71;
height = 1.8;
%粒子群算法中的两个参数
c1 = 0.5;
c2 = 0.5;

maxgen=80;   % 进化次数  
popsize=50; %种群规模

%粒子更新速度
Vmax=1;
Vmin=-1;


% 变量取值范围
bound=[2 60;0 80];  %变量范围

% 优化粒子数目
par_num=2;

%% 产生初始粒子和速度
for i=1:popsize
    %随机产生一个种群
    pop(i,1)=bound(1,1)+rand*(bound(1,2)-bound(1,1));%初始种群
    pop(i,2)= 80 .* rand;
    V(i,:)=rand(1,par_num);  %初始化速度
    %计算适应度
    fitness(i)=fun(pop(i,:), data, tilt);   %染色体的适应度
end

%找最好的染色体
[bestfitness bestindex]=min(fitness);
zbest=pop(bestindex,:);   %全局最佳
gbest=pop;    %个体最佳
fitnessgbest=fitness;   %个体最佳适应度值
fitnesszbest=bestfitness;   %全局最佳适应度值

%% 迭代寻优
for i=1:maxgen
    for j=1:popsize

        %速度更新 PSO选择更新
        V(j,:) = V(j,:) + c1*rand*(gbest(j,:) - pop(j,:)) + c2*rand*(zbest - pop(j,:));
        V(j,find(V(j,:)>Vmax))=Vmax;
        V(j,find(V(j,:)<Vmin))=Vmin;

        %种群更新 PSO选择更新
        pop(j,:)=pop(j,:)+0.5*V(j,:);
        pop(j,find(pop(j,1)>80))=80;
        pop(j,find(pop(j,1)<0))=0;
        pop(j,find(pop(j,2)>20))=20;
        pop(j,find(pop(j,2)<0))=0;


        GApop=Cross(pc,lenchrom,pop,popsize,bound);

        % 变异操作 GA变异
        GApop=Mutation(pm,lenchrom,GApop,popsize,[i maxgen],bound);

        pop=GApop; % GA pop --> PSO pop
        fitness(j)=fun(pop(j,:),data,tilt);
        %个体最优更新
        if fitness(j) < fitnessgbest(j)
            gbest(j,:) = pop(j,:);
            fitnessgbest(j) = fitness(j);
        end

        %群体最优更新
        if fitness(j) < fitnesszbest
            zbest = pop(j,:);
            fitnesszbest = fitness(j);
        end
    end
    yy(i)=fitnesszbest;     
    waitbar(i/maxgen);
end

%% 结果
disp '*************result****************'
betaj = zbest(1)
rj = zbest(2)-40
a = mean(data(:,1));
D = height*sin((a+betaj)*pi/180)/sin((a+betaj+tilt)*pi/180)
close(h);
plot(yy,'linewidth',2);
grid on
title(['适应度曲线  ' '终止代数=' num2str(maxgen)]);
xlabel('进化代数');ylabel('适应度');

其中子函数包括fun.m, Cross.m, Mutation.m,
test.m,

fun.m如下

function y = fun(x,data,tilt)
if(size(data,2) > 4)
    A1 = data(:,7);
    alpha = data(:,6);
    y = 0;
    for i=1:size(A1,1)
        y=y+alpha(i,1)*sin((alpha(i,1)+x(1)+tilt)*2*pi/360)*cos((A1(i,1)+140+x(2))*2*pi/360);
    end
    y = -y;
elseif size(data,2) == 3
    A1 = data(:,3);
    alpha = data(:,2);
    y = 0;
    for i=1:size(A1,1)
        y=y+alpha(i,1)*sin((alpha(i,1)+x(1)+tilt)*2*pi/360)*cos((A1(i,1)+140+x(2))*2*pi/360);
    end
    y = -y;
else
    A1 = data(:,2);
    alpha = data(:,1);
    y = 0;
    for i=1:size(A1,1)
        y=y+alpha(i,1)*sin((alpha(i,1)+x(1)+tilt)*2*pi/360)*cos((A1(i,1)+140+x(2))*2*pi/360)+0.4*alpha(i,1)*(1+cos((x(1)+tilt)*2*pi/360))/2+0.2*alpha(i,1)*(1-cos((x(1)+tilt)*2*pi/360))/2;
    end
    y = -y;
end
end

Cross.m如下

function ret=Cross(pcross,lenchrom,chrom,sizepop,bound)
%本函数完成交叉操作
% pcorss                input  : 交叉概率
% lenchrom              input  : 染色体的长度
% chrom                 input  : 染色体群
% sizepop               input  : 种群规模
% ret                   output : 交叉后的染色体

for i=1:sizepop 

    % 随机选择两个染色体进行交叉
    pick=rand(1,2);
    while prod(pick)==0
        pick=rand(1,2);
    end
    index=ceil(pick.*sizepop);
    % 交叉概率决定是否进行交叉
    pick=rand;
    while pick==0
        pick=rand;
    end
    if pick>pcross
        continue;
    end
    flag=0;
    while flag==0
        % 随机选择交叉位置
        pick=rand;
        while pick==0
            pick=rand;
        end
        pos=ceil(pick.*sum(lenchrom)); %随机选择进行交叉的位置,即选择第几个变量进行交叉,注意:两个染色体交叉的位置相同
        pick=rand; %交叉开始
        v1=chrom(index(1),pos);
        v2=chrom(index(2),pos);
        chrom(index(1),pos)=pick*v2+(1-pick)*v1;
        chrom(index(2),pos)=pick*v1+(1-pick)*v2; %交叉结束
        flag1=test(lenchrom,bound,chrom(index(1),:));  %检验染色体1的可行性
        flag2=test(lenchrom,bound,chrom(index(2),:));  %检验染色体2的可行性
        if   flag1*flag2==0
            flag=0;
        else flag=1;
        end    %如果两个染色体不是都可行,则重新交叉
    end
end
ret=chrom;

Mutation.m如下

function ret=Mutation(pmutation,lenchrom,chrom,sizepop,pop,bound)
% 本函数完成变异操作
% pcorss                input  : 变异概率
% lenchrom              input  : 染色体长度
% chrom                 input  : 染色体群
% sizepop               input  : 种群规模
% pop                   input  : 当前种群的进化代数和最大的进化代数信息
% ret                   output : 变异后的染色体

for i=1:sizepop  
    % 随机选择一个染色体进行变异
    pick=rand;
    while pick==0
        pick=rand;
    end
    index=ceil(pick*sizepop);
    % 变异概率决定该轮循环是否进行变异
    pick=rand;
    if pick>pmutation
        continue;
    end
    flag=0;
    while flag==0
        % 变异位置
        pick=rand;
        while pick==0
            pick=rand;
        end
        pos=ceil(pick*sum(lenchrom));  %随机选择了染色体变异的位置,即选择了第pos个变量进行变异
        v=chrom(i,pos);
        v1=v-bound(pos,1);
        v2=bound(pos,2)-v;
        pick=rand; %变异开始
        if pick>0.5
            delta=v2*(1-pick^((1-pop(1)/pop(2))^2));
            chrom(i,pos)=v+delta;
        else
            delta=v1*(1-pick^((1-pop(1)/pop(2))^2));
            chrom(i,pos)=v-delta;
        end   %变异结束
        flag=test(lenchrom,bound,chrom(i,:));     %检验染色体的可行性
    end
end
ret=chrom;

test.m如下

function flag=test(lenchrom,bound,code)
% lenchrom   input : 染色体长度
% bound      input : 变量的取值范围
% code       output: 染色体的编码值

flag=1;
[n,m]=size(code);

for i=1:n
    if code(i)<bound(i,1) || code(i)>bound(i,2)
        flag=0;
    end
end

第三题

题目要求如果在一个月的时间里考虑, 设计安装间距D、倾角和方位角等参数,使获得最大月产能, 其模型与第二题一致, 不同的是数据的不同, 为3255组一个月内不同的时间点的太阳方向角及高度角数据, 因此求解过程也与第二问类似, 仍然选用第二题的GA-PSO算法对第三题进行求解. 算法的迭代次数为100次, 种群规模pop-size为50, 交叉概率pc为0.7, 变异概率pm为0.3, 程序的迭代过程如下图所示

所得结果为 倾角19.0518度(百分制单位), 方向角1.2331度, 间距1.6824米.
代码如下

clear
lenchrom=2;    %字符串长度(个体长度),染色体编码长度
pc=0.7;        %设置交叉概率,本例中交叉概率是定值,若想设置变化的交叉概率可用表达式表示,或从写一个交叉概率函数,例如用神经网络训练得到的值作为交叉概率
pm=0.3;        %设置变异概率,同理也可设置为变化的
data = xlsread('/Users/xuguodong/Desktop/4/4/data2.xlsx');
tilt = 5.71;
height = 1.8;
%粒子群算法中的两个参数
c1 = 0.5;
c2 = 0.5;

maxgen=80;   % 进化次数  
popsize=50; %种群规模

%粒子更新速度
Vmax=1;
Vmin=-1;

% 变量取值范围
bound=[2 60;0 80];  %变量范围

% 优化粒子数目
par_num=2;
h = waitbar(0, 'couting...');
%% 产生初始粒子和速度
for i=1:popsize
    %随机产生一个种群
    pop(i,1)=bound(1,1)+rand*(bound(1,2)-bound(1,1));%初始种群
    pop(i,2)= 80 .* rand;
    V(i,:)=rand(1,par_num);  %初始化速度
    %计算适应度
    fitness(i)=fun(pop(i,:), data, tilt);   %染色体的适应度
end

%找最好的染色体
[bestfitness bestindex]=min(fitness);
zbest=pop(bestindex,:);   %全局最佳
gbest=pop;    %个体最佳
fitnessgbest=fitness;   %个体最佳适应度值
fitnesszbest=bestfitness;   %全局最佳适应度值

%% 迭代寻优
for i=1:maxgen
    for j=1:popsize

        %速度更新 PSO选择更新
        V(j,:) = V(j,:) + c1*rand*(gbest(j,:) - pop(j,:)) + c2*rand*(zbest - pop(j,:));
        V(j,find(V(j,:)>Vmax))=Vmax;
        V(j,find(V(j,:)<Vmin))=Vmin;

        %种群更新 PSO选择更新
        pop(j,:)=pop(j,:)+0.5*V(j,:);
        pop(j,find(pop(j,1)>80))=80;
        pop(j,find(pop(j,1)<0))=0;
        pop(j,find(pop(j,2)>20))=20;
        pop(j,find(pop(j,2)<0))=0;


        GApop=Cross(pc,lenchrom,pop,popsize,bound);

        % 变异操作 GA变异
        GApop=Mutation(pm,lenchrom,GApop,popsize,[i maxgen],bound);

        pop=GApop; % GA pop --> PSO pop
        fitness(j)=fun(pop(j,:),data,tilt);
        %个体最优更新
        if fitness(j) < fitnessgbest(j)
            gbest(j,:) = pop(j,:);
            fitnessgbest(j) = fitness(j);
        end

        %群体最优更新
        if fitness(j) < fitnesszbest
            zbest = pop(j,:);
            fitnesszbest = fitness(j);
        end
    end
    yy(i)=fitnesszbest;    
    waitbar(i/maxgen);
end

%% 结果
disp '*************result****************'
betaj = zbest(1)
rj = zbest(2)-40
a = mean(data(:,1));
close(h);
D = height*sin((a+betaj)*pi/180)/sin((a+betaj+tilt)*pi/180)
%%
plot(yy,'linewidth',2);
grid on
title(['适应度曲线  ' '终止代数=' num2str(maxgen)]);
xlabel('进化代数');ylabel('适应度');

第四题

改变的是目标函数的值, 只改变了fun.m, 代码不再贴了, 主要的改变的由于需要做出程序的GUI, 此时优化模型就更加宽泛了. 所以在这里使用了sun_position函数来对输入的经纬度与海拔计算该地2017年一整年的数据, 具体为以分钟为单位的518400组太阳高度角与方向角数据, 并利用该数据为基础结合第四问的模型以及GA-PSO算法来为该
住房进行优化计算.

GUI设计

利用matlab设计的程序gui如下图所示

使用过程如下步骤

  1. 输入优化所需的参数.
  2. 点击开始优化就开始优化了.
  3. 优化结果如下图所示

可以看到优化的最终结果为间距D为1.6724米, 方向角p为38.5359度, 倾角a 为22.9018度

GUI代码

gui的代码由于太冗长, 就不贴上来了, 这里只把GUI的按钮call_back上传, 是程序的核心控制部分, 不得不得说matlab的GUIDE确实好用..

function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
location.longitude = str2num(get(handles.edit1,'String'));
location.latitude = str2num(get(handles.edit2,'String'));
location.altitude = str2num(get(handles.edit3,'String'));
toward = str2num(get(handles.edit9,'String'));
tilt = str2num(get(handles.edit6,'String'));
height= str2num(get(handles.edit7,'String'));
[beta, r, D] = loc_pso(location,tilt,height,toward);
set(handles.edit4,'String',num2str(beta));
set(handles.edit5,'String',num2str(r));
set(handles.edit8,'String',num2str(D));
guidata(hObject, handles);

按钮处的代码如上

核心函数loc_pso

具体的, 其中的loc_pso是封装好的核心求解优化函数, 其代码如下.

function [betaj,rj,D] = loc_pso(location,tilt,height, toward)

lenchrom=2;    %字符串长度(个体长度),染色体编码长度
pc=0.7;        %设置交叉概率,本例中交叉概率是定值,若想设置变化的交叉概率可用表达式表示,或从写一个交叉概率函数,例如用神经网络训练得到的值作为交叉概率
pm=0.3;        %设置变异概率,同理也可设置为变化的
nyears = 1;
time.sec = 30;
time.UTC = -7;
i = 1;
h = waitbar(0, 'counting...');
for timeyear = 1:nyears
    for timemonth = 1:12,
        for timeday = 1:30,
            for timehour = 1:24,
                for timemin = 1:60,
                    time.year = timeyear+2016;
                    time.month = timemonth;
                    time.day = timeday;
                    time.hour = timehour;
                    time.min = timemin;
                    sun = sun_position(time, location);
                    data(i,1) = 90-sun.zenith;
                    data(i,2) = sun.azimuth;
                    i = i+1;
                end
            end
        end
        timemonth
    end
    waitbar(timeyear/103);
end
size(data)
%粒子群算法中的两个参数
c1 = 0.5;
c2 = 0.5;

maxgen=100;   % 进化次数  
popsize=50; %种群规模

%粒子更新速度
Vmax=1;
Vmin=-1;

% 变量取值范围
bound=[5 80;0 80];  %变量范围

% 优化粒子数目
par_num=2;

%% 产生初始粒子和速度
for i=1:popsize
    %随机产生一个种群
    pop(i,1)=bound(1,1)+rand*(bound(1,2)-bound(1,1));%初始种群
    pop(i,2)= 80 .* rand;
    V(i,:)=rand(1,par_num);  %初始化速度
    %计算适应度
    fitness(i)=fun(pop(i,:), data, tilt);   %染色体的适应度
end

%找最好的染色体
[bestfitness bestindex]=min(fitness);
zbest=pop(bestindex,:);   %全局最佳
gbest=pop;    %个体最佳
fitnessgbest=fitness;   %个体最佳适应度值
fitnesszbest=bestfitness;%全局最佳适应度值

%% 迭代寻优
for i=1:maxgen
    for j=1:popsize

        %速度更新 PSO选择更新
        V(j,:) = V(j,:) + c1*rand*(gbest(j,:) - pop(j,:)) + c2*rand*(zbest - pop(j,:));
        V(j,find(V(j,:)>Vmax))=Vmax;
        V(j,find(V(j,:)<Vmin))=Vmin;

        %种群更新 PSO选择更新
        pop(j,:)=pop(j,:)+0.5*V(j,:);
        pop(j,find(pop(j,1)>80))=80;
        pop(j,find(pop(j,1)<0))=0;
        pop(j,find(pop(j,2)>20))=20;
        pop(j,find(pop(j,2)<0))=0;


        GApop=Cross(pc,lenchrom,pop,popsize,bound);

        % 变异操作 GA变异
        GApop=Mutation(pm,lenchrom,GApop,popsize,[i maxgen],bound);

        pop=GApop; % GA pop --> PSO pop
        fitness(j)=fun(pop(j,:), data, tilt);
        %个体最优更新
        if fitness(j) < fitnessgbest(j)
            gbest(j,:) = pop(j,:);
            fitnessgbest(j) = fitness(j);
        end

        %群体最优更新
        if fitness(j) < fitnesszbest
            zbest = pop(j,:);
            fitnesszbest = fitness(j);
        end

    end
    yy(i)=fitnesszbest;     
    waitbar((3+i)/(maxgen+3));
end

%% 结果
betaj = zbest(1);
rj = zbest(2)-40;
a = mean(data(:,1));
D = height*sin((a+betaj)*pi/180)/sin((a+betaj+tilt)*pi/180);
close(h);
end