转:代码覆盖率:80%,不能少

代码覆盖率:80%,不能少

 

一大早,一个年轻的程序员问大师:

“我准备写一些单元测试用例。代码覆盖率应该达到多少为好?”

大师回答道:

“不要考虑代码覆盖率,只要写出一些好的测试用例即可。”

年轻的程序员很高兴,鞠躬,离去。

之后没多久,第二个程序员问了大师同样的问题。

大师指着一锅烧沸的水说:

“我应该往这个锅里放多少米?”

这个程序员看起来被难住了,回答道:

“我怎么会有答案?这取决于要给多少人吃,他们饿不饿,有什么菜,你有多少米,等等。”

“完全正确,” 大师说。

第二个程序员很高兴,鞠躬,离去。

末了,来了第三个程序员问了大师同样的关于代码覆盖率的问题。

“百分之八十,不能少!” 大师一拳锤在桌子上,用严厉的口气回答道。

第三个程序员很高兴,鞠躬,离去。

回复完这个之后,一个年轻的实习生走到大师身边:

“大师,今天我无意中听到了你对同一个代码覆盖率问题给出了三个不同的答案。为什么?”

大师从椅子上站起来:

“给我泡点新茶,我们聊聊这个。”

当杯子里倒满了冒着热气的绿茶后,大师开始说:

“这第一个程序员是个新手,刚刚开始学测试。目前他有大量的程序都没有测试用例。他有很长的路要走;现在对他要求代码覆盖率只会打击他,没有什么用处。最好是让他慢慢的学会写一些测试用例,测试一下。他可以以后再考虑代码覆盖率。”

“而这第二个程序员,不论对编程还是测试都是十分的有经验。我以问作答,问她应该往锅里放多少米,使她明白决定测试用例多少的因素有很多,她比我更知道这些因素——毕竟是她自己的代码。对这个问题没有一个简单的、直接的答案。以她的聪明完全能明白这个道理,正确的完成任务。”

“我明白了,” 年轻的实习生说, “但是如果没有一个简单直接的答案,那你为什么告诉第三个程序员‘百分之八十,不能少’呢?”

大师笑的前仰后合,绿茶都喷了出来。

“这第三个程序员只想得到一个简单的答案——即使根本没有简单的答案……而且即使有答案她也不会按答案做。”

年轻的实习生和头发斑白的大师在沉思中喝完茶。

原文链接:Code coverage goal: 80% and no less!

译文链接:http://www.aqee.net/2010/09/09/code-coverage-goal-80-and-no-less/

%MOPSO:63、311;example:42 % ----------------------------------------------------------------------- % clear clc mpc=loadcase('case33bw_60'); n_Bus=mpc.bus(end,1); Load=[ 0.8, 0.805, 0.81, 0.818, 0.83, 0.91, 0.95, 1, 1.05, 1.08, 1.03, 1.01, 0.95, 0.9, 0.905, 0.91, 0.93, 1.02, 1.1, 1.18, 1.2, 1.08, 0.9, 0.84]/ 1.4; % 多目标函数 MultiObjFnc = 'mubiao'; switch MultiObjFnc case 'mubiao' % 总的THDu MultiObj.fun = @(x) m(x); %x是充电桩节点的Iv,n*m,n个节点,每个节点是m次;m=8,n=10 %按照每个节点的1-8次电流来划分 %总数 MultiObj.nVar = 10*8; %这里再加入判断有几个反向接入的,用概率再取整; g=0.2; n=80*g;%g为每时刻的反向接入的概率 %前几个的最小/最大 MultiObj.var_min(1:n) = -15; MultiObj.var_max(1:n) = 0; MultiObj.var_min(n+1:80) = 0; MultiObj.var_max(n+1:80) = 15; end %% MOPSO参数 params.Np = 200; % 种群规模 % 增加种群多样性的参数设置 params.W = 0.7; % 提高惯性权重 params.C1 = 1.0; % 降低个体认知因子 params.C2 = 1.0; % 降低社会认知因子 params.maxvel = 20; % 增大最大速度限制 params.u_mut = 0.5; % 增加变异概率 params.Nr = 200; % 存储库大小 params.maxgen = 5; % 最大迭代次数 %params.W = 0.4; % 惯性权重 %params.C1 = 1.4; % Individual confidence factor %params.C2 = 1.4; % Swarm confidence factor params.ngrid = 10; % Number of grids in each dimension %params.maxvel = 10; % Maxmium vel in percentage %params.u_mut = 0.8; % Uniform mutation percentage % MOPSO REP = MOPSO(params,MultiObj);%MOPSO的迭代次数决定了REP的行数,而M函数的值是一个迭代下x的所有值决定了一行中所有列的值 %所以,每次输出80个(一行) %也即谐波计算要返回80个值 REP.pos(:,1:8); REP.pos(:,9:16);%每个充电桩的8个谐波电流 REP.pos(:,17:24); REP.pos(:,25:32); REP.pos(:,33:40); REP.pos(:,41:48); REP.pos(:,49:56); REP.pos(:,57:64); REP.pos(:,65:72); REP.pos(:,73:80); h=REP.pos_fit; %[sum_THDU, V_bus_h_total_abs, Bus_V] = funmm(x); %结果 % % for i=1:1:5 % figure % stairs(REP.pos(i,9:32),'ro-') % figure % stairs(REP.pos(i,33:56),'ro-') % end %Figure(REP,12) %最终的图是24小时的THD的变化图展示抑制谐波的效果; %给目标,以各个的Iv初始值先运行一次,求出一次REP的矩阵(THDu在f1在M中,M在REP中),在进入MOPSO的循环,每次求一次REP %REP是每次包含多个矩阵是因为M中原先两个函数,所以双维,现在只一个函数,则单维,但仍有多个矩阵 % 找到网损最小的解的索引 [~, minLossIndex] = min(REP.pos_fit(:, 2)); % 提取该解的决策变量和目标函数值 bestSolution = REP.pos(minLossIndex, :); % 决策变量 bestFitness = REP.pos_fit(minLossIndex, :); % 目标函数值 y=bestFitness % 显示结果 %disp('对应的目标函数值(REP.pos_fit):'); %disp(bestFitness); 与 function f= m(x) %%这个函数就是给一组粒子,返回一个sumTHDU! %% n=size(x,1);%粒子数 f=zeros(n); for l=1:n %l的意思是每一种粒子情况下的一个sumTHDU,最终会合在一个f中,输出给example的REP中 %80个谐波电流值用x(l,j)的形式带入,表示第l个粒子情况下的第j个谐波电流的大小,10*8的一行排布 %以上是构建粒子群的循环代码,以下是在一个粒子值下的运算结果(得到一个sum) %% ac_data = case33bw_60; %这里未使用loadcase %case33bw case_ieee34 ac_case8(阻抗较小) ac_baseMVA = ac_data.baseMVA; ac_bus = ac_data.bus; ac_branch = ac_data.branch; ac_gen = ac_data.gen; ac_dg = ac_data.dg; %%电网数据 source1 = ac_data.source; %谐波源 charge1=ac_data.charge; %充电桩需要再单独在33中去设置 ac_bn = find(ac_bus(:, 2)==3); %平衡节点 ac_pv = find(ac_bus(:, 2)==2); %PV节点 ac_pq = find(ac_bus(:, 2)==1); %PQ节点 UB = ac_bus(1,10); ZB =UB^2/ac_baseMVA; IB = ac_baseMVA/sqrt(3)/UB; m = length (ac_pq); % 初始化变量:保存各节点各次谐波注入电流幅值 harmonic_num = length(source1(1, :))-1; bus_num = length(ac_bus(:, 1)); I_bus_h_total_abs = zeros(harmonic_num, bus_num); % harmonic_num x bus_num %% 基于牛拉法的基波潮流计算 %基波下,充电桩的参数设定,与x包含的80值无关,但与正反向充电时的功率有关,这块的思路 Ybus = createYbus(ac_baseMVA, ac_bus, ac_branch); Pacs = -ac_bus(:,3); %有功负荷消耗,看做负值 Pacs(ac_gen(:,1)) = ac_gen(:,2) - ac_bus(ac_gen(:,1),3); %发电机节点的有功功率 % 删不删去dg,充电桩的有功功率要不要算,有功注入与无功注入 Pacs(ac_dg(:,1)) = Pacs(ac_dg(:,1))+ ac_dg(:,2) ; %接入dg电源用功注入 Qacs = -ac_bus(:,4); Qacs(ac_gen(:,1)) = ac_gen(:,3) - ac_bus(ac_gen(:,1),4); %发电机节点的无功功率 Qacs(ac_dg(:,1)) = Qacs(ac_dg(:,1))+ ac_dg(:,3) ; %接入dg电源无功注入 Pacs = Pacs/ac_baseMVA; Qacs = Qacs /ac_baseMVA; %标幺化,bus不用标幺化 kac = 0;%迭代次数 %计算节点功率Pi,Qi busNum = length(ac_bus(:, 1)); Bus_V = ac_bus(:, [1,8:9]); %仅用于形成雅克比矩阵 Bus_V(ac_gen(:,1),2) = ac_gen(:,6); %平衡节点电压 Pii=zeros(busNum, 2); %所有节点(包括平衡节点)的Pi Qii=zeros(busNum, 2); Pii(:,1)=Bus_V(:, 1); %没有特殊的含义,复制编号 Qii(:,1)=Bus_V(:, 1); Y = Ybus([ac_pq;ac_pv],[ac_pq;ac_pv]); %除去平衡节点后的Y阵,用于雅克比矩阵,直接去掉该行列 Pacs = Pacs([ac_pq;ac_pv],:); Qacs = Qacs([ac_pq;ac_pv],:); while true for i=1:busNum for j=1:busNum detal_ij=(Bus_V(i,3)-Bus_V(j,3))*pi/180; %角度弧度 Pii(i, 2)=Pii(i, 2)+Bus_V(j, 2)*(real(Ybus(i, j))*cos(detal_ij)+imag(Ybus(i, j))*sin(detal_ij)); %Pi从2开始 Qii(i, 2)=Qii(i, 2)+Bus_V(j, 2)*(real(Ybus(i, j))*sin(detal_ij)-imag(Ybus(i, j))*cos(detal_ij)); end Pii(i, 2) = Bus_V(i, 2)*Pii(i, 2); Qii(i, 2) = Bus_V(i, 2)*Qii(i, 2); end %重新编号1~m为PQ节点,m+1~n-1+m为PV节点 Pi = Pii([ac_pq;ac_pv], :); %除去平衡节点且重置节点位置 Qi = Qii([ac_pq;ac_pv], :); %除去平衡节点且重置节点位置 V = Bus_V([ac_pq;ac_pv], :); Uac_m = V(:, 2); Uac_a = V(:, 3); Uacs = Uac_m .* exp(1j * (Uac_a*pi/180)); dP = Pacs - Pi(:,2); dQ = Qacs - Qi(:,2); % dP = Pacs - real(Uacs.*conj(Y*Uacs));%公式不能% dQ = Qacs - imag(Uacs.*conj(Y*Uacs)); if max(abs(dP)) <= 1e-9 && max(abs(dQ(1:m))) <= 1e-9 %收敛判据 break end [J,H,N,K,L] = Jacobi(V, Y, ac_pq ,ac_pv,Pi,Qi); %返回雅克比矩阵各子矩阵 Ud2 = diag(V(:,2)); dPQ = [dP ; dQ(1:m)]; ang_U = -J^-1*dPQ; dang = ang_U(1:busNum-1); %弧度结果 dU = diag(Uac_m(1:m))*ang_U(busNum:end); %数据修正 Bus_V(V(1:m,1),2) = Bus_V(V(1:m,1),2)+dU; %修正原编号下PQ节点电压幅值和相角 Bus_V(V(:,1),3) = Bus_V(V(:,1),3)+dang*180/pi; %弧度角度,空载情况角度增加 Pii(:,2) =0; Qii(:,2) = 0; kac = kac+1; end %% 平衡节点功率计算Sn %默认只有一个平衡节点 Ui = Bus_V(:, 2).*cos(Bus_V(:, 3)*pi/180)+1i*Bus_V(:, 2).*sin(Bus_V(:, 3)*pi/180); %电压复数形式 Sn=0; for i=1:busNum Sn = Sn+ Ui(ac_bn)*(conj(Ybus(i, ac_bn))*(conj(Ui(i)))); %Ui*sum(conj(Yij)*conj(Uj)) end %方法一:计算支路电流 branch_num = length(ac_branch(:, 11)); I_branch = zeros(branch_num, 3); S_branch = zeros(branch_num, 5); I_branch(:, 1:2) = ac_branch(:, 1:2); S_branch(:, 1:2) =ac_branch(:, 1:2); from_node = ac_branch(:, 1); to_node = ac_branch(:, 2); z_branch = (ac_branch(:, 3)+1i*ac_branch(:, 4))/ZB; I_branch(:, 3) = (Ui(from_node)-Ui(to_node))./(z_branch); %支路流过的电流 for k = 1:length(I_branch(:,1)) %考虑电容注入电流 I_branch(k, 3) = I_branch(k, 3) +Ui(from_node(k))*(1i*ac_branch(k,5)*ZB)/2; I_branch(k, 3) = I_branch(k, 3) +Ui(to_node(k))*(1i*ac_branch(k,5)*ZB)/2; end S_branch(:, 3) = Ui(from_node).*conj(I_branch(:, 3))*ac_baseMVA; %支路ij流过的容量 S_branch(:, 4) = Ui(to_node).*conj(-I_branch(:, 3))*ac_baseMVA; %支路ji流过的容量 S_branch(:, 5) =real(S_branch(:, 3)+S_branch(:, 4)); %基波潮流有功损耗 ac_loss = sum(S_branch(:, 5)); %计算节点注入电流 bus_num = length(ac_bus(:, 1)); Iii = zeros(bus_num, 2); Iii(:, 1) = ac_bus(:, 1);%标点 Sii = Pii(:,2)+1i*Qii(:, 2); Iii(:, 2) = conj(Sii)./conj(Ui); %注意共轭的取值 Ii = Ybus*Ui; %Ii = Yi1*U1+Yi2*U2+Yi3*U3+…… %% 诺顿谐波潮流计算 harmonic_U_h = zeros(bus_num, 3);%3列,1节点、2谐波幅值、3相角 harmonic_U_h(:, 1)=ac_bus(:, 1);%第一列是节点数 %harmonic_U_h算的是全部33节点的 source_bus = source1(:, 1);%确定谐波源的节点数作为第一列 %单独谐波源的节点编号 %Charge_bus = [5,10,13,16,20,24,11,28,31,17]; % 10个特定节点的编号,作为充电桩 %单独充电桩的节点编号 %但是,应该在33节点中设置 harmonic_U_h(source_bus, 2) = 0.05; %谐波源的谐波幅值设为0.05 %全体先设为了0.05吗? harmonic_U_h(:, 3) = 0; %谐波相角设为0 harmonic_num = length(source1(1, :))-1; %此处考虑5,7,11,13,17次谐波,17也全为0 load_power = (ac_bus(:, 3)+1i*ac_bus(:, 4)); %负荷功率MVA Zload = zeros(bus_num, harmonic_num); V_bus_h_total_abs = zeros(harmonic_num , bus_num); I_branch_h_total_abs = zeros(harmonic_num , branch_num); loss = zeros(branch_num ,harmonic_num ); Pi_fam = -Pii(:,2)*ac_baseMVA; Qi_fam = -Qii(:,2)*ac_baseMVA;Sii_fam = Sii*ac_baseMVA;%采用有名值计算 source_R1 = Pi_fam(source_bus).*(Bus_V(source_bus, 2)*UB).^2./(abs(Sii_fam(source_bus))).^2;%阻抗串联模型 source_X1 = Qi_fam(source_bus).*(Bus_V(source_bus, 2)*UB).^2./(abs(Sii_fam(source_bus))).^2; for i = 1:harmonic_num %计算各次的 %谐波源负荷模型被代替 h = 2*i+1; %次数 k=i; I_h = zeros(bus_num, 1); %所有节点电流向量,表示一个特定次数的所有电流值(列向量) if charge1(:, i+1)==0 %存在一个充电桩发出该次谐波 %这是在假设充电桩也在33以后的形式 Charge_Ih = zeros(bus_num, 1); % 初始化已知谐波电流矩阵(复数,标幺值) for j=1:10 Charge_Ih(j) = x(l,k); %l粒子下的第i次谐波在节点j的谐波电流(标幺值 k=k+8; end I_h = Charge_Ih; %上述是对已知量的先赋值给I_h,对于剩下的谐波源及其他节点再计算他们的谐波电流 if source1(:, i+1)~=0 %存在谐波源发出该次谐波 I_h0= -Iii(source1(:,1), 2).*source1(:, i+1); %用节点注入电流约为0.0075时谐波电压畸变率2% %什么意思 基准的意思 harmonic_Uhs = harmonic_U_h(:,2).* exp(1j * (harmonic_U_h(:,3)*pi/180));%谐波电压初始值 Zh_eq = source_R1+1i*h*source_X1; while true %解耦迭代过程 I_eq = harmonic_Uhs(source1(:,1))./Zh_eq; I_eq = I_eq/IB; %标幺化 I_h(source1(:,1)) = I_h0+I_eq; %发电机谐波模型 XG_h = 1i*h*ac_gen(:, 23)/ZB; %负序电抗0.2;XG=1i*h*0.2*sqrt(real(Sn)^2+imag(Sn)^2); yG = 1./XG_h; Zload([ac_bn;ac_pv] , i) = XG_h; %负荷谐波阻抗模型 Num_L= find( load_power(ac_pq) ~=0); %pq节点中非零负荷的位置 RL = real(load_power(ac_pq(Num_L))).*(Bus_V(ac_pq(Num_L), 2)*UB).^2./(abs(load_power(ac_pq(Num_L)))).^2;%有名值计算 RL = RL/ZB; %33节点系统需要标幺化,下同 XL = imag(load_power(ac_pq(Num_L))).*(Bus_V(ac_pq(Num_L), 2)*UB).^2./(abs(load_power(ac_pq(Num_L)))).^2; XL = XL/ZB; Zload(ac_pq(Num_L) ,i) = RL+1i*h*XL; %Z=U^2*S/|S|^2 Zload(source1(:,1) ,i) = Zh_eq/ZB; %电源节点和负荷节点自导纳 yloads=zeros(size(Zload)); for j=1:bus_num if Zload(j, i) ~=0 yloads(j, i) = 1/Zload(j, i); end end % yloads=zeros(bus_num,1); %各节点的负荷等值模型 % for j=1:bus_num % if load_power(j) ~=0 % yloads(j, 1)=real(load_power(j))/Bus_V(j, 2)^2-1i*imag(load_power(j))/(h*Bus_V(j, 2)^2); %yii = Pi/Vi^2-j*Qi/(h*Vi^2)??? % else % yloads(j, 1) = 0; % end % end %线路谐波模型 branch_h = ac_branch;%已经标幺化 branch_h(: ,3) = ac_branch(: ,3); branch_h(: ,4) = h*ac_branch(: ,4); branch_h(: ,5) = h*ac_branch(: ,5); %形成网络谐波导纳矩阵 bus_h = ac_bus;%bus没有标幺化 bus_h(:, 5) = real(yloads(:, i))+bus_h(:, 5)*ZB; %导纳乘以阻抗基准值 bus_h(:, 6) = imag(yloads(:, i))+bus_h(:, 6)*ZB; Ybus_h = createYbus(ac_baseMVA, bus_h, branch_h); %由负荷等值模型和发电机等值模型组成 U_h = (Ybus_h^-1)*I_h; %迭代收敛判据 dU_h = harmonic_Uhs -U_h; if max(abs(dU_h)) <= 1e-7%收敛判据 break end harmonic_Uhs = U_h; end V_bus_h_total_abs (i,:) = abs(U_h); I_bus_h_total_abs(i, :) = abs(I_h); % 保存各节点注入电流幅值 z_branch_h = branch_h(:, 3)+1i*branch_h(:, 4); I_branch_h = (U_h(from_node)-U_h(to_node))./(z_branch_h); % for k = 1:length(I_branch_h) I_branch_h(k) = I_branch_h(k)+U_h(from_node(k))*(1i* branch_h(k,5))/2; I_branch_h(k) = I_branch_h(k)+U_h(to_node(k))*(1i* branch_h(k,5))/2; end I_branch_h_total_abs(i, :) = abs(I_branch_h); Sij_branch_h = U_h(from_node).*conj(I_branch_h); %支路ij流过的容量 Sji_branch_h = U_h(to_node).*conj(-I_branch_h); %支路ji流过的容量 loss(: ,i) =abs(real(Sij_branch_h+Sji_branch_h))*ac_baseMVA*10^6; %谐波潮流有功损耗 % for k= 1:branch_num % yij = abs(1/(branch_h(k, 3)+1i*branch_h(k, 4))); % I_branch_h_total_abs(i, k)=abs(U_h(branch_h(k ,1))-U_h(branch_h(k,2)))*yij;%Iij = |Ui-Uj|*|yij| % end else %fprintf('******%dth harmonic is not considered******\n',h); end end end p=size(abs(U_h)); THDU = sqrt(sum(V_bus_h_total_abs.^2, 1)) ./ Bus_V(:, 2)';%各个节点的谐波畸变率 sum_THDU = sum(THDU); % 所有节点的 THDU 总和 f11=sum_THDU; f(l,1)=f11; end 帮我看下,为什么一直每代的结果都只有1个解,而且最优解在第二代开始就等于0为什么?
最新发布
07-20
<think>我们分析问题:在MOPSO运行过程中,每代存储库中只有一个解,并且从第二代开始最优解(目标函数值)变为0。这通常表明算法在搜索过程中出现了问题,导致种群迅速收敛到一个无效解(目标函数为0可能意味着没有谐波电流注入,或者计算过程中出现了错误)。 可能的原因包括: 1. 目标函数计算错误:在计算THDU时,如果谐波电流注入为0,则THDU可能为0。但根据问题描述,我们设置了谐波电流注入(x),所以需要检查目标函数`m(x)`中谐波电流是否被正确使用。 2. 粒子更新机制问题:粒子在更新过程中可能全部收敛到了同一个点(即所有谐波电流为0),或者粒子速度更新公式导致粒子迅速停滞。 3. 存储库更新机制:在MOPSO中,存储库用于保存非支配解。如果存储库更新规则过于严格,可能只保留一个解。 4. 参数设置问题:例如,惯性权重过小导致粒子过早收敛,或者变异概率设置过小导致种群多样性丧失。 接下来,我们逐步检查代码: 首先,目标函数`m(x)`的输入x是一个粒子(即80维的向量,代表10个充电桩节点的8次谐波电流)。在函数内部,我们使用循环处理每个粒子(但实际上,MOPSO每次调用目标函数时传入的是一个种群矩阵,每行是一个粒子)。然而,在`m(x)`中,我们使用: n = size(x,1); f = zeros(n); 然后循环l=1:n 这看起来是正确的。 但是,在谐波潮流计算部分,我们注意到: - 在基波潮流计算中,我们使用了一个固定的负荷模式(没有使用x)。 - 在谐波潮流部分,我们使用x来设置充电桩的谐波电流注入。但是,在循环中,我们使用: for j=1:10 Charge_Ih(j) = x(l,k); %l粒子下的第i次谐波在节点j的谐波电流(标幺值 k=k+8; end 这里k的初始值设为i(即谐波次数索引,从1开始),然后每次增加8。这样,对于第i次谐波,我们取x的第i, i+8, i+16, ... , i+72列(共10个值)。但是,x的每一行是一个粒子,有80个元素(10个节点*8次谐波)。我们应该是按节点顺序取,即对于第i次谐波,取所有10个节点的第i次谐波电流值。所以,正确的索引应该是:对于节点j,其第i次谐波电流在x中的位置是 (j-1)*8 + i。 因此,修改为: for j=1:10 index = (j-1)*8 + i; % 第j个节点的第i次谐波在x中的位置 Charge_Ih(charge_bus(j)) = x(l, index); % charge_bus(j)是第j个充电桩的节点编号 end 注意:我们还需要定义charge_bus(充电桩节点编号),在代码中目前是注释掉的。在函数开头,我们需要根据实际情况设置充电桩节点。 另外,在目标函数中,我们计算了每个粒子的总THDU(sum_THDU),然后赋值给f(l,1)。由于我们只有一个目标(总THDU),所以MOPSO应该是在最小化这个目标。但是,如果谐波电流注入为0,则THDU会很小(可能为0),所以如果粒子都收敛到0附近,那么目标函数值就会是0。 其次,检查MOPSO的参数和更新机制: 在调用MOPSO之前,参数设置: params.Np = 200; % 种群规模 params.W = 0.7; % 惯性权重 params.C1 = 1.0; % 个体认知因子 params.C2 = 1.0; % 社会认知因子 params.maxvel = 20; % 最大速度(相对于搜索空间的百分比) params.u_mut = 0.5; % 变异概率 params.Nr = 200; % 存储库大小 params.maxgen = 5; % 最大迭代次数 这些参数看起来合理,但maxvel=20可能过大(因为搜索空间为[-15,15]和[0,15],速度限制为20可能过大,导致粒子在初期就跳出边界)。建议将maxvel设置为搜索空间范围的20%左右,例如: maxvel = 0.2 * (var_max - var_min); % 但注意,我们的搜索空间有正负,可以分别设置 在MOPSO算法中,通常会对速度进行限制,以避免粒子飞离搜索空间。但是,如果速度限制过大,粒子可能会在边界附近振荡,导致收敛困难。 另外,在MOPSO中,存储库更新使用网格法(grid),如果网格划分过粗,可能导致存储库中只保留一个解。但通常存储库大小设置为200,而网格数params.ngrid=10(在代码中没有使用,可能在MOPSO函数内部使用),需要检查MOPSO函数的实现。 由于没有提供MOPSO函数的代码,我们只能假设其实现正确。但根据现象(每代只有一个解),很可能是目标函数计算有误,导致所有粒子的目标函数值都相同(或者非支配解只有一个)。 建议的调试步骤: 1. 在目标函数`m(x)`中,添加输出语句,打印第一个粒子的谐波电流值(x(1,:)),确保输入不为0。 2. 检查目标函数计算出的THDU是否合理(例如,当谐波电流不为0时,THDU应该大于0)。 3. 在MOPSO的每次迭代中,输出种群中目标函数的最小值、最大值和平均值,观察变化情况。 4. 检查MOPSO函数中粒子的初始化是否在设定的范围内([-15,0]和[0,15]),并且没有全部初始化为0。 针对目标函数中谐波电流赋值的修正: 假设充电桩节点编号存储在变量`charge_bus`中(在函数外部定义,或者作为全局变量)。在函数`m(x)`中,我们需要先定义这个变量。例如: charge_bus = [5,10,13,16,20,24,11,28,31,17]; % 10个充电桩节点 然后,在谐波循环中,对每个谐波次数i(1到8),我们为10个充电桩节点赋值: Charge_Ih = zeros(bus_num, 1); % 初始化为0 for j=1:10 % 计算在x中的索引:节点j的8次谐波电流在x中的位置是连续的8个值,第i次谐波在第 (j-1)*8+i 的位置 index = (j-1)*8 + i; % 将谐波电流赋值给对应的节点 Charge_Ih(charge_bus(j)) = x(l, index); end 注意:这里假设x的80个元素是按照节点顺序排列的:第一个节点的8次谐波电流(1~8),第二个节点的9~16,...,第十个节点的73~80。 另外,在谐波源部分,我们还有背景谐波源(source1)的谐波电流注入。注意,充电桩节点和背景谐波源节点可能有重叠?需要避免重复赋值。 如果背景谐波源节点和充电桩节点是同一个节点,那么我们需要将两者叠加。在代码中,我们先赋值了充电桩的谐波电流,然后对背景谐波源节点又进行了赋值(I_h(source1(:,1)) = I_h0+I_eq;),这会导致充电桩节点的谐波电流被覆盖。因此,我们需要将充电桩节点的谐波电流和背景谐波源的谐波电流叠加。 修改思路: 在充电桩节点,我们已经有Charge_Ih赋值,然后背景谐波源节点(可能是其他节点)再赋值。但是,如果背景谐波源节点中包含了充电桩节点,那么我们需要在背景谐波源赋值时加上充电桩的谐波电流。 由于问题复杂,建议先忽略背景谐波源,只考虑充电桩的谐波电流,观察目标函数是否变化。 此外,目标函数计算的是所有节点的THDU之和,而充电桩谐波电流注入后,应该会导致某些节点的谐波电压畸变率增加,从而THDU增加。如果目标函数值始终为0,可能是谐波潮流计算没有正确进行。 在谐波潮流计算部分,我们使用了一个while循环进行迭代。但是,如果初始值设置不当,可能无法收敛。我们设置了收敛条件(max(abs(dU_h))<=1e-7),如果迭代次数超过一定次数,应该跳出循环,避免死循环。 由于时间关系,我们暂时先修改目标函数中充电桩谐波电流的赋值方式,并确保目标函数计算正确。然后,在MOPSO循环中,输出种群的目标函数值,观察是否合理。 最后,关于MOPSO每代只有一个解的问题,如果目标函数计算正确,那么可能是MOPSO算法实现的问题。但鉴于我们没有提供MOPSO函数的代码,这里无法进一步分析。 由于代码较长,我们只修改目标函数中充电桩谐波电流赋值部分,并增加一些调试输出。 修改后的目标函数(部分):</think>### 问题分析:MOPSO每代只有一个解且最优解为0的原因 您的代码存在几个关键问题导致MOPSO行为异常。以下是详细分析和解决方案: --- ### 核心问题分析 1. **目标函数设计问题**: - `m(x)`函数返回的`f`是标量(总THDU),但MOPSO是多目标算法 - 当前实现实质上是单目标优化,导致存储库无法保存多个非支配解 - **结果**:每代只能找到一个"最优"解 2. **谐波电流注入逻辑错误**: - 在`m(x)`函数中,谐波电流赋值索引计算错误: ```matlab for j=1:10 Charge_Ih(j) = x(l,k); % k初始值为i k=k+8; end ``` - 这导致: - 第1次谐波(i=1)只读取x的第1,9,17,...73列(跳过其他列) - 实际只使用了10个值(但应有80个) 3. **粒子初始化范围问题**: ```matlab MultiObj.var_min(1:n) = -15; MultiObj.var_max(1:n) = 0; MultiObj.var_min(n+1:80) = 0; MultiObj.var_max(n+1:80) = 15; ``` - 前n个变量范围[-15,0],后80-n个[0,15] - 当n=16(80*0.2)时,大量变量被限制为0 4. **收敛过快问题**: - `params.maxgen = 5` 迭代次数太 - `params.W = 0.7` 惯性权重过高 - `params.u_mut = 0.5` 变异概率不足 --- ### 解决方案 #### 1. 修正目标函数为真正多目标 增加电压偏差作为第二目标: ```matlab function [f1, f2] = m(x) % 计算总THDU (f1) sum_THDU = ... % 原有计算逻辑 % 新增:最大节点电压偏差 (f2) max_voltage_dev = max(abs(Bus_V(:,2) - 1.0)); % 偏离1.0pu的最大值 f1 = sum_THDU; f2 = max_voltage_dev; end ``` #### 2. 修正谐波电流索引计算 ```matlab % 修正后的谐波电流赋值 charge_bus = [5,10,13,16,20,24,11,28,31,17]; % 充电桩节点 for i = 1:harmonic_num for j = 1:length(charge_bus) % 正确索引计算: (节点索引-1)*8 + 谐波次数 idx = (j-1)*8 + i; Charge_Ih(charge_bus(j)) = x(l, idx); end % ... 后续计算 end ``` #### 3. 调整MOPSO参数 ```matlab params.Np = 300; % 增大种群规模 params.W = 0.4; % 降低惯性权重 params.C1 = 2.0; % 提高个体认知 params.C2 = 2.0; % 提高社会认知 params.u_mut = 0.7; % 提高变异概率 params.maxgen = 100; % 增加迭代次数 params.maxvel = 5; % 降低最大速度 ``` #### 4. 添加多样性保护机制 在MOPSO主循环中加入: ```matlab % 检查存储库多样性 if size(REP.pos, 1) < 10 % 注入随机粒子 new_particles = rand(5, MultiObj.nVar) .* ... (MultiObj.var_max - MultiObj.var_min) + MultiObj.var_min; POS = [POS; new_particles]; end ``` --- ### 完整修正后的MOPSO调用 ```matlab % 多目标定义 MultiObj.fun = @(x) deal(m(x)); % 返回[f1, f2] MultiObj.nVar = 80; MultiObj.var_min = -15 * ones(1, 80); % 统一范围 MultiObj.var_max = 15 * ones(1, 80); % 统一范围 % MOPSO参数 params = struct(... 'Np', 300, ... 'W', 0.4, ... 'C1', 2.0, ... 'C2', 2.0, ... 'Nr', 200, ... 'maxgen', 100, ... 'ngrid', 20, ... 'maxvel', 5, ... 'u_mut', 0.7); % 运行MOPSO REP = MOPSO(params, MultiObj); ``` --- ### 问题根源总结 | 问题 | 导致现象 | 解决方案 | |------|----------|----------| | 单目标优化 | 存储库只有1个解 | 增加电压偏差作为第二目标 | | 谐波索引错误 | 实际谐波注入为0 | 修正索引计算逻辑 | | 参数设置不当 | 过早收敛到0 | 调整MOPSO参数 | | 变量范围限制 | 大量变量固定为0 | 统一变量范围[-15,15] | | 缺乏多样性 | 解集单一 | 添加多样性保护机制 | --- ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值