改进遗传算法的参数反演--实例复现(详细注释)

目录

主函数:

计算适应度大小:

选择操作(论文中的竞争选择法,锦标赛选择法):

 交叉操作(论文中的离散交叉法):

变异操作(论文中的非均匀变异法):

生成测试数据

某次运行结果:

​​​​​​​

主函数:

%% 清除变量,导入数据
clear, clc;
load('Data_Create_For_Test.mat');
Data_real = Data_Create;

% 如果想导入EXCEL的数据,请注释掉上面两段代码,使用下面的一段代码
% Data_real = xlsread('Data_Create_For_Test.xlsx'); %导入EXCEL表格的真实数据
%% 初始化参数
Pc = 0.8; %交叉概率
Pm = 0.01; %变异概率
iter_max = 200; %最大进化代数,即最大迭代次数
iter = 1; %初始化进化代数,即当前迭代次数
N_chrom = 20; %种群染色体的数目,解的个数
N_gen = 3; %染色体基因的数目,自变量的个数(表示论文里需反演的三个参数Alpha, Beta, S)
Up_gen = [0.5; 0.01; 0.01]; %三个基因的上界取值范围(三个参数的取值范围, 根据实际情况设定) 
Down_gen = [0; 0; 0]; %三个基因的下界取值范围

%% 生成初始解
chrom = zeros(N_chrom, N_gen); %初始化染色体矩阵(解集)
for i = 1 : N_chrom %初始化N_chrom组的参数值
    chrom(i, 1) = Down_gen(1) + rand(1) * (Up_gen(1) - Down_gen(1)); %初始化Alpha(i)
    chrom(i, 2) = Down_gen(2) + rand(1) * (Up_gen(2) - Down_gen(2)); %初始化Beta(i)
    chrom(i, 3) = Down_gen(3) + rand(1) * (Up_gen(3) - Down_gen(3)); %初始化S(i)
end

fitness = zeros(N_chrom, 1); %初始化适应度矩阵(每一个解对应的适应度大小)
for i = 1 : N_chrom
    fitness(i) = CalFitness(Data_real, chrom(i, : ));  %计算每一个初始解对应的适应度大小
end

fitness_best = zeros(iter_max, 1); %初始化每一代的最优适应度大小
for i = 1 : iter_max
    fitness_best(i) = inf;   %初始化为无穷大
end

chrom_best = zeros(iter_max, N_gen); %初始化每一代的最优染色体


%% 进化迭代
[row, line] = size(chrom); %初始化选择操作中父本和母本的对数
dad_mom = zeros(2 * row, line);    %初始化父本和母本,这里奇数行号认为是父本,偶数行号认为是母本
New_chrom = zeros(2 * row, line);  %初始化交叉操作生成的新种群
for iter = 1 : iter_max
%% 选择操作(论文中的竞争选择法,锦标赛选择法)
    dad_mom = Selection(chrom, fitness);
    
%% 交叉操作(论文中的离散交叉法)
    New_chrom = Cross(dad_mom, Pc);
    
%% 变异操作(论文中的非均匀变异法)
    New_chrom = Mutation(New_chrom, Up_gen, Down_gen, iter, iter_max, Pm);

%% 计算新种群的适应度大小    
    [row, line] = size(New_chrom);
    New_fitness = zeros(row, line);
    for i = 1 : row
        New_fitness(i) = CalFitness(Data_real, New_chrom(i, : )); %计算每一个新染色体的适应度大小
        if New_fitness(i) < fitness_best(iter) %判断当前新染色体的适应度,是否优于本迭代次数的最优适应度
            fitness_best(iter) = New_fitness(i); %判断结果为是,则更新当前迭代次数的最优适应度
            chrom_best(iter, : ) = New_chrom(i, : ); %同时更新最优染色体
        end
    end
    
    if ( (iter ~= 1) && ( fitness_best(iter - 1) < fitness_best(iter) ) )
        fitness_best(iter) = fitness_best(iter - 1); %记录截止到当前迭代次数,最优的适应度大小
        chrom_best(iter, : ) = chrom_best(iter - 1, : ); %记录截止到当前迭代次数,最优的适应度对应的最优染色体
    end
 
