How to set up the Matrix variables to use Options = optimoptio​ns('lsqcur​vefit','al​gorithm','​levenberg-​marquardt'​)

I have two sets of M1 and M2 vectors (1x20) of experimental values that correspond to two sets of K1 and K2 inputs (1x20) respectively. Theoretlcal values of M1 and M2 (call them M1T and M2T) have a relationship with K1 and K2 such that M1-T is a function of K1 and K2, and M2-T is also a function of K1 and K2 with a series of a1 to a6 coefficients.
I am trying to find those a1 to a6 coefficients by minimizing the error function Total Error = (M1 - M1T)^2 + (M2-M2T)^2 by the use of
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt'), however, I don't know how to set up my variables into these names/function (i.e. don't know the approriate coding syntax).
As an example;
the inputs are: M1 = [ i1 i2 i3 ............ i20], M2 = [ i1 i2 i3 .............i20], K1 = [ i1 i2 i3 ............ i20], K2 = [ i1 i2 i3 .............i20],
the relationship between theroretical values of M1, M2 and the K1 and K2 are:
M1T(i) = a1*K1(i) + a2*K1(i)*K2(i) + a3*K2(i) + a4*(K1(i))^2
M2T(i) = a2*K2(i) + a2*K1(i) + a5*(K2(i))^2 + a6*K1(i)*K2(i)

 Accepted Answer

I am not certain how ‘M1T’ and ‘M2T’ enter into this, however witth the ‘K’ values as the independent variables, and the ‘M’ values as the dependent variables, this is how I would set this up. (I prefer column vectors and column-oriented matrices, so I transposed the original row vectors to column vectors here.)
Try this, with your actual data —
M1 = randn(1,20);
M2 = randn(1,20);
K1 = randn(1,20);
K2 = randn(1,20);
% M1T = randn(1,20);
% M2T = randn(1,20);
M = [M1; M2].';
K = [K1; K2].';
MT = [M1T; M2T].';
objfcn = @(a,K) [a(1).*K(:,1) + a(2).*K(:,1).*K(:,2) + a(3).*K(:,2) + a(4).*K(:,1).^2, a(2).*K(:,2) + a(2).*K(:,1) + a(5).*K(:,2).^2 + a(6).*K(:,1).*K(:,2)]
objfcn = function_handle with value:
@(a,K)[a(1).*K(:,1)+a(2).*K(:,1).*K(:,2)+a(3).*K(:,2)+a(4).*K(:,1).^2,a(2).*K(:,2)+a(2).*K(:,1)+a(5).*K(:,2).^2+a(6).*K(:,1).*K(:,2)]
A0 = rand(6,1);
[A,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, A0, K, M);
Local minimum found. Optimization completed because the size of the gradient is less than the value of the optimality tolerance.
Estimated_Parameters = A
Estimated_Parameters = 6x1
-0.0124 -0.2568 0.2718 -0.0384 0.1853 0.1014
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
I did not include the options call or options structure here, for simplicity. I usually lett lsqcurvefit pick the approopriate algorthm.
.

23 Comments

Thank you - this is a great help. One comment and follow-up question; I defnitely need to incorporate the M1T and M2T since I am trying to estimate them based on combination inputs of K1 and K2. So, the goal is to find those a1 through a6 coefficients that would then give the minimum error between the experimental values of M1, M2 and the predicted of M1T and M2T for the each i= 1 to 20 data points.
Also, I am required to use the options structure as part of the comparision method.
Thanks again - greatly appreciated.
As always, my pleasure!
I believe that I understand how the ‘M’ and ‘K’ matrices are related, however I do not understand how a matching ‘MT’ matrix fits into it. Please describe that.
My guess is that it mightt go somethng like this —
M1 = randn(1,20);
M2 = randn(1,20);
K1 = randn(1,20);
K2 = randn(1,20);
M1T = randn(1,20);
M2T = randn(1,20);
M = [M1; M2].';
K = [K1; K2].';
MT = [M1T; M2T].';
objfcn = @(a,K) [a(1).*K(:,1) + a(2).*K(:,1).*K(:,2) + a(3).*K(:,2) + a(4).*K(:,1).^2, a(2).*K(:,2) + a(2).*K(:,1) + a(5).*K(:,2).^2 + a(6).*K(:,1).*K(:,2)];
A0 = rand(6,1);
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, A0, K, M, [], [], options);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
Estimated_Parameters = A
Estimated_Parameters = 6x1
0.1110 0.0106 0.5301 0.1358 -0.1990 -0.0467
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Mest = objfcn(A,K) % Fitted Values of 'M' From Regression
Mest = 20x2
0.5153 -0.1702 1.2665 -0.1943 0.0072 -0.0241 0.2855 0.0162 -0.6897 -0.4732 0.8010 -0.0193 0.3003 -0.0789 -0.1747 -0.0731 -0.5193 -0.2608 0.3886 0.0200
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Merr = MT - Mest % Matrix Of Differences
Merr = 20x2
-0.9136 0.9008 -2.4218 1.3586 0.1662 0.3310 0.0995 0.0920 2.2879 0.6085 0.5736 -0.8223 0.0818 -1.6282 2.0840 0.2712 0.8627 -0.2415 -0.5600 0.9696
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
MerrRMS = sqrt(mean(Merr.^2)) % Root-Mean_Squared Error
MerrRMS = 1x2
1.3816 0.8316
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
[Ks, idx] = sort(K);
figure
col = 1;
plot(K(idx(:,col),col), M(idx(:,col),col), '.')
hold on
plot(K(idx(:,col),col), Mest(idx(:,col),col), '-r')
hold off
grid
xlabel("K(:,"+col+")")
ylabel("M(:,"+col+")")
figure
col = 2;
plot(K(idx(:,col),col), M(idx(:,col),col), '.')
hold on
plot(K(idx(:,col),col), Mest(idx(:,col),col), '-r')
hold off
grid
xlabel("K(:,"+col+")")
ylabel("M(:,"+col+")")
Micro$oft once again randomly crashed my computer, apparently because it is fun for them (since there is no obvious reason for it) while I was typing this. My apologies for the resulting delay.
EDIT — (28 Jui 2024 at 17:19)
Since the options structure is required, it is now added. Code otherwise unchanged.
.
Thank you very much! - Meanwhile, I am exploring a slightly different modeling with the following M1T and M2T relationships to the independent variable K1 and K2.This time I have 7 coefficients (A through G).
M1T = 2*A*K1 + B*K2 + 3*D*(K1)^2 + 2*E*K1*K2 + F*(K2)^2;
M2T = B*K1 + 2*C*K2 + E*(K1)^2 + 2*F*K1*K2 + 3*G*(K2)^2
Like the last set, I have the K1, K2 independent values and their corresponding M1 and M2 dependent measurements.
My goal is again to determine the fit function for the K1 and K2 ( x-axis) based on the minimizing the error (similar to above) between (M1 and M1T) & (M2 and M2T) pairs using the same options function in order to derive the 7 coefficients. I think I should be able to use the same stucture you generated? Also, this time, I was thinking that I could even assign the unity matrix of 1s to the coefficients as their starting points rather than random integeters. Thanks again.
As always, my pleasure!
That is relatively straightforward. I did not know how you wanted ot integrate the ‘M’ and ‘MT’ arrays into your code.
My code changes slightly to —
M1 = randn(1,20);
M2 = randn(1,20);
K1 = randn(1,20);
K2 = randn(1,20);
M1T = randn(1,20);
M2T = randn(1,20);
M = [M1; M2].';
K = [K1; K2].';
MT = [M1T; M2T].';
objfcn = @(a,K) [2*a(1).*K(:,1) + a(2).*K(:,2).*K(:,2) + 3*a(4).*K(:,1).^2 + a(5).*K(:,1).*K(:,2), a(2).*K(:,1) + 2*a(3).*K(:,2) + a(5).*K(:,2).^2 + a(6).*K(:,1).*K(:,2) + 3.*a(7).*K(:,1).^2];
A0 = rand(7,1);
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm1,Rsd1,ExFlg1,OptmInfo1,Lmda1,Jmat1] = lsqcurvefit(objfcn, A0, K, M, [], [], options);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1, 'RowNames',ParmNames)
M_Parameters = 7x1 table
A1 __________ A 0.23359 B 0.17204 C -0.0034356 D 0.072715 E 0.023078 F -0.22083 G -0.071126
M_est = objfcn(A1,K) % Fitted Values of 'M' From Regression
M_est = 20x2
-0.1065 -1.1130 -0.0042 -0.0178 -0.0682 -1.0381 -0.2495 -0.3619 -0.0041 -0.2390 1.0891 0.2467 -0.1451 -0.7540 -0.1674 -0.1271 0.6402 -0.0834 0.1359 0.0547
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
[A2,Rsdnrm2,Rsd2,ExFlg2,OptmInfo2,Lmda2,Jmat2] = lsqcurvefit(objfcn, A0, K, MT, [], [], options);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
MT_Parameters = table(A2, 'RowNames',ParmNames)
MT_Parameters = 7x1 table
A2 __________ A -0.052173 B -0.0016726 C 0.1332 D -0.10325 E 0.036607 F 1.1643 G 0.063416
MT_est = objfcn(A2,K) % Fitted Values of 'M' From Regression
MT_est = 20x2
-0.8528 0.9717 0.0079 -0.0642 -1.0278 0.1142 -0.2042 0.1122 -0.0144 0.4419 -0.0350 0.1037 -0.7566 -0.1839 -0.0164 0.0512 -0.3521 0.5579 -0.0312 -0.2379
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
[Ks, idx] = sort(K);
figure
col = 1;
plot(K(idx(:,col),col), M(idx(:,col),col), '.')
hold on
plot(K(idx(:,col),col), M_est(idx(:,col),col), '-r')
hold off
grid
xlabel("K(:,"+col+")")
ylabel("M(:,"+col+")")
figure
col = 2;
plot(K(idx(:,col),col), M(idx(:,col),col), '.')
hold on
plot(K(idx(:,col),col), M_est(idx(:,col),col), '-r')
hold off
grid
xlabel("K(:,"+col+")")
ylabel("M(:,"+col+")")
figure
col = 1;
plot(K(idx(:,col),col), MT(idx(:,col),col), '.')
hold on
plot(K(idx(:,col),col), MT_est(idx(:,col),col), '-r')
hold off
grid
xlabel("K(:,"+col+")")
ylabel("MT(:,"+col+")")
figure
col = 2;
plot(K(idx(:,col),col), MT(idx(:,col),col), '.')
hold on
plot(K(idx(:,col),col), MT_est(idx(:,col),col), '-r')
hold off
grid
xlabel("K(:,"+col+")")
ylabel("MT(:,"+col+")")
This uses the new version of ‘objfcn’ however I suggest that you check it. Now, a(1)=A, ... a(7)=G.
Use the correct values for the relevant vectors, and this should do what you want. (The plots are optional. I included them because I like to see how the regressions look.)
.
Hi again, I hope this question finds you and that you will be able to provide your feedback.
After running my data, things did not make sense. I realized that there were some error in my original variable names and set up. I modified the variables such that hopefully MT now it should make sense to you as well. Do you think the below code and syntax make sense?
%given
M1 = [5 11 18 25 32 39 46 52 60];
M2 = [9 10 11 12 13 15 16 18 21];
K1 = [0 0.2 0.36 0.44 0.49 0.51 0.52 0.54 0.55];
K2 = [0.75 0.77 0.8 0.84 0.88 0.94 0.98 1.0 1.02];
%Theoritical Calculation of M1 and M2 in terms of the coefficients and K1 and K2
%M1_Theory = 2*Cff(1)*K1 + Cff(2)*K2 + 3*Cff(4)*K1^2 + 2*Cff(5)*K1*K2 + Cff(6)*K2^2;
%M2_Theory = Cff(2)*K1 + 2*Cff(3)*K2 + Cff(5)*K1^2 + 2*Cff(6)*K1*K2 + 3*Cff(7)*K2^2;
K = [K1; K2].';
M = [M1; M2].';
M1_Theory = 2*Cff(1).*K(:,1) + Cff(2).*K(:,2) + 3*Cff(4).*K(:,1) + 2*Cff(5).*K(:,1).*K(:,2) + Cff(6).*K(:,2).^2;
Unrecognized function or variable 'Cff'.
M2_Theory = Cff(2).*K(:,1) + 2*Cff(3).*K(:,2) + Cff(5).*K(:,1)^2 + 2*Cff(6).*K(:,1).*K(:,2) + 3*Cff(7).*K(:,2).^2;
M_Theory = [M1_Theory; M2_THeory].';
objfcn = @(Cff,M_Theory) [(M1-M1_Theory)^2 -(M2-M2_Theory)^2]
Cff = ones (7,1);
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff, M, M_Theory, [], [], options);
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1,'RowNames',ParmNames)
M_Theory = objfcn(A1,M_Theory)
The best way to see if it makes sense is to run it.
I did my best to get this to run, and that required several significant changes. The problem is that ‘objfcn’ need to return a (9x2) matrix. Before my changes, your code would not run at all. After my changes, ‘objfcn’ returns a (9x18) matrix. I am not certain what you want to do, so I will leave tthis for the time being and check back when ‘objfcn’ works correctly, or at least that I understand what you want to do with it. I creeated a ‘Q’ variable to see what ‘objfcn’ returns. You can use it for that purpose, to get ‘objfcn’ to work correctly.
M1 = [5 11 18 25 32 39 46 52 60];
M2 = [9 10 11 12 13 15 16 18 21];
K1 = [0 0.2 0.36 0.44 0.49 0.51 0.52 0.54 0.55];
K2 = [0.75 0.77 0.8 0.84 0.88 0.94 0.98 1.0 1.02];
%Theoritical Calculation of M1 and M2 in terms of the coefficients and K1 and K2
%M1_Theory = 2*Cff(1)*K1 + Cff(2)*K2 + 3*Cff(4)*K1^2 + 2*Cff(5)*K1*K2 + Cff(6)*K2^2;
%M2_Theory = Cff(2)*K1 + 2*Cff(3)*K2 + Cff(5)*K1^2 + 2*Cff(6)*K1*K2 + 3*Cff(7)*K2^2;
K = [K1; K2].'
K = 9x2
0 0.7500 0.2000 0.7700 0.3600 0.8000 0.4400 0.8400 0.4900 0.8800 0.5100 0.9400 0.5200 0.9800 0.5400 1.0000 0.5500 1.0200
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
M = [M1; M2].'
M = 9x2
5 9 11 10 18 11 25 12 32 13 39 15 46 16 52 18 60 21
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
M1_Theory = @(Cff,K) 2*Cff(1).*K(:,1) + Cff(2).*K(:,2) + 3*Cff(4).*K(:,1) + 2*Cff(5).*K(:,1).*K(:,2) + Cff(6).*K(:,2).^2;
M2_Theory = @(Cff,K) Cff(2).*K(:,1) + 2*Cff(3).*K(:,2) + Cff(5).*K(:,1).^2 + 2*Cff(6).*K(:,1).*K(:,2) + 3*Cff(7).*K(:,2).^2;
M_Theory = @(Cff,K) [M1_Theory(Cff,K); M2_THeory(Cff,K)].';
objfcn = @(Cff,K) [(M1-M1_Theory(Cff,K)).^2 -(M2-M2_Theory(Cff,K)).^2];
Cff0 = ones(7,1);
Q = objfcn(Cff0,K) % Check: 'objfcn'
Q = 9x18
1.0e+03 * 0.0136 0.0938 0.2785 0.5611 0.9417 1.4203 1.9970 2.5692 3.4442 -0.0338 -0.0464 -0.0610 -0.0777 -0.0963 -0.1395 -0.1642 -0.2194 -0.3173 0.0054 0.0694 0.2350 0.4986 0.8602 1.3198 1.8774 2.4334 3.2866 -0.0264 -0.0376 -0.0509 -0.0662 -0.0834 -0.1240 -0.1472 -0.1998 -0.2935 0.0014 0.0516 0.2012 0.4488 0.7943 1.2379 1.7795 2.3217 3.1566 -0.0195 -0.0293 -0.0411 -0.0550 -0.0708 -0.1085 -0.1303 -0.1799 -0.2694 0.0003 0.0424 0.1827 0.4209 0.7571 1.1913 1.7235 2.2577 3.0819 -0.0147 -0.0233 -0.0340 -0.0467 -0.0613 -0.0966 -0.1173 -0.1646 -0.2506 0.0000 0.0364 0.1699 0.4013 0.7308 1.1583 1.6837 2.2121 3.0287 -0.0111 -0.0187 -0.0283 -0.0400 -0.0536 -0.0869 -0.1066 -0.1519 -0.2348 0.0001 0.0321 0.1605 0.3868 0.7112 1.1335 1.6539 2.1779 2.9885 -0.0075 -0.0140 -0.0225 -0.0330 -0.0454 -0.0764 -0.0949 -0.1378 -0.2173 0.0003 0.0296 0.1548 0.3779 0.6991 1.1183 1.6354 2.1567 2.9638 -0.0055 -0.0112 -0.0189 -0.0286 -0.0403 -0.0697 -0.0874 -0.1288 -0.2059 0.0006 0.0272 0.1493 0.3694 0.6875 1.1036 1.6176 2.1363 2.9398 -0.0044 -0.0095 -0.0167 -0.0259 -0.0371 -0.0654 -0.0826 -0.1230 -0.1985 0.0009 0.0257 0.1456 0.3636 0.6795 1.0935 1.6054 2.1222 2.9233 -0.0035 -0.0082 -0.0149 -0.0237 -0.0344 -0.0618 -0.0786 -0.1180 -0.1922
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
Error using lsqcurvefit (line 312)
Function value and YDATA sizes are not equal.
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1,'RowNames',ParmNames)
M_Theory = objfcn(A1,M_Theory)
.
Thank you SO MUCH for your time and efforts. I really appreciated it.
I am not quite sure how the below code works so I just tried to mimick it from your orginal one.
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
So, as you indicated when I ran it, I got the lsqcurvefit error.
I do know that somehow the solution involves the line:
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt') but not being familiar with the lsqcurvefit or the way it is called with the options, makes it difficult to work.
I admit that the experiment is somewhat straight forward but the use of the variables and the relationships are a bit cumbersome. Imagine on the x-axis we have K1 and on the y-axis we have M1 on one graph. ( the relationship is nonlinear with a total 9 pair data points). Likewise on the second graph, K2 and M2 on the x and y axes respectively. So, in other words, K1 and K2 are my inputs ( independent variables) and M1 and M2 are my outputs. (dependent variables). Now, since the M1 and M2 are experimental measurements, there is also the theoritical calculations of M1 and M2 which are derived from K1 and K2 and bunch of coefficents (A through G). So, let's say we knew those coefficients, then I would be able to plot on the M1_Theoritical on the first graph, and M2_Theoritical on the second graph. Now, having the M1 and M1_Theoritical values, I can also take their least squared sums for each of the 9 data points per graph. If I were to add these summed squares from graph1 and graph2, then i would get the total error. In my case, I don't know the values of the coefficients and I am trying to construct the code such that this error should be minimum.
I am going to think more about your comments and the modified program to see if I can somehow make progress. Thanks again. It is so nice to bounce back some ideas and get some guidance and help from an expert.
As always, my pleasure!
Note that ‘objfcn’ does not need to consider ‘[M1; M2].'’ so they do not belong in it. The lsqcurvefit function will calculate the values of ‘M1_Theory’ and ‘M2_Theory’ using the ‘Cff’ coefficients (that it estimates) and the ‘K’ matrix, so ‘M1’ and ‘M2’ should not be present in it, since they the dependent variables. The lsqcurvefit function calculates ‘objfcn’ using ‘K’ and estimates the values of ‘Cff’ to minimise the least-squares error between it and the ‘M’ matrix.
Try this —
M1 = [5 11 18 25 32 39 46 52 60];
M2 = [9 10 11 12 13 15 16 18 21];
K1 = [0 0.2 0.36 0.44 0.49 0.51 0.52 0.54 0.55];
K2 = [0.75 0.77 0.8 0.84 0.88 0.94 0.98 1.0 1.02];
K = [K1; K2].';
M = [M1; M2].';
M1_Theory = @(Cff,K) 2*Cff(1).*K(:,1) + Cff(2).*K(:,2) + 3*Cff(4).*K(:,1) + 2*Cff(5).*K(:,1).*K(:,2) + Cff(6).*K(:,2).^2;
M2_Theory = @(Cff,K) Cff(2).*K(:,1) + 2*Cff(3).*K(:,2) + Cff(5).*K(:,1).^2 + 2*Cff(6).*K(:,1).*K(:,2) + 3*Cff(7).*K(:,2).^2;
M_Theory = @(Cff,K) [M1_Theory(Cff,K); M2_THeory(Cff,K)].';
objfcn = @(Cff,K) [M1_Theory(Cff,K).^2 M2_Theory(Cff,K).^2];
Cff0 = rand(7,1);
Q = objfcn(Cff0,K)
Q = 9x2
0.4660 2.8271 2.2158 4.3295 4.7095 6.2091 6.6163 7.8526 8.2071 9.3678 9.5723 11.0816 10.4853 12.2748 11.3830 13.1920 12.0380 13.9546
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
% options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
% [A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1,'RowNames',ParmNames)
M_Parameters = 7x1 table
A1 _______ A -3.6046 B 13.933 C -1.2449 D -6.3572 E 20.366 F -14.481 G 2.9709
M_Theory = objfcn(A1,K)
M_Theory = 9x2
5.3094 9.8974 9.9817 6.2915 17.2109 9.1603 24.7736 12.7198 32.8724 15.5213 41.2911 16.4318 46.7626 16.9165 52.6524 18.0294 56.8880 18.5718
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Err = M - M_Theory
Err = 9x2
-0.3094 -0.8974 1.0183 3.7085 0.7891 1.8397 0.2264 -0.7198 -0.8724 -2.5213 -2.2911 -1.4318 -0.7626 -0.9165 -0.6524 -0.0294 3.1120 2.4282
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
RMS_Err = sqrt(mean(Err.^2))
RMS_Err = 1x2
1.4341 1.9323
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
figure
col = 1;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
figure
col = 2;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
Now I understand how this is supposed to work!
The ‘M1_Theory’ regression fits quite well, however ‘M2_Theory’ does not, so you need to check it and make any necessary changes only to it (the code will adapt automatically, so no other changes are necessary), then run this code again.
.
EDIT — (01 Aug 2024 at 13:05)
Removed unary negative in ‘objfcn’ as noted in @Selim’s Comment, changing it from:
objfcn = @(Cff,K) [M1_Theory(Cff,K).^2 -M2_Theory(Cff,K).^2];
to:
objfcn = @(Cff,K) [M1_Theory(Cff,K).^2 M2_Theory(Cff,K).^2];
and then re-ran the code to get the current result.
Code otherwise unchanged.
.
This works! I noticed in the objfcn the minus sign needed to plus between M1_Theory and M2_Theory (since we are adding up the errors). I ran it afterwords, got the second graph as;
I think this is it - you did it :-) Thank you again,
On a side note, when I ran the code, it gives the yellow warnings of " Value assigned to variable might be unsued.Considr replacing the variable with ~ instead.". But obviously, this is just FYI.
As always, my pleasure!
I am plesed that all this is now sorted!
I got no warnings, even after updating the code to remove the unary minus sign (see EDIT in my previoous Comment) and re-running it. I suspect that you got the warning because you are using the code inside a function.
Sorry to bother you but for some strange reason, now my code is not working. Anything that stands out for you? ( I am getting the error below)
My code is:
M1 = [5 11 18 25 32 39 46 52 60];
M2 = [9 10 11 12 13 15 16 18 21];
K1 = [0 0.2 0.36 0.44 0.49 0.51 0.52 0.54 0.55];
K2 = [0.75 0.77 0.8 0.84 0.88 0.94 0.98 1.0 1.02];
K = [K1; K2].';
M = [M1; M2].';
M1_Theory = @(Cff,K) 2*Cff(1).*K(:,1) + Cff(2).*K(:,2) + 3*Cff(4).*K(:,1) + 2*Cff(5).*K(:,1).*K(:,2) + Cff(6).*K(:,2).^2;
M2_Theory = @(Cff,K) Cff(2).*K(:,1) + 2*Cff(3).*K(:,2) + Cff(5).*K(:,1).^2 + 2*Cff(6).*K(:,1).*K(:,2) + 3*Cff(7).*K(:,2).^2;
M_Theory = @(Cff,K) [M1_Theory(Cff,K); M2_Theory(Cff,K)].';
objfcn = @(Cff,K) [(M1-M1_Theory(Cff,K)).^2 +(M2-M2_Theory(Cff,K)).^2];
Cff0 = rand(7,1);
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
Error using lsqcurvefit (line 312)
Function value and YDATA sizes are not equal.
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1,'RowNames',ParmNames)
M_Theory = objfcn(A1,K)
Err = M - M_Theory
RMS_Err = sqrt(mean(Err.^2))
figure
col = 1;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
figure
col = 2;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
Use
M_Theory = @(Cff,K) [M1_Theory(Cff,K), M2_Theory(Cff,K)];
objfcn = @(Cff,K) M_Theory(Cff,K);
instead of
M_Theory = @(Cff,K) [M1_Theory(Cff,K); M2_Theory(Cff,K)].';
objfcn = @(Cff,K) [(M1-M1_Theory(Cff,K)).^2 +(M2-M2_Theory(Cff,K)).^2];
M1 = [5 11 18 25 32 39 46 52 60];
M2 = [9 10 11 12 13 15 16 18 21];
K1 = [0 0.2 0.36 0.44 0.49 0.51 0.52 0.54 0.55];
K2 = [0.75 0.77 0.8 0.84 0.88 0.94 0.98 1.0 1.02];
K = [K1; K2].';
M = [M1; M2].';
M1_Theory = @(Cff,K) 2*Cff(1).*K(:,1) + Cff(2).*K(:,2) + 3*Cff(4).*K(:,1) + 2*Cff(5).*K(:,1).*K(:,2) + Cff(6).*K(:,2).^2;
M2_Theory = @(Cff,K) Cff(2).*K(:,1) + 2*Cff(3).*K(:,2) + Cff(5).*K(:,1).^2 + 2*Cff(6).*K(:,1).*K(:,2) + 3*Cff(7).*K(:,2).^2;
M_Theory = @(Cff,K) [M1_Theory(Cff,K); M2_Theory(Cff,K)];
objfcn = @(Cff,K) M_Theory(Cff,K);
Cff0 = rand(7,1);
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
Error using lsqcurvefit (line 312)
Function value and YDATA sizes are not equal.
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1,'RowNames',ParmNames)
M_Theory = objfcn(A1,K)
Err = M - M_Theory
RMS_Err = sqrt(mean(Err.^2))
figure
col = 1;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
figure
col = 2;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
Anything that stands out for you?
Yes! When in doubt, see what ‘objfcn’ returns with the default parameter vector and an appropriate independent variable. Here, ‘objfcn’ is returning a (9x18) matrix instead of the (9x2) matriux that it should. This is because ‘M1’ and ‘M2’ are(1x9) row vectors, and the subtracting them uses ‘iimplicit expansion’ to do that, rather than throwing an error. (Automatic implicit expansion was introduced in R2014b and has caused these sort of problems ever since.) That is the reason the the ‘M’ matrix transposes ‘M1’ and ‘M2’ to column vectors before concatenating them into a matrix.
The solution is to revert to the original code for this that I wrote, because it does not consider ‘M1’ and ‘M2’ at all in ‘objfcn’ since lsqcurvefit does that comparison internally to fit ‘objfcn’ to ‘M’, so doing it in ‘objfcn’ will produce inaccurate results for the parameter vector ‘Cff’.
M1 = [5 11 18 25 32 39 46 52 60];
M2 = [9 10 11 12 13 15 16 18 21];
K1 = [0 0.2 0.36 0.44 0.49 0.51 0.52 0.54 0.55];
K2 = [0.75 0.77 0.8 0.84 0.88 0.94 0.98 1.0 1.02];
K = [K1; K2].';
M = [M1; M2].';
M1_Theory = @(Cff,K) 2*Cff(1).*K(:,1) + Cff(2).*K(:,2) + 3*Cff(4).*K(:,1) + 2*Cff(5).*K(:,1).*K(:,2) + Cff(6).*K(:,2).^2;
M2_Theory = @(Cff,K) Cff(2).*K(:,1) + 2*Cff(3).*K(:,2) + Cff(5).*K(:,1).^2 + 2*Cff(6).*K(:,1).*K(:,2) + 3*Cff(7).*K(:,2).^2;
M_Theory = @(Cff,K) [M1_Theory(Cff,K); M2_Theory(Cff,K)].';
% objfcn = @(Cff,K) [(M1-M1_Theory(Cff,K)).^2 +(M2-M2_Theory(Cff,K)).^2];% % Inaccurate
objfcn = @(Cff,K) [(M1_Theory(Cff,K)).^2 +(M2_Theory(Cff,K)).^2]; % Corrected
Cff0 = rand(7,1);
Check_objfcn = objfcn(Cff0,K)
Check_objfcn = 9x2
1.0267 1.7372 2.0513 3.0710 3.2265 4.7208 4.1175 6.2446 4.8720 7.7262 5.6255 9.6510 6.1382 11.0757 6.5582 12.0743 6.8908 12.9754
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
M
M = 9x2
5 9 11 10 18 11 25 12 32 13 39 15 46 16 52 18 60 21
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% return
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1,'RowNames',ParmNames)
M_Parameters = 7x1 table
A1 _______ A -4.3908 B 13.933 C -1.2448 D -5.8328 E 20.366 F -14.481 G 2.9708
M_Theory = objfcn(A1,K)
M_Theory = 9x2
5.3094 9.8975 9.9817 6.2917 17.2109 9.1605 24.7737 12.7199 32.8725 15.5214 41.2911 16.4318 46.7626 16.9165 52.6524 18.0293 56.8879 18.5717
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Err = M - M_Theory
Err = 9x2
-0.3094 -0.8975 1.0183 3.7083 0.7891 1.8395 0.2263 -0.7199 -0.8725 -2.5214 -2.2911 -1.4318 -0.7626 -0.9165 -0.6524 -0.0293 3.1121 2.4283
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
RMS_Err = sqrt(mean(Err.^2))
RMS_Err = 1x2
1.4341 1.9323
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
figure
col = 1;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
figure
col = 2;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
You can certainly change ‘objfcn’ to a new version with different expressions (that might be a better match to ‘M2’), however it is not appropriate to include ‘M1’ and ‘M2’ in it at all.
.
This makes sense. I got myself confused I suppose. When I looked at objfcn
% objfcn = @(Cff,K) [(M1-M1_Theory(Cff,K)).^2 +(M2-M2_Theory(Cff,K)).^2];% % Inaccurate
objfcn = @(Cff,K) [(M1_Theory(Cff,K)).^2 +(M2_Theory(Cff,K)).^2]; % Corrected
I was thinking that it needed to have the squared difference between the experimental and theoritical as the objective, and just seeing the squares of the M1_Theory and M2_Theory made me second guess.
Thanks again. You are the best!
If you square M1_theory and M2_theory in
objfcn = @(Cff,K) [(M1_Theory(Cff,K)).^2 +(M2_Theory(Cff,K)).^2];
don't you also have to square M1 and M2 ?
In the case above, I think lsqcurvefit will try to minimize
sum_i ((M1_Theory(i)^2 - M1(i))^2 + (M2_theory(i)^2 - M2(i))^2)
I think
M_Theory = @(Cff,K) [M1_Theory(Cff,K), M2_Theory(Cff,K)];
objfcn = @(Cff,K) M_Theory(Cff,K);
is the correct choice.
I trust your knowledge and experience. Thanks again. I have a feeling that this will not my last question :-)
As always, my pleasure!
Thank you!
I did not initially pick up on the squaring, since I was concentrating on a different problem.
i believe that they shoud not be squared in any event, at least not in ‘objfcn’. Let lsqcurvefit take care of those details.
Squaring the difference would be appropriate for some optimisation functions such as fminsearch or fmincon in which it would be:
objfcn = @(Cff) [(M1.'-M1_Theory(Cff,K)).^2 (M2.'-M2_Theory(Cff,K)).^2];
inheriting ‘K’ from the workspace, and that would probably work (note the simple transpose operations denoted by.'). I did not test it with any of those functions.
Not squaring produces —
M1 = [5 11 18 25 32 39 46 52 60];
M2 = [9 10 11 12 13 15 16 18 21];
K1 = [0 0.2 0.36 0.44 0.49 0.51 0.52 0.54 0.55];
K2 = [0.75 0.77 0.8 0.84 0.88 0.94 0.98 1.0 1.02];
K = [K1; K2].';
M = [M1; M2].';
M1_Theory = @(Cff,K) 2*Cff(1).*K(:,1) + Cff(2).*K(:,2) + 3*Cff(4).*K(:,1) + 2*Cff(5).*K(:,1).*K(:,2) + Cff(6).*K(:,2).^2;
M2_Theory = @(Cff,K) Cff(2).*K(:,1) + 2*Cff(3).*K(:,2) + Cff(5).*K(:,1).^2 + 2*Cff(6).*K(:,1).*K(:,2) + 3*Cff(7).*K(:,2).^2;
M_Theory = @(Cff,K) [M1_Theory(Cff,K); M2_Theory(Cff,K)].';
% objfcn = @(Cff,K) [(M1-M1_Theory(Cff,K)).^2 +(M2-M2_Theory(Cff,K)).^2];% % Inaccurate
objfcn = @(Cff,K) [(M1_Theory(Cff,K)) (M2_Theory(Cff,K))]; % Corrected
Cff0 = rand(7,1);
Check_objfcn = objfcn(Cff0,K)
Check_objfcn = 9x2
0.2308 1.2562 0.6142 1.4026 0.9409 1.5906 1.1338 1.7550 1.2749 1.8984 1.3813 2.0619 1.4472 2.1699 1.5134 2.2419 1.5587 2.3031
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
M
M = 9x2
5 9 11 10 18 11 25 12 32 13 39 15 46 16 52 18 60 21
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% return
options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
[A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
% options = optimoptions('lsqcurvefit','Algorithm','levenberg-marquardt');
% [A1,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqcurvefit(objfcn, Cff0, K, M, [], [], options);
ParmNames = {'A','B','C','D','E','F','G'};
M_Parameters = table(A1,'RowNames',ParmNames)
M_Parameters = 7x1 table
A1 _______ A -45.62 B 91.776 C -12.856 D -68.993 E 217.68 F -114.39 G 17.929
M_Theory = objfcn(A1,K)
M_Theory = 9x2
4.4866 10.9705 10.2458 3.9211 18.2340 9.2142 26.0685 14.3188 33.7764 17.6086 41.8111 17.1010 46.8625 16.4538 51.4385 17.5648 54.8129 17.7095
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Err = M - M_Theory
Err = 9x2
0.5134 -1.9705 0.7542 6.0789 -0.2340 1.7858 -1.0685 -2.3188 -1.7764 -4.6086 -2.8111 -2.1010 -0.8625 -0.4538 0.5615 0.4352 5.1871 3.2905
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
RMS_Err = sqrt(mean(Err.^2))
RMS_Err = 1x2
2.1357 3.0962
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
figure
col = 1;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
figure
col = 2;
plot(K(:,col), M(:,col), '.', 'DisplayName','Data')
hold on
plot(K(:,col), M_Theory(:,col), '-r', 'DisplayName','Regression')
hold off
grid
xlabel('K')
ylabel('M')
title("Column "+col)
legend('Location','best')
So not squaring produces different parameter estimates, however the same essential fit.
.
Thanks again. I have a feeling that this will not my last question :-)
As always, my plesure!
I will do my best to provide an appropriate respoinse!
Squaring the difference would be appropriate for some optimisation functions such as fminsearch or fmincon in which it would be:
objfcn = @(Cff) [(M1.'-M1_Theory(Cff,K)).^2 (M2.'-M2_Theory(Cff,K)).^2];
inheriting ‘K’ from the workspace, and that would probably work (note the simple transpose operations denoted by.'). I did not test it with any of those functions.
For "fminsearch" or "fmincon", you even had to sum over the squared differences.
I usually use the norm function for that, although I did not do that experiment in this instance.

Sign in to comment.

More Answers (0)

Products

Release

R2023a

Asked:

on 28 Jul 2024

Edited:

on 5 Aug 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!