To provide a brief background, I am working on a project to control the velocity of a bi-stable solenoid and I am trying to create a state-space representation of the system. One of the variables in my state-space is F, the force on the armature of the solenoid. F is dependent on the specific geometric configuration of the solenoid and the BH-curves of the ferrite cores and permanent magnet. F can be described as a function of position of the armature, x, and the current in the solenoid, i, otherwise written as F = g(x,i).
The attached excel sheet is data collected from a Maxwell finite element model of the solenoid that gives the force (in N) on the solenoid with respect to position (in mm) and current (in A). From papers I've read online (1 and 2), it is common practice to fit this curve to a bicubic spline approximation. The bicubic spline approximation can be represented as shown below.
F(t) = g(i,x) = g_0(x) + g_1(x)*i + g_2(x)*i^2 + g_3(x)*i^3
Where g_i(x) = α_i,1 + α_i,2*x + α_i,3*x^2 + α_i,4*x^3 for i=1,2,3,4
From this equation, you get 16 coefficients to fit to your data. I tried fitting to the attached excel data but it wasn't able to fit the highly non-linear forces near 0mm and 4.895mm and ended up with a high MSE = 163.05.
My method for fitting the data was done in Matlab using the nlinfit() function. If you want to replicate my results, I got α coefficients as follows:
[α_11, α_12, α_13, α_14, α_21, α_22, α_23, α_24, α_31, α_32, α_33, α_34, α_41, α_42, α_43, α_44] = [59.6556, -104.012, 49.6096, -6.9047, -14.8646, 9.3209, -1.8018, -0.0318, -0.2990, 0.8670, -0.4706, 0.0661, 0.0971, -0.0944, 0.0197]
Here is a plot of the fitted curve versus the actual data (in red).
Force Curve Fit
I believe its the function I am fitting that is the issue rather than my method of fitting. But, I don't know what the best equation to use as I don't think increasing polynomial order will help (but maybe I am wrong).
If anyone has suggestions on either figuring out how to find a good equation to fit to, or has suggestions on a particular equation that you think is appropriate for this data, I would greatly appreciate it! The data is very symmetrical in both of the input variable, current and position, which I think could be useful in finding the appropriate equation to fit.
Thank you.
Edit: Forgot to attach the excel data. Run the code snippet to generate the table of data.
<table><tbody><tr><th> </th><th>-7</th><th>-6</th><th>-5</th><th>-4</th><th>-3</th><th>-2</th><th>-1</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>i (A)</th></tr><tr><td>4.895</td><td>30.002332</td><td>21.985427</td><td>6.810482</td><td>-15.670808</td><td>-45.233394</td><td>-77.215051</td><td>-105.258626</td><td>-125.69229</td><td>-137.533424</td><td>-144.608218</td><td>-149.37894</td><td>-153.029304</td><td>-155.689815</td><td>-157.477955</td><td>-158.626949</td><td> </td></tr><tr><td>4.845</td><td>30.232465</td><td>24.087844</td><td>14.620048</td><td>1.72655</td><td>-14.792426</td><td>-35.152992</td><td>-59.469883</td><td>-84.288</td><td>-102.159215</td><td>-114.172775</td><td>-123.557279</td><td>-130.950597</td><td>-136.22158</td><td>-139.785929</td><td>-142.188687</td><td> </td></tr><tr><td>4.795</td><td>30.421325</td><td>24.932531</td><td>17.444529</td><td>7.892998</td><td>-3.856977</td><td>-18.014886</td><td>-34.99118</td><td>-54.76071</td><td>-73.12193</td><td>-87.497601</td><td>-98.824193</td><td>-108.060712</td><td>-114.987903</td><td>-120.253359</td><td>-124.356373</td><td> </td></tr><tr><td>4.745</td><td>30.551303</td><td>25.391767</td><td>18.870906</td><td>10.957517</td><td>1.538053</td><td>-9.535194</td><td>-22.598697</td><td>-38.389555</td><td>-55.208053</td><td>-69.556258</td><td>-81.254268</td><td>-90.739807</td><td>-98.322417</td><td>-104.256711</td><td>-108.853733</td><td> </td></tr><tr><td>4.695</td><td>30.664703</td><td>25.675715</td><td>19.70439</td><td>12.733737</td><td>4.693012</td><td>-4.564309</td><td>-15.382383</td><td>-28.781825</td><td>-44.015781</td><td>-57.405663</td><td>-68.654996</td><td>-78.136226</td><td>-85.96381</td><td>-92.262205</td><td>-97.271558</td><td> </td></tr><tr><td>4.645</td><td>30.727753</td><td>25.865955</td><td>20.238259</td><td>13.853267</td><td>6.664413</td><td>-1.448761</td><td>-10.800537</td><td>-22.615818</td><td>-36.367379</td><td>-48.848877</td><td>-59.549314</td><td>-68.920612</td><td>-76.813046</td><td>-83.32022</td><td>-88.600393</td><td> </td></tr><tr><td>4.395</td><td>30.865921</td><td>26.241471</td><td>21.290271</td><td>16.08672</td><td>10.626372</td><td>4.839985</td><td>-1.602854</td><td>-9.43494</td><td>-18.83834</td><td>-28.636958</td><td>-37.691591</td><td>-45.92364</td><td>-53.263184</td><td>-59.60791</td><td>-64.797286</td><td> </td></tr><tr><td>4.145</td><td>31.095974</td><td>26.462957</td><td>21.68939</td><td>16.805136</td><td>11.820302</td><td>6.696608</td><td>1.18386</td><td>-5.121618</td><td>-12.593724</td><td>-20.872655</td><td>-28.902156</td><td>-36.190138</td><td>-42.81756</td><td>-48.711318</td><td>-53.733812</td><td> </td></tr><tr><td>3.895</td><td>31.46129</td><td>26.783809</td><td>22.050232</td><td>17.24325</td><td>12.414941</td><td>7.549917</td><td>2.463171</td><td>-3.126318</td><td>-9.525282</td><td>-16.772883</td><td>-24.024533</td><td>-30.735935</td><td>-36.907371</td><td>-42.495141</td><td>-47.386621</td><td> </td></tr><tr><td>3.645</td><td>31.84872</td><td>27.13964</td><td>22.399963</td><td>17.609472</td><td>12.824883</td><td>8.054302</td><td>3.167199</td><td>-2.022925</td><td>-7.798272</td><td>-14.333423</td><td>-20.98601</td><td>-27.322197</td><td>-33.20454</td><td>-38.422392</td><td>-43.441491</td><td> </td></tr><tr><td>3.395</td><td>32.321379</td><td>27.611153</td><td>22.830246</td><td>18.00384</td><td>13.186564</td><td>8.407782</td><td>3.614684</td><td>-1.377083</td><td>-6.778505</td><td>-12.763999</td><td>-18.950497</td><td>-24.996769</td><td>-30.700952</td><td>-36.002519</td><td>-40.845001</td><td> </td></tr><tr><td>3.145</td><td>32.912865</td><td>28.117376</td><td>23.297908</td><td>18.414747</td><td>13.541529</td><td>8.720016</td><td>3.953985</td><td>-0.893617</td><td>-6.030829</td><td>-11.646948</td><td>-17.480042</td><td>-23.272051</td><td>-28.818368</td><td>-34.05723</td><td>-38.898901</td><td> </td></tr><tr><td>2.895</td><td>33.461235</td><td>28.733026</td><td>23.846096</td><td>18.900341</td><td>13.945926</td><td>9.043626</td><td>4.247023</td><td>-0.554529</td><td>-5.54091</td><td>-10.874341</td><td>-16.437732</td><td>-22.017734</td><td>-27.450488</td><td>-32.671967</td><td>-37.55842</td><td> </td></tr><tr><td>2.645</td><td>34.20239</td><td>29.399207</td><td>24.450979</td><td>19.429789</td><td>14.378361</td><td>9.384043</td><td>4.50818</td><td>-0.228657</td><td>-5.110888</td><td>-10.256221</td><td>-15.598685</td><td>-20.988768</td><td>-26.283234</td><td>-31.452038</td><td>-36.351057</td><td> </td></tr><tr><td>2.395</td><td>34.914372</td><td>30.186026</td><td>25.182228</td><td>20.081931</td><td>14.90649</td><td>9.757508</td><td>4.793411</td><td>-0.022121</td><td>-4.818618</td><td>-9.801554</td><td>-14.977042</td><td>-20.209359</td><td>-25.40338</td><td>-30.537892</td><td>-35.491473</td><td> </td></tr><tr><td>2.145</td><td>35.805782</td><td>31.056782</td><td>26.042754</td><td>20.849744</td><td>15.526359</td><td>10.206612</td><td>5.079032</td><td>0.217373</td><td>-4.533031</td><td>-9.394064</td><td>-14.424973</td><td>-19.520352</td><td>-24.601559</td><td>-29.643549</td><td>-34.578382</td><td> </td></tr><tr><td>1.895</td><td>36.912236</td><td>32.230447</td><td>27.190092</td><td>21.88521</td><td>16.388134</td><td>10.852426</td><td>5.512241</td><td>0.53729</td><td>-4.252576</td><td>-9.060047</td><td>-13.988674</td><td>-18.990227</td><td>-23.997652</td><td>-28.971069</td><td>-33.911535</td><td> </td></tr><tr><td>1.645</td><td>38.220177</td><td>33.55963</td><td>28.522922</td><td>23.132328</td><td>17.438377</td><td>11.652987</td><td>6.043032</td><td>0.901</td><td>-3.941164</td><td>-8.721107</td><td>-13.565417</td><td>-18.470008</td><td>-23.400995</td><td>-28.283206</td><td>-33.172001</td><td> </td></tr><tr><td>1.395</td><td>40.089435</td><td>35.460059</td><td>30.362062</td><td>24.861205</td><td>18.933028</td><td>12.805265</td><td>6.809413</td><td>1.39481</td><td>-3.583199</td><td>-8.390298</td><td>-13.200262</td><td>-18.057954</td><td>-22.938035</td><td>-27.768679</td><td>-32.61952</td><td> </td></tr><tr><td>1.145</td><td>42.604155</td><td>38.034489</td><td>32.852205</td><td>27.179704</td><td>21.024509</td><td>14.456797</td><td>7.936568</td><td>2.129503</td><td>-3.092501</td><td>-7.988163</td><td>-12.808929</td><td>-17.635859</td><td>-22.475901</td><td>-27.255258</td><td>-32.039299</td><td> </td></tr><tr><td>0.895</td><td>46.740509</td><td>42.104713</td><td>36.736597</td><td>30.755343</td><td>24.224614</td><td>17.087908</td><td>9.853802</td><td>3.360219</td><td>-2.293161</td><td>-7.426018</td><td>-12.358482</td><td>-17.254878</td><td>-22.122863</td><td>-26.910174</td><td>-31.65453</td><td> </td></tr><tr><td>0.645</td><td>53.63405</td><td>48.823341</td><td>43.145538</td><td>36.706073</td><td>29.56244</td><td>21.689267</td><td>13.405102</td><td>5.735263</td><td>-0.786028</td><td>-6.417941</td><td>-11.659605</td><td>-16.769755</td><td>-21.760135</td><td>-26.617262</td><td>-31.321544</td><td> </td></tr><tr><td>0.395</td><td>66.719783</td><td>61.669457</td><td>55.479065</td><td>48.279934</td><td>40.173712</td><td>31.232975</td><td>21.372923</td><td>11.406692</td><td>2.961089</td><td>-3.87916</td><td>-10.044617</td><td>-15.840246</td><td>-21.29497</td><td>-26.408778</td><td>-31.159668</td><td> </td></tr><tr><td>0.25</td><td>81.066195</td><td>75.939181</td><td>69.61686</td><td>62.097845</td><td>53.400235</td><td>43.453173</td><td>31.99206</td><td>19.510149</td><td>8.697597</td><td>0.08383</td><td>-7.513168</td><td>-14.397559</td><td>-20.598789</td><td>-26.139851</td><td>-31.007816</td><td> </td></tr><tr><td>0.2</td><td>88.630566</td><td>83.616297</td><td>77.408061</td><td>69.893348</td><td>60.994658</td><td>50.53292</td><td>38.266849</td><td>24.550308</td><td>12.460448</td><td>2.685077</td><td>-5.844277</td><td>-13.434216</td><td>-20.125472</td><td>-25.947463</td><td>-30.897252</td><td> </td></tr><tr><td>0.15</td><td>98.70275</td><td>93.957875</td><td>87.989331</td><td>80.562783</td><td>71.487536</td><td>60.477972</td><td>47.235774</td><td>32.081579</td><td>18.171011</td><td>6.62184</td><td>-3.316554</td><td>-11.987794</td><td>-19.434567</td><td>-25.69812</td><td>-30.791197</td><td> </td></tr><tr><td>0.1</td><td>112.445855</td><td>108.177395</td><td>102.579509</td><td>95.384179</td><td>86.396863</td><td>75.206226</td><td>61.200302</td><td>44.511365</td><td>27.603038</td><td>13.116663</td><td>0.853254</td><td>-9.609617</td><td>-18.315011</td><td>-25.317822</td><td>-30.657122</td><td> </td></tr><tr><td>0.05</td><td>129.953349</td><td>126.729465</td><td>122.16493</td><td>115.888176</td><td>107.735583</td><td>97.599944</td><td>84.78044</td><td>67.007035</td><td>45.133323</td><td>25.293443</td><td>8.703572</td><td>-5.123796</td><td>-16.206876</td><td>-24.614329</td><td>-30.421939</td><td> </td></tr><tr><td>0</td><td>146.979281</td><td>145.477655</td><td>143.182354</td><td>139.720174</td><td>134.892754</td><td>128.593272</td><td>119.228637</td><td>104.230568</td><td>81.016758</td><td>53.376624</td><td>27.161422</td><td>5.354242</td><td>-11.477492</td><td>-23.316319</td><td>-30.26605</td><td> </td></tr><tr><td>x (mm)</td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr></tbody></table>
I have applied griddata and fit to the supplied data. poly23 is not the best choice to fit a surface to the supplied data, let me explain:
1.- This is the supplied data
clear all;close all;clc
% supplied data
E=[30.002332 21.985427 6.810482 -15.670808 -45.233394 -77.215051 -105.258626 -125.69229 -137.533424 -144.608218 -149.37894 -153.029304 -155.689815 -157.477955 -158.626949
30.232465 24.087844 14.620048 1.72655 -14.792426 -35.152992 -59.469883 -84.288 -102.159215 -114.172775 -123.557279 -130.950597 -136.22158 -139.785929 -142.188687
30.421325 24.932531 17.444529 7.892998 -3.856977 -18.014886 -34.99118 -54.76071 -73.12193 -87.497601 -98.824193 -108.060712 -114.987903 -120.253359 -124.356373
30.551303 25.391767 18.870906 10.957517 1.538053 -9.535194 -22.598697 -38.389555 -55.208053 -69.556258 -81.254268 -90.739807 -98.322417 -104.256711 -108.853733
30.664703 25.675715 19.70439 12.733737 4.693012 -4.564309 -15.382383 -28.781825 -44.015781 -57.405663 -68.654996 -78.136226 -85.96381 -92.262205 -97.271558
30.727753 25.865955 20.238259 13.853267 6.664413 -1.448761 -10.800537 -22.615818 -36.367379 -48.848877 -59.549314 -68.920612 -76.813046 -83.32022 -88.600393
30.865921 26.241471 21.290271 16.08672 10.626372 4.839985 -1.602854 -9.43494 -18.83834 -28.636958 -37.691591 -45.92364 -53.263184 -59.60791 -64.797286
31.095974 26.462957 21.68939 16.805136 11.820302 6.696608 1.18386 -5.121618 -12.593724 -20.872655 -28.902156 -36.190138 -42.81756 -48.711318 -53.733812
31.46129 26.783809 22.050232 17.24325 12.414941 7.549917 2.463171 -3.126318 -9.525282 -16.772883 -24.024533 -30.735935 -36.907371 -42.495141 -47.386621
31.84872 27.13964 22.399963 17.609472 12.824883 8.054302 3.167199 -2.022925 -7.798272 -14.333423 -20.98601 -27.322197 -33.20454 -38.422392 -43.441491
32.321379 27.611153 22.830246 18.00384 13.186564 8.407782 3.614684 -1.377083 -6.778505 -12.763999 -18.950497 -24.996769 -30.700952 -36.002519 -40.845001
32.912865 28.117376 23.297908 18.414747 13.541529 8.720016 3.953985 -0.893617 -6.030829 -11.646948 -17.480042 -23.272051 -28.818368 -34.05723 -38.898901
33.461235 28.733026 23.846096 18.900341 13.945926 9.043626 4.247023 -0.554529 -5.54091 -10.874341 -16.437732 -22.017734 -27.450488 -32.671967 -37.55842
34.20239 29.399207 24.450979 19.429789 14.378361 9.384043 4.50818 -0.228657 -5.110888 -10.256221 -15.598685 -20.988768 -26.283234 -31.452038 -36.351057
34.914372 30.186026 25.182228 20.081931 14.90649 9.757508 4.793411 -0.022121 -4.818618 -9.801554 -14.977042 -20.209359 -25.40338 -30.537892 -35.491473
35.805782 31.056782 26.042754 20.849744 15.526359 10.206612 5.079032 0.217373 -4.533031 -9.394064 -14.424973 -19.520352 -24.601559 -29.643549 -34.578382
36.912236 32.230447 27.190092 21.88521 16.388134 10.852426 5.512241 0.53729 -4.252576 -9.060047 -13.988674 -18.990227 -23.997652 -28.971069 -33.911535
38.220177 33.55963 28.522922 23.132328 17.438377 11.652987 6.043032 0.901 -3.941164 -8.721107 -13.565417 -18.470008 -23.400995 -28.283206 -33.172001
40.089435 35.460059 30.362062 24.861205 18.933028 12.805265 6.809413 1.39481 -3.583199 -8.390298 -13.200262 -18.057954 -22.938035 -27.768679 -32.61952
42.604155 38.034489 32.852205 27.179704 21.024509 14.456797 7.936568 2.129503 -3.092501 -7.988163 -12.808929 -17.635859 -22.475901 -27.255258 -32.039299
46.740509 42.104713 36.736597 30.755343 24.224614 17.087908 9.853802 3.360219 -2.293161 -7.426018 -12.358482 -17.254878 -22.122863 -26.910174 -31.65453
53.63405 48.823341 43.145538 36.706073 29.56244 21.689267 13.405102 5.735263 -0.786028 -6.417941 -11.659605 -16.769755 -21.760135 -26.617262 -31.321544
66.719783 61.669457 55.479065 48.279934 40.173712 31.232975 21.372923 11.406692 2.961089 -3.87916 -10.044617 -15.840246 -21.29497 -26.408778 -31.159668
81.066195 75.939181 69.61686 62.097845 53.400235 43.453173 31.99206 19.510149 8.697597 0.08383 -7.513168 -14.397559 -20.598789 -26.139851 -31.007816
88.630566 83.616297 77.408061 69.893348 60.994658 50.53292 38.266849 24.550308 12.460448 2.685077 -5.844277 -13.434216 -20.125472 -25.947463 -30.897252
98.70275 93.957875 87.989331 80.562783 71.487536 60.477972 47.235774 32.081579 18.171011 6.62184 -3.316554 -11.987794 -19.434567 -25.69812 -30.791197
112.445855 108.177395 102.579509 95.384179 86.396863 75.206226 61.200302 44.511365 27.603038 13.116663 0.853254 -9.609617 -18.315011 -25.317822 -30.657122
129.953349 126.729465 122.16493 115.888176 107.735583 97.599944 84.78044 67.007035 45.133323 25.293443 8.703572 -5.123796 -16.206876 -24.614329 -30.421939
146.979281 145.477655 143.182354 139.720174 134.892754 128.593272 119.228637 104.230568 81.016758 53.376624 27.161422 5.354242 -11.477492 -23.316319 -30.26605];
I have removed the 1st column from left hand side that doesn't seem to match the screenshot you have supplied.
and this is supplied data with surf
[sz2 sz1]=size(E)
x_range=[-floor(sz1/2):1:floor(sz1/2)];
y_range=[-floor(sz2/2):1:floor(sz2/2)];
[X,Y,Z]=meshgrid(x_range,y_range,0);
figure(1)
ax1=gca
hs1=surf(ax1,X,Y,E)
hs1.EdgeColor='none'
xlabel('X');ylabel('Y');
grid on
title('surf(data)')
direct surf does not add points, the coloured surface is rendering, one can check the amount of points generated with surf with hs1 the handle to this surf output
hs1 =
Surface with properties:
EdgeColor: 'none'
LineStyle: '-'
FaceColor: 'flat'
FaceLighting: 'flat'
FaceAlpha: 1
XData: [29×15 double]
YData: [29×15 double]
ZData: [29×15 double]
CData: [29×15 double]
29x15 we just get what we give.
2.- In MATLAB the default command to fit a surface to 3D data is griddata
Applied here
% define finer grid
dx=.01
nx=(x_range(end)+1-(x_range(1)-1))/dx
x_range2=linspace(x_range(1)-1,x_range(end)+1,nx);
y_range2=linspace(y_range(1)-1,y_range(end)+1,nx);
[xq,yq,zq]=meshgrid(x_range2,y_range2,0);
% yq=linspace(y_range(1)-1,y_range(end)+1,nx);
E_range=linspace(min(E,[],'all'),max(E,[],'all'),nx);
%
Eq=griddata(X,Y,E,xq,yq);
% Eq = griddata(x_range,y_range,E_range,E,xq,yq,zq);
figure(2)
ax2=gca
plot3(ax2,X,Y,E,'ro')
hold on
hs2=surf(ax2,xq,yq,Eq)
hs2.EdgeColor='none'
xlabel('X');ylabel('Y');
grid on
title('griddata(data)')
Now the handle hs2 from this surf does contain all the additional points generated when fitting a surface to the 29X15 (435) points.
Check
hs2 =
Surface with properties:
EdgeColor: 'none'
LineStyle: '-'
FaceColor: 'flat'
FaceLighting: 'flat'
FaceAlpha: 1
XData: [1600×1600 double]
YData: [1600×1600 double]
ZData: [1600×1600 double]
CData: [1600×1600 double]
4.- Depending upon what version of MATLAB being used one can also use command fit to the purpose of fitting a surface to 3D points.
4.1.- fit option poly11 uses a simple linear polynomial curve f1_poly11(x,y) = p00 + p10*x + p01*y
x1=X(:);
y1=Y(:);
E1=E(:);
% 'poly11' Linear polynomial curve
% f1_poly11(x,y) = p00 + p10*x + p01*y
f1_poly11 = fit([x1 y1],E1,"poly11")
figure(3)
plot(f1_poly11,[x1 y1],E1)
title('E fit with poly11')
% poly coefficients available here
f1_poly11.p00
f1_poly11.p10
f1_poly11.p01
as expected linear approximation is not best fit for the supplied points.
4.2.- linear interpolation does quite a good job though
f1_linint = fit([x1 y1],E1,"linearinterp")
figure(4)
plot(f1_linint,[x1 y1],E1)
title('E fit with linearinterp')
% poly coefficients available here
f1_linint.p
4.3.- option cubicinterp is a piecewise cubic interpolation
f1_cbint = fit([x1 y1],E1,"cubicinterp")
figure(5)
plot(f1_cbint,[x1 y1],E1)
title('E fit with cubicinterp')
% poly coefficients available here
f1_cbint.p
4.4.- option lowess is a local linear regression
f1_low = fit([x1 y1],E1,"lowess")
figure(6)
plot(f1_low,[x1 y1],E1)
title('E fit with lowess')
% poly coefficients available here
f1_low.p.Degree
f1_low.p.Lambda
again this regression is not as good as expected, is it?
4.5.- and poly23 is a similar approximation that you have used with nlinfit
using the following expression :
f1_poly23(x,y) = p00 + p10*x + p01*y + p20*x^2 + p11*x*y + p02*y^2 + p21*x^2*y + p12*x*y^2 + p03*y^3
MATLAB returns a confidence interval, always appreciated Coefficients with 95% confidence bounds.
f1_poly23 = fit([x1 y1],E1,"poly23")
figure(7)
plot(f1_poly23,[x1 y1],E1)
title('E fit with poly23')
% poly coefficients available yere
f1_poly23.p00
f1_poly23.p10
f1_poly23.p01
f1_poly23.p20
f1_poly23.p11
f1_poly23.p02
f1_poly23.p21
f1_poly23.p12
f1_poly23.p03
5.- So griddata is quite good at fitting curves.
I'd like to mention that since
hs2.XData
hs2.YData
hs2.ZData
already contains all the points of the approximating surface, do you really need the polynomial expression?
It may be easier and faster to generate the surface, and then whatever your coding is about, just read and process data with the stored points.
Additional comment
There is an improved version of griddata called gridfit by John D'Errico available here
https://uk.mathworks.com/matlabcentral/fileexchange/8998-surface-fitting-using-gridfit?s_tid=srchtitle_surface%20fitting_2
If you find this answer useful would you please be so kind to consider clicking on the accepted answer?
Thanks
Related
I have found several tools which convert isosurface - class or meshgrid data in MATLAB to an STL format. Examples include stlwrite and surf2stl . What I can't quite figure out is how to take a delaunayTriangulation object and either uses it to create an STL file or convert it into an isosurface object.
The root problem is that I'm starting with an N-by-2 array of boundary points for irregular polygons, so I don't have any simple way to generate an xyz meshgrid. If there's a way to convert the boundary list into an isosurface of the interior region (constant Z-height is all I need), that would also solve my problem.
Otherwise, I need some way to convert the delaunayTriangulation object into something the referenced MATLAB FEX tools can handle.
edit to respond to Ander B's suggestion:
I verified that my triangulated set inside MATLAB is a 2-D sector of a circle. But when I feed the data to stlwrite , and import into Cura , I get a disaster - triangles at right angles or rotate pi from desired, or worse. Whether this is the fault of stlwrite , Cura being sensitive to some unexpected value, or both I can't tell. HEre's what started out as a disc:
As an example, here's a set of points which define a sector of a circle. I can successfully create a delaunayTriangulation object from these data.
>> [fcx1',fcy1']
ans =
100.4563 26.9172
99.9712 28.6663
99.4557 30.4067
98.9099 32.1378
98.3339 33.8591
97.7280 35.5701
97.0924 37.2703
96.4271 38.9591
95.7325 40.6360
95.0087 42.3006
94.2560 43.9523
93.4746 45.5906
92.6647 47.2150
91.8265 48.8250
90.9604 50.4202
90.0666 52.0000
89.1454 53.5640
88.1970 55.1116
87.2217 56.6425
86.2199 58.1561
85.1918 59.6519
84.1378 61.1297
83.0581 62.5888
81.9531 64.0288
80.8232 65.4493
79.6686 66.8499
78.4898 68.2301
77.2871 69.5896
76.0608 70.9278
74.8113 72.2445
73.5391 73.5391
72.2445 74.8113
70.9278 76.0608
69.5896 77.2871
68.2301 78.4898
66.8499 79.6686
65.4493 80.8232
64.0288 81.9531
62.5888 83.0581
61.1297 84.1378
59.6519 85.1918
58.1561 86.2199
56.6425 87.2217
55.1116 88.1970
53.5640 89.1454
52.0000 90.0666
50.4202 90.9604
48.8250 91.8265
47.2150 92.6647
45.5906 93.4746
43.9523 94.2560
42.3006 95.0087
40.6360 95.7325
38.9591 96.4271
37.2703 97.0924
35.5701 97.7280
33.8591 98.3339
32.1378 98.9099
30.4067 99.4557
28.6663 99.9712
26.9172 100.4563
25.1599 100.9108
23.3949 101.3345
21.6228 101.7274
19.8441 102.0892
18.0594 102.4200
16.2692 102.7196
14.4740 102.9879
12.6744 103.2248
10.8710 103.4303
9.0642 103.6042
7.2547 103.7467
5.4429 103.8575
3.6295 103.9366
1.8151 103.9842
0 104.0000
-1.8151 103.9842
-3.6295 103.9366
-5.4429 103.8575
-7.2547 103.7467
-9.0642 103.6042
-10.8710 103.4303
-12.6744 103.2248
-14.4740 102.9879
-16.2692 102.7196
-18.0594 102.4200
-19.8441 102.0892
-21.6228 101.7274
-23.3949 101.3345
-25.1599 100.9108
-26.9172 100.4563
0 0
Building on Ander B's answer, here is the complete sequence. These steps ensure that even concave polygons are properly handled.
Start with two vectors containing all the x and the y coordinates. Then:
% build the constraint list
constr=[ (1:(numel(x)-1))' (2:numel(x))' ; numel(x) 1;];
foodel = delaunayTriangulation(x',y',constr);
% get logical indices of interior triangles
inout = isInterior(foodel);
% if desired, plot the triangles and the original points to verify.
% triplot(foodel.ConnectivityList(inout, :),...
foodel.Points(:,1),foodel.Points(:,2), 'r')
% hold on
% plot(fooa.Points(:,1),fooa.Points(:,2),'g')
% now solidify
% need to create dummy 3rd column of points for a solid
point3 = [foodel.Points,ones(numel(foodel.Points(:,1)),1)];
% pick any negative 'elevation' to make the area into a solid
[solface,solvert] = surf2solid(foodel.ConnectivityList(inout,:),...
point3, 'Elevation', -10);
stlwrite('myfigure.stl',solface,solvert);
I've successfully turned some 'ugly' concave polygons into STLs that Cura is happy to turn into gCode.
STL is just a format to store in memory mesh information, thus you have the data if you have a mesh, you just need to write it to memory using the right format.
It appears that you input the vertices and faces to the stlwrite function as
stlwrite(FILE, FACES, VERTICES);
And the delaunayTriangulation output gives you a object that has easy access to this data as for an object DT, DT.Points is the vertices, and DT.ConnectivityList is the faces.
You can read more about it in the documentation you linked.
I'm trying to implement a simple SVM linear binary classification in Matlab but I got strange results.
I have two classes g={-1;1} defined by two predictors varX and varY. In fact, varY is enough to classify the dataset in two distinct classes (about varY=0.38) but I will keep varX as random variable since I will need it to other works.
Using the code bellow (adapted from MAtlab examples) I got a wrong classifier. Linear classifier should be closer to an horizontal line about varY=0.38, as we can perceive by ploting 2D points.
It is not displayed the line that should separate two classes
What am I doing wrong?
g(1:14,1)=1;
g(15:26,1)=-1;
m3(:,1)=rand(26,1); %varX
m3(:,2)=[0.4008; 0.3984; 0.4054; 0.4048; 0.4052; 0.4071; 0.4088; 0.4113; 0.4189;
0.4220; 0.4265; 0.4353; 0.4361; 0.4288; 0.3458; 0.3415; 0.3528;
0.3481; 0.3564; 0.3374; 0.3610; 0.3241; 0.3593; 0.3434; 0.3361; 0.3201]; %varY
SVMmodel_testm = fitcsvm(m3,g,'KernelFunction','Linear');
d = 0.005; % Step size of the grid
[x1Grid,x2Grid] = meshgrid(min(m3(:,1)):d:max(m3(:,1)),...
min(m3(:,2)):d:max(m3(:,2)));
xGrid = [x1Grid(:),x2Grid(:)]; % The grid
[~,scores2] = predict(SVMmodel_testm,xGrid); % The scores
figure();
h(1:2)=gscatter(m3(:,1), m3(:,2), g,'br','ox');
hold on
% Support vectors
h(3) = plot(m3(SVMmodel_testm.IsSupportVector,1),m3(SVMmodel_testm.IsSupportVector,2),'ko','MarkerSize',10);
% Decision boundary
contour(x1Grid,x2Grid,reshape(scores2(:,1),size(x1Grid)),[0 0],'k');
xlabel('varX'); ylabel('varY');
set(gca,'Color',[0.5 0.5 0.5]);
hold off
A common problem with SVM or any classification method for that matter is unnormalized data. You have one dimension that spans for 0 to 1 and the other from about 0.3 to 0.4. This causes inbalance between the features. Common practice is to somehow normalize the features, for examply by std. try this code:
g(1:14,1)=1;
g(15:26,1)=-1;
m3(:,1)=rand(26,1); %varX
m3(:,2)=[0.4008; 0.3984; 0.4054; 0.4048; 0.4052; 0.4071; 0.4088; 0.4113; 0.4189;
0.4220; 0.4265; 0.4353; 0.4361; 0.4288; 0.3458; 0.3415; 0.3528;
0.3481; 0.3564; 0.3374; 0.3610; 0.3241; 0.3593; 0.3434; 0.3361; 0.3201]; %varY
m3(:,2) = m3(:,2)./std(m3(:,2));
SVMmodel_testm = fitcsvm(m3,g,'KernelFunction','Linear');
Notice the line before the last.
I have a spreadsheet ANA2009_1ag.xlsx with column 1= wavelength lambda and col2=specta1, col3=spectra2, col4=spectra3 etc
I want to fit a curve to each of the spectra using the equation:
ag(lambda) = ag(lambda_o)*exp(-S(lambda-lambda_o)
So I can get the slope S.
I have the code and I am able to run it if I have a text file with 2 columns:
column 1= wavelength lambda and col2=specta1
But as i said above I have several spectra so i would like to make a loop so that the routine i got for fitting the curve and getting the slope loops from one column to the next. ut as a novice in matlab loops are my biggest problem.
My code is as follows.
%//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[num,txt,raw]=xlsread('ANA2009_1ag.xlsx');
%// Get the size of data to be plotted
[r,c]=size(num);
%//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%// using txt vector to make appropriate legend that matches the data plot
Sepctra=cellstr(txt); %//C = cellstr converts array to a cell array.
%//FIND OUT HOW YOU CAN SAY TO END OF COLUMN
for i=2:7
Sepctra(i)=txt(i);
end
%//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%//takeout range of interest
I=find(num(:,1)<650 & num(:,1)>400);
wl=num(I,1);
a_g=num(I,2);
%//setting options for fmisearch
opts = optimset('fminsearch');
opts = optimset(opts,'MaxIter',4000);
opts = optimset(opts,'MaxFunEvals',2000); %// usually 100*number of params
opts = optimset(opts,'TolFun',1e-9);
%//opts = optimset('LevenbergMarquardt','on');
%//guess for paramters (amplitude at 532 and slope)
x0=[0.1, 0.03];
%//minimization routine
x1 = fminsearch(#least_squares,x0,opts,a_g,wl)
%//plot data and fit
plot(wl, a_g, '.k', wl, x1(1)*exp(-x1(2)*(wl-412)),'b')
DATA IS FROM 300 NM (LAMBDA) TO 685 NM (lambda) BUT I CHOSE TO FIT THE CURVE FROM 650-400NM
Wavelength AN10070A-4m AN10066A-10m
300 1.561434 1.434769
300.5 1.549919 1.42786
301 1.531495 1.414042
301.5 1.506162 1.400224
302 1.483132 1.386406
302.5 1.467011 1.372588
303 1.45089 1.356467
303.5 1.443981 1.342649
304 1.42786 1.333437
304.5 1.414042 1.324225
305 1.407133 1.31271
My expected output is:
x1 which is a vector of the amplitude at 412nm and the slope S
I would like to post the figure that i got for the curve fit but I dont know how to do it.
I am currently working with my undergraduate thesis on complex valued neural network(CVNN).My topic is based on Single-layered complex-valued neural network for real-valued classification problems.I am using gradient-descent learning rule to classify a dataset given below:
Data Set
The alogorithm i used here can be found on page 946 of the following PDF labeled as Complex valued neuron (CVN) Model.The main algorithm can be on section 3 of that topic
Algorithm of CVN Model
But instead of getting convergence,my error curve has shown divergent characteristics.Here is my output of error curve.
error curve at CVNN implementation
I am simulating the code behind this on MATLAB.My implementation is also given below:
clc
clear all
epoch=1000;
n=8;
%x=real input value
in=dlmread('Diabetes1.txt');
x=in(1:384,1:8);
%d=desired output value
out=dlmread('Diabetes1.txt');
data_1=out(1:384,9);
data_2=out(1:384,10);
%m=complex representation of input
m=(cos((pi).*(x(:,:)-0))+1i*sin((pi).*(x(:,:)-0)));
%
%research
%m=i.*x(:,:)
%m=x(:,:)+i.*x(:,:)
%Wih=weight
%
%m=x(:,:).*(cos(pi./4)+i.*sin(pi./4));
Wih1 =0.5* exp(1i * 2*pi*rand(8,1));
Wih2 =0.5* exp(1i * 2*pi*rand(8,1));
%Pih=bias
Pih1 =0.5*exp(1i * 2*pi*rand(1,1));
Pih2 =0.5*exp(1i * 2*pi*rand(1,1));
for ite=1:epoch
% www(ite)=ite;
E_Total=0;
E1t=0;
E2t=0;
for j=1:384
%blr=learning rate
blr=0.1;
%cpat=current pattern
cpat = m(j,:);
z1=cpat*Wih1+Pih1;
u1=real(z1);
v1=imag(z1);
fu1=1/(1+exp(-u1));
fv1=1/(1+exp(-v1));
%y=actual output
%for activation function 1
y1=sqrt((fu1).^2+(fv1).^2);
%for activation function 2
% y1=(fu1-fv1).^2;
error1=(data_1(j,1)-y1);
E1=((data_1(j,1)-y1).^2);
t11=1./(1+exp(-u1));
f11=t11.*(1-t11);
t21=1./(1+exp(-v1));
f21=t21.*(1-t21);
%for activation function 1
r1= blr.*(data_1(j,1)-y1).*((t11.*f11)./y1)+i.*blr.*(data_1(j,1)-y1).*((t21.*f21)./y1);
%for activation function 2
%r1=2.*blr.*(data_1(j,1)-y1).*(t11-t21).*f11+1i.*2.*blr.*(data_1(j,1)-y1).*(t21-t11).*f21;
%
Pih1=Pih1+r1;
Wih1= Wih1+(conj(m(j,:)))'.*r1;
%////////////////////////////////////////////////
%cpat=current pattern
z2=cpat*Wih2+Pih2;
u2=real(z2);
v2=imag(z2);
fu2=1./(1+exp(-u2));
fv2=1./(1+exp(-v2));
% fu2=tanh(u2);
% fv2=tanh(v2);
%y=actual output
%for activation function 1
y2=sqrt((fu2).^2+(fv2).^2);
%for activation function 2
% y2=(fu2-fv2).^2;
error2=(data_2(j,1)-y2);
E2=((data_2(j,1)-y2).^2);
t12=1./(1+exp(-u2));
f12=t12.*(1-t12);
t22=1./(1+exp(-v2));
f22=t22.*(1-t22);
%for activation function1
r2= blr.*(data_2(j,1)-y2).*((t12.*f12)./y2)+i.*blr.*(data_2(j,1)-y2).*((t22.*f22)./y2);
%for activation function 2
%r2=2*blr*(data_2(j,1)-y2)*(t12-t22)*f12+1i*2*blr*(data_2(j,1)-y2)*(t22-t12)*f22;
Pih2=Pih2+r2;
Wih2= Wih2+(conj(m(j,:)))'.*r2;
%///////////////////////////////////////////////
E1t=E1+E1t;
E2t=E2+E2t;
E_Total=(E1+E2+E_Total);
E1;
E2;
end
Err=E_Total/(2.*384);
figure(1)
plot(ite,Err,'b--')
hold on;
%figure(1)
end
dlmwrite('weight.txt',Wih1)
dlmwrite('weight.txt', Wih2, '-append', ...
'roffset', 1, 'delimiter', ' ')
dlmwrite('weight.txt', Pih1, '-append', ...
'roffset', 1, 'delimiter', ' ')
dlmwrite('weight.txt', Pih2, '-append', ...
'roffset', 1, 'delimiter', ' ')
I still could not figure out reason behind this opposite characteristics on the dataset.So any kind of help regarding this is appreciated.
If you are doing gradient descent, a very common debugging technique is to check whether the gradient you calculated actually matches the numerical gradient of your loss function.
That is, check
(f(x+dx)-f(x))/dx==f'(x)*dx
for a variety of small dx. Usually try along each dimension, as well as in a variety of random directions. You also want to do this check for a variety of value of x.
You should take a glance at this blog for complex back-propagation.
For holomorphic functions, complex BP are fairly straight forward.
For non-holomorphic functions (every CVNN must have at least one non-holomorphic function), they need careful treat.
I am using Matlab. I have a large column vector consisting of complex values. e.g.
data=[
-0.4447 + 0.6263i
0.3114 + 0.8654i
0.7201 + 0.6808i
0.7566 + 0.8177i
-0.7532 - 0.8085i
-0.7851 + 0.6042i
-0.7351 - 0.8725i
-0.4580 + 0.8053i
0.5775 - 0.6369i
0.7073 - 0.5565i
0.4939 - 0.7015i
-0.4981 + 0.8112i
....
]
This represents a constellation diagram which is shown below.
I would like to colour grade the constellation points depending on frequency at a particular point. I presume I need to create a histogram, but I am not sure how to do this using complex vectors and then how to plot the colour grade.
Any help appreciated.
I think you want to do a heat map:
histdata = [real(data), imag(data)];
nbins_x = nbins_y = 10;
[N, C] = hist3(histdata, [nbins_x, nbins_y]); % the second argument is optional.
imagesc(N);
Here hist3 creates the histogram-matrix, imagesc draws a scaled heat-map. If you prefer a 3d-visualization, just type hist3(histdata).
If you just right-click on N in the workspace window there are plenty of other visualization options. I suggest also trying contourf(N) which is a filled contour plot.
So, what you want to do is to find a two-2 histogram. The easiest way would be to separate out the real and imaginary points, and use the hist2d function, like this:
rdata=real(data);
idata=imag(data);
hist2d([rdata;idata]);