%% 形成新的种群,用于下一次迭代(自然选择)
    Sort_fitness = sort(New_fitness); %排序新种群的适应度(注意这里适应度值的个数是N_chrom的两倍)
    for i = 1 : (row/2)
        index = find(New_fitness == Sort_fitness(i), 1);
        chrom(i, : ) = New_chrom(index, : );  %取适应度排名前50%的染色体,作为下一次迭代的新种群,这里可以理解为自然选择操作
    end
end

%% 绘图
figure(1)
plot(1:iter_max, fitness_best, 'r');
title('迭代图')
xlabel('迭代次数')
ylabel('适应度大小')
    
%% 输出结果
disp(['最优适应度:' num2str( fitness_best(iter) )])
disp(['Alpha最优参数值:' num2str( chrom_best(iter, 1) )]) 
disp(['Beta最优参数值:' num2str( chrom_best(iter, 2) )]) 
disp(['S最优参数值:' num2str( chrom_best(iter, 3) )]) 

计算适应度大小:

%% 计算适应度大小
function Fitness_Chrom = CalFitness(Data_real, chrom) 
%输入:真实观测数据Data_real(两列),包括时间t(第一列数据)和真实水位抬升值s(第二列数据)
%      染色体解集chrom(三列,分别代表三个参数alpha,beta,S)
%输出:适应度大小

M = 60; %含水层厚度
Q = 58; %定流量
r = 0.1; %井径
A = Q / (4 * pi * M); %论文中的斜率A
B = A * log( 2.25*M / (r*r) ); %论文中的截距B

Data_t = Data_real(:, 1); %取第一列数据,即时间t
Data_s = Data_real(:, 2); %取第二列数据,即观测到的真实水位抬升值s
Alpha = chrom(:, 1); %取第一列数据,即参数alpha
Beta = chrom(:, 2);  %取第二列数据,即参数Beta
S = chrom(:, 3);     %取第三列数据,即参数S

Data_num = size(Data_s, 1); %计算真实观测数据的数目
Error_sum = 0; %总误差的平方和,即优化目标
X = zeros(Data_num, 1);

for j = 1 : Data_num
    X(j) = -1*Beta*Data_t(j) + log( Alpha*Data_t(j) ) - log( S );  %计算时刻t(i)对应的X(i)
    error = Data_s(j) - ( A*X(j)+B ) / ( Alpha * exp( -1*Beta*Data_t(j) ) ); %计算时刻t(i)对应的误差(s-s*)
    Error_sum = Error_sum + abs(error * error); %计算总误差的平方和
end
    
Fitness_Chrom = Error_sum; %记录染色体(一组参数)对应的优化目标值

选择操作(论文中的竞争选择法,锦标赛选择法):

function dad_mom = Selection(chrom, fitness)
%% 选择操作(竞争选择法,锦标赛选择法)
% 输入:染色体种群, 适应度矩阵 
% 输出:选择操作得到的父本和母本(用于交叉操作)

sn = 3; %从种群中选择的个体数目,进行竞争
[row, line] = size(chrom); %选择父本和母本的对数
dad_mom = zeros(2 * row, line); %初始化父本和母本,这里奇数行号认为是父本,偶数行号认为是母本

for i = 1 : 2 : 2*row   %间距为2
    r = randi([1 row], sn, 1); %从[1,sum]中随机生成sn个整数,即随机抽出来进行比赛的个体编号
    index = find(fitness == min(fitness(r)), 1); %在进行比赛的个体中,找到适应度最优的个体编号,即在原种群chrom中对应的编号
    dad_mom(i, : ) = chrom(index, : ); %将比赛胜出者作为父本
    dad_mom(i+1, : ) = chrom(randi([1, row]), : ); %随机选择一个个体作为母本
end

 交叉操作(论文中的离散交叉法):

function New_chrom = Cross(dad_mom, pc)
%% 交叉操作(离散交叉法)
%输入:选择操作得到的父本和母本;交叉概率
%输出:交叉操作后的新种群(子本)
[row, line] = size(dad_mom);
New_chrom = zeros(row, line); %初始化交叉操作的新种群
for i = 1 : 2 : row
    if rand < pc  %生成一个随机数,判断是否进行交叉操作
        for j = 1 : line %进行交叉操作
            if randi([0, 1]) == 1 %随机数为1,则对应基因不进行交叉操作
                New_chrom(i, j) = dad_mom(i, j);
                New_chrom(i+1, j) = dad_mom(i+1, j);
            else                  %随机数为0,则相邻两个个体(即父本和母本),进行相应基因的交叉操作(互换基因)
                New_chrom(i, j) = dad_mom(i+1, j);
                New_chrom(i+1, j) = dad_mom(i, j);
            end
        end
    else          %不进行交叉操作
        New_chrom(i, : ) = dad_mom(i, : ); %子代保持不变
        New_chrom(i, : ) = dad_mom(i+1, :); %子代保持不变
    end
end

变异操作(论文中的非均匀变异法):

function New_chrom = Mutation(Cross_chrom, Up_gen, Down_gen, iter, iter_max, pm)
%% 变异操作(非均匀变异法)
%输入:交叉操作得到的新种群;基因的上界;基因的下界;当前迭代次数;最大迭代次数;变异的概率
%输出:变异操作后的新种群
[row, line] = size(Cross_chrom);
New_chrom = zeros(row, line); %初始化变异操作得到的新种群

b = 2; %非均匀变异公式中的常数
a = 1 - iter/iter_max; %此常数随当前迭代次数的变化而变化,具体见非均匀变异中的公式

for i = 1 : row      %遍历每一个染色体,即每一个解
    for j = 1 : line %遍历每一个基因,即要求解的参数(这里可以根据个人情况修改代码,如果你只想变异一个特定的基因,只需只定j为特定常数)
        r = rand;    %生成一个随机数,表示非均匀变异公式中随机数
        if rand < pm    %判断是否发生变异操作(此处为发生变异操作)
            if randi([0, 1]) == 1 
                New_chrom(i, j) = Cross_chrom(i, j) + ( Up_gen(j) - Cross_chrom(i, j) ) * ( 1 - r^(a*b) );   %公式1
            else
                New_chrom(i, j) = Cross_chrom(i, j) + ( Cross_chrom(i, j) - Down_gen(j) ) * ( 1 - r^(a*b) ); %公式2
            end
        else
            New_chrom(i, j) = Cross_chrom(i, j); 
        end
    end
end

生成测试数据

%% 生成测试数据
clear, clc;
M = 60; %含水层厚度
Q = 58; %定流量
r = 0.1; %井径
A = Q / (4 * pi * M); %论文中的斜率A
B = A * log( 2.25*M / (r*r) ); %论文中的截距B

Alpha = 0.346; %参数1
Beta = 0.0044; %参数2
S = 0.00192;   %参数3

Sum = 15;
Data_Create = zeros(Sum, 2);
X = zeros(Sum, 1);
for i = 1 : 15
    Data_Create(i, 1) = i;
    X(i) = -1*Beta*Data_Create(i, 1) + log( Alpha * Data_Create(i, 1) ) - log( S );
    Data_Create(i, 2) = ( A*X(i)+B ) / ( Alpha * exp( -1*Beta*Data_Create(i, 1) ) );
end

save Data_Create_For_Test.mat  Data_Create;

算法使用的算子公式参考视频

参考论文链接

某次运行结果:

 

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值