Евгений МашеровsvvВот, решил использовать метод золотого сечения. У нас уже есть график зависимости
от
:
Тут, в принципе, видно, что при более-менее нормальном начальном приближении минимум должен искаться хорошо – главное начальным отрезком попасть в "большую впадину". Начальное приближение возьмём, считая пересечения через ноль, оно у нас достаточно близко к искомому
: 0,0942 (при искомом 0,0934). Начальный отрезок я беру как начальное приближение плюс-минус 2 процента от него, в нашем случае это от 0,0923 до 0,0961. Если отметить эти точки на графике, то видно, что в " большую впадину" мы попали, причём с запасом (ну и искомый минимум лежит внутри нашего отрезка).
Вот код, который должен искать набор коэффициентов, обеспечивающих минимальную невязку методом золотого сечения:
y=[61.8345252303583; 64.2186685630058; 68.5780907223303; 73.8351943469310; ...
78.1178746381488; 79.4447599032848; 77.1209584326325; 72.3384843492439; ...
67.1780874592201; 63.3083342155163; 61.5848686426315; 62.2811015529467; ...
65.2944676251564; 70.0570903999628; 75.2539157928855; 78.8647097424086; ...
79.1332309482167; 75.9175990711235; 70.8145100998371; 65.8890541188997; ...
62.5767534515232; 61.5348068381206; 62.9195242022718; 66.5179434492526; ...
71.5768723085928; 76.5420755341518; 79.3273502810222; 78.5249447120497; ...
74.5575769012328; 69.3099594259272; 64.7368823911916; 62.0334551154671; ...
61.6848623894562; 63.7418912006921; 67.8660696583989; 73.0933449460809; ...
77.6481344114599; 79.4840538567364; 77.6481344114599; 73.0933449460811; ...
67.8660696583989; 63.7418912006923; 61.6848623894562; 62.0334551154669; ...
64.7368823911916; 69.3099594259272; 74.5575769012327; 78.5249447120497; ...
79.3273502810222; 76.5420755341517; 71.5768723085929; 66.5179434492527; ...
62.9195242022719; 61.5348068381207; 62.5767534515231; 65.8890541188995; ...
70.8145100998372; 75.9175990711235; 79.1332309482166; 78.8647097424087; ...
75.2539157928858; 70.0570903999627; 65.2944676251561; 62.2811015529469; ...
61.5848686426318; 63.3083342155164; 67.1780874592199; 72.3384843492438; ...
77.1209584326324; 79.4447599032847; 78.1178746381488; 73.8351943469311; ...
68.5780907223305; 64.2186685630060 ];
n=size(y,1);
x=(1:n)';
init_approx = find_frequency(x, y);
init_approx_delta = init_approx * 0.02;
a_n = init_approx - init_approx_delta;
b_n = init_approx + init_approx_delta;
c_n = (b_n - a_n) * 0.312 + a_n;
d_n = (b_n - a_n) * 0.618 + a_n;
[answ_c, S_c] = LS(init_approx, x, y);
[answ_d, S_d] = LS(init_approx, x, y);
for counter = (1:10)
if S_c > S_d
a_n = c_n;
c_n = d_n;
d_n = (b_n - a_n) * 0.618 + a_n;
%disp(["Выбран d: " string(d_n) ". При a=" string(a_n) ", c=" string(c_n) ", b=" string(b_n)])
[answ_d, S_d] = LS(d_n, x, y);
else
b_n = d_n;
d_n = c_n;
c_n = (b_n - a_n) * 0.312 + a_n;
%disp(["Выбран c: " string(c_n) ". При a=" string(a_n) ", d=" string(d_n) ", b=" string(b_n)])
[answ_c, S_c] = LS(c_n, x, y);
end
end
[c, S] = LS(a_n + (b_n - a_n) / 2, x, y);
disp(c)
disp(a_n + (b_n - a_n) / 2)
disp(S)
function [c, S] = LS(b, x, y)
A=[ones(size(y,1),1), cos(2*pi*b*x), sin(2*pi*b*x)];
c=pinv(A)*y;
S=norm(y-A*c);
end
function frequency = find_frequency(x, y)
counter = 0;
first_i = 0;
last_i = 0;
zero = (min(y) + max(y)) / 2;
for i = 2:size(x, 1)
if y(i - 1) > zero && y(i) < zero || y(i - 1) < zero && y(i) > zero
counter = counter + 1;
if counter == 1
first_i = i;
else
last_i = i;
end
end
end
frequency = (counter - 1) / (last_i - first_i) / 2;
end
Данный код на выдаёт
при невязке
. Интересно не только то, что это не искомый коэффициент
, но и то, что невязка не та
. Если ткнуть в такую точку на приведённом выше графике, то невязка там равна 5,76103, отсюда и проблема. Видимо, я неправильно преобразовал функцию поиска коэффициентов. Вот так было:
y=[61.8345252303583; 64.2186685630058; 68.5780907223303; 73.8351943469310; ...
78.1178746381488; 79.4447599032848; 77.1209584326325; 72.3384843492439; ...
67.1780874592201; 63.3083342155163; 61.5848686426315; 62.2811015529467; ...
65.2944676251564; 70.0570903999628; 75.2539157928855; 78.8647097424086; ...
79.1332309482167; 75.9175990711235; 70.8145100998371; 65.8890541188997; ...
62.5767534515232; 61.5348068381206; 62.9195242022718; 66.5179434492526; ...
71.5768723085928; 76.5420755341518; 79.3273502810222; 78.5249447120497; ...
74.5575769012328; 69.3099594259272; 64.7368823911916; 62.0334551154671; ...
61.6848623894562; 63.7418912006921; 67.8660696583989; 73.0933449460809; ...
77.6481344114599; 79.4840538567364; 77.6481344114599; 73.0933449460811; ...
67.8660696583989; 63.7418912006923; 61.6848623894562; 62.0334551154669; ...
64.7368823911916; 69.3099594259272; 74.5575769012327; 78.5249447120497; ...
79.3273502810222; 76.5420755341517; 71.5768723085929; 66.5179434492527; ...
62.9195242022719; 61.5348068381207; 62.5767534515231; 65.8890541188995; ...
70.8145100998372; 75.9175990711235; 79.1332309482166; 78.8647097424087; ...
75.2539157928858; 70.0570903999627; 65.2944676251561; 62.2811015529469; ...
61.5848686426318; 63.3083342155164; 67.1780874592199; 72.3384843492438; ...
77.1209584326324; 79.4447599032847; 78.1178746381488; 73.8351943469311; ...
68.5780907223305; 64.2186685630060 ];
n=size(y,1);
x=(1:n)';
b=0.02:0.0001:0.16;
N=size(b,2);
cc=zeros(3,N);
S=zeros(N);
for j=1:N
A=[ones(n,1), cos(2*pi*b(j)*x), sin(2*pi*b(j)*x)];
c=pinv(A)*y;
S(j)=norm(y-A*c);
cc(:,j)=c;
end
[Smin,Ind]=min(S);
b_=b(Ind(1))
c_=cc(:,Ind(1))
Но нам ведь теперь не нужно считать всё для большого количества
, верно? Нужно посчитать коэффициенты и невязку в конкретной точке. Вот я и написал:
function [c, S] = LS(b, x, y)
A=[ones(size(y,1),1), cos(2*pi*b*x), sin(2*pi*b*x)];
c=pinv(A)*y;
S=norm(y-A*c);
end
Ответ такая функция выдаёт не совсем верный. Хотя я ничего не менял – x тот же, y тот же. Не понимаю
-- 11.05.2023, 00:53 --Ещё заметил – если в "изначальном" коде в 10 раз уменьшить шаг поиска
, то найденный коэффициент
не меняется, невязка не меняется, а остальные коэффициенты меняются