Graph perpendicular line when axes scales are different - math

Consider the following toy example:
clear
set seed 1234567890
set obs 500
generate v1 = rnormal(434.80132, 237.89369)
generate v2 = rnormal(0.08, 0.04)
generate y1 = 10000 * v2
twoway scatter v1 v2 || line y1 v2
I would like to find and graph a line perpendicular to the one above.
Basic math tells us that if the slope of a straight line with equation y = m * x is m, then the slope of the other line is the negative reciprocal of m:
generate y2 = -(1 / 10000) * v2
twoway scatter v1 v2 || line y1 v2 || line y2 v2
Evidently, this is not the case here and the problem appears to be twofold:
The graph's aspect ratio
The axes different scales
How can I programmatically integrate these two in my solution?
Note that the y-xis of this graph is 4 inches while the x-axis is 5.5 inches (thus the aspect ratio is 5.5 / 4 = 1.375).
I have consulted a number of posts such as:
How do you find a point at a given perpendicular distance from a line?
Find perpendicular line using points on that line
calculate a perpendicular offset from a diagonal line
However, I have not been able to come up with a working solution yet.
EDIT:
Here are the data that the above code generates:
v1 v2 y1 y2
269.39346 .1296253 1296.253 -.00001296253
296.7234 .10551854 1055.1854 -.000010551854
-26.31669 .10365818 1036.5818 -.000010365818
657.1838 .1518674 1518.674 -.00001518674
252.1337 .11415068 1141.5068 -.000011415068
524.65295 .08042029 804.2029 -8.042029e-06
302.86755 .04647604 464.7604 -4.647604e-06
419.6649 .10652875 1065.2875 -.000010652875
920.3746 .12058274 1205.8274 -.000012058274
382.45035 .11835476 1183.5476 -.000011835476
563.7043 .05736395 573.63947 -5.736395e-06
714.242 .028945755 289.45755 -2.8945756e-06
511.74585 .07873922 787.3922 -7.873922e-06
305.3213 .12720083 1272.0083 -.000012720083
485.2742 .04365303 436.5303 -4.3653026e-06
143.06741 .09216157 921.6157 -9.216156e-06
187.2168 .13030003 1303.0002 -.000013030003
612.5165 .1331835 1331.835 -.00001331835
361.2785 .08907203 890.7203 -8.907204e-06
360.4551 .06243951 624.3951 -6.243951e-06
296.04575 .10163532 1016.3532 -.000010163532
569.25415 .09742134 974.2134 -9.742134e-06
637.6291 .09733213 973.3213 -9.733213e-06
560.2654 .21330532 2133.0532 -.00002133053
448.2809 .14670238 1467.0238 -.000014670238
683.3372 .1697338 1697.3383 -.000016973383
523.0644 -.004095574 -40.95574 4.095574e-07
411.0599 .030772524 307.72525 -3.0772524e-06
441.5038 .06584484 658.4484 -6.584484e-06
336.168 .0958923 958.923 -9.58923e-06
198.6761 .08582716 858.2715 -8.582716e-06
246.97536 .152105 1521.05 -.0000152105
460.7311 .09324597 932.4597 -9.324597e-06
287.2187 .021772934 217.72934 -2.1772935e-06
38.66368 .036870584 368.7058 -3.687058e-06
500.0821 .14235458 1423.5458 -.000014235457
352.3894 .07493528 749.3528 -7.493528e-06
811.4477 .04826602 482.6602 -4.826602e-06
679.0712 .06238959 623.8959 -6.238959e-06
301.30457 .09074442 907.4442 -9.0744425e-06
757.7222 .05119324 511.9324 -5.119325e-06
570.274 .10332661 1033.2661 -.00001033266
590.91846 .10045127 1004.5127 -.000010045127
620.4365 .14892302 1489.2302 -.000014892303
130.16528 .08897128 889.7128 -8.897128e-06
336.9956 .1393297 1393.297 -.00001393297
839.7582 .0996195 996.195 -9.96195e-06
390.4998 .0865124 865.124 -8.651239e-06
326.7999 .033503372 335.0337 -3.350337e-06
350.7236 .05849207 584.9207 -5.849207e-06
625.7621 .13081506 1308.1506 -.000013081506
661.3865 .10882486 1088.2485 -.000010882486
772.1646 .05676838 567.6838 -5.676838e-06
288.92468 .04983922 498.3922 -4.983922e-06
452.0564 .08711468 871.1469 -8.711469e-06
119.64562 .14033437 1403.3436 -.000014033437
540.64465 .01785021 178.5021 -1.785021e-06
486.0001 .0352254 352.254 -3.52254e-06
313.4424 .069143936 691.4393 -6.914393e-06
664.7051 .05293872 529.3872 -5.293872e-06
331.3703 .06169248 616.9249 -6.169249e-06
-62.07745 .06645174 664.5175 -6.645174e-06
993.134 .07217993 721.7993 -7.217993e-06
601.41437 .07325878 732.5878 -7.325878e-06
567.1587 .13941422 1394.1422 -.000013941422
118.95367 .05569748 556.9748 -5.569748e-06
437.1982 .05619644 561.96436 -5.619644e-06
283.20987 .04376043 437.6043 -4.376043e-06
362.279 .1073577 1073.5769 -.00001073577
173.81154 .08425744 842.5744 -8.4257435e-06
365.7731 .06203346 620.3346 -6.203346e-06
695.8716 .08280326 828.0327 -8.280326e-06
105.1409 .08470224 847.0224 -8.470224e-06
438.4622 .06138157 613.8157 -6.138157e-06
704.993 .05607803 560.7803 -5.607803e-06
11.55953 .1063125 1063.1249 -.00001063125
520.18304 .15763256 1576.3256 -.000015763257
685.0488 .1517116 1517.116 -.000015171158
645.567 .04092862 409.2862 -4.092862e-06
361.465 .07043068 704.3068 -7.043068e-06
1050.0239 .1012046 1012.0459 -.00001012046
99.06884 .06545984 654.5984 -6.545984e-06
699.0544 .09549447 954.9447 -9.549447e-06
547.5491 .11651776 1165.1776 -.000011651776
367.7509 .07570159 757.0159 -7.570159e-06
554.36414 .06114044 611.4044 -6.114044e-06
174.2912 .05117374 511.7374 -5.117374e-06
615.7756 .022821637 228.21637 -2.282164e-06
678.1454 .1108198 1108.198 -.00001108198
522.73535 .07071783 707.1783 -7.071783e-06
411.2797 .04971372 497.1372 -4.971372e-06
308.1041 .05743588 574.35876 -5.743588e-06
-375.5049 .05214334 521.4334 -5.214334e-06
40.3021 .16943806 1694.3806 -.000016943806
578.10266 .04062266 406.2266 -4.0622663e-06
198.2699 .035349682 353.4968 -3.534968e-06
254.9718 .00995418 99.54179 -9.95418e-07
538.3042 .04819309 481.9309 -4.819309e-06
608.1482 .10872427 1087.2428 -.000010872427
40.12729 .04191337 419.1337 -4.1913368e-06

The visual slope of a line is just:
slope = m * height * domain / (width * range)
Here width and height are the physical dimensions of the plot (you said 5.5” by 4”), while domain and range are the span of x and y values it covers (here, about 0.225 and 2300).
Call the m coefficient (in this case, about 7.1e-5) v (for visual), and we have that:
slope2 = -1 / slope1
m2 * v * m1 * v = -1
m2 = -1 / (m1 * v^2)
In your example, this equates to approximately -19800.

Related

Plotting a 3D surface in Julia, using either Plots or PyPlot

I would like to plot a two variable function(s) (e_pos and e_neg in the code). Here, t and a are constants which I have given the value of 1.
My code to plot this function is the following:
t = 1
a = 1
kx = ky = range(3.14/a, step=0.1, 3.14/a)
# Doing a meshgrid for values of k
KX, KY = kx'.*ones(size(kx)[1]), ky'.*ones(size(ky)[1])
e_pos = +t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
e_neg = -t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
using Plots
plot(KX,KY,e_pos, st=:surface,cmap="inferno")
If I use Plots this way, sometimes I get an empty 3D plane without the surface. What am I doing wrong? I think it may have to do with the meshgrids I did for kx and ky, but I am unsure.
Edit: I also get the following error:
I changed some few things in my code.
First, I left the variables as ranges. Second, I simply computed the functions I needed without mapping the variables onto them. Here's the code:
t = 2.8
a = 1
kx = range(-pi/a,stop = pi/a, length=100)
ky = range(-pi/a,stop = pi/a, length=100)
#e_pos = +t*np.sqrt(3 + 4*np.cos(3*KX*a/2)*np.cos(np.sqrt(3)*KY*a/2) + 2*np.cos(np.sqrt(3)*KY*a))
e_pos(kx,ky) = t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
e_neg(kx,ky) = -t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
# Sort of broadcasting?
e_posfunc = e_pos.(kx,ky);
e_negfunc = e_neg.(kx,ky);
For the plotting I simply used the GR backend:
using Plots
gr()
plot(kx,ky,e_pos,st=:surface)
plot!(kx,ky,e_neg,st=:surface, xlabel="kx", ylabel="ky",zlabel="E(k)")
I got what I wanted!

Find local minima in noisy data with exact criteria and without for-loop

I have a timerow and would like to find minima which fulfill specific criteria. Those are that the number of points within the valleys (below the red line) between 2 peaks should exceed a certain value and also the number of points above the red line should exceed a certain value for each peak neighboring the valley. Also the lower of the two peaks should be resolved at a value lower than 50% of its height (meaning that the max(intensity) of the lower of the two peaks should be at least 2 fold the intensity of the lowest intensity within the valley between the two peaks - as calculated below in the code sample). I drew the red line here at a specific height but in reality those unresolved peaks can have any height and can also be seperated by any distance. So what I am doing at the moment is to "scan" with the red line over each point of the time series which is of course very slow and inefficient.
So here is the for-loop I am using at the moment:
detect_double_peaks <- function(pot.doubleP.v, Min.PpP = 10) {
peak.dt <-
data.table(
breakP = NA,
breakH = NA,
resolved = NA
)
for (point in pot.doubleP.v[pot.doubleP.v > 0 &
pot.doubleP.v < 0.8 * max(pot.doubleP.v)]) {
doublePeak.rle <- S4Vectors::Rle(pot.doubleP.v > point)
doublePeak.rle.dt <-
data.table(
idx = as.numeric(seq.int(length(
doublePeak.rle#values
))),
values = doublePeak.rle#values,
lengths = doublePeak.rle#lengths,
start = start(doublePeak.rle),
end = end(doublePeak.rle)
)
doublePeak.rle.dt_p <-
doublePeak.rle.dt[values == TRUE & lengths > Min.PpP]
if (nrow(doublePeak.rle.dt_p) > 1) {
for(peak in 1:nrow(doublePeak.rle.dt_p)-1){
doublePeak.rle.dt_v <- doublePeak.rle.dt[idx > doublePeak.rle.dt_p[peak]$idx & idx < doublePeak.rle.dt_p[peak + 1]$idx]
if(sum(doublePeak.rle.dt_v[values == FALSE]$lengths) >= max(max(doublePeak.rle.dt_p[peak]$lengths, doublePeak.rle.dt_p[peak+1]$lengths) * 0.5, Min.PpP)){
dp.p_height_h <-
max(max(pot.doubleP.v[(doublePeak.rle.dt_p[peak]$start):(doublePeak.rle.dt_p[peak]$end)]),
max(pot.doubleP.v[(doublePeak.rle.dt_p[peak + 1]$start):(doublePeak.rle.dt_p[peak + 1]$end)]))# - baseL
dp.p_height_l <-
min(max(pot.doubleP.v[(doublePeak.rle.dt_p[peak]$start):(doublePeak.rle.dt_p[peak]$end)]),
max(pot.doubleP.v[(doublePeak.rle.dt_p[peak + 1]$start):(doublePeak.rle.dt_p[peak + 1]$end)]))# - baseL
breakH <-
min(pot.doubleP.v[min(doublePeak.rle.dt[idx > doublePeak.rle.dt_p[peak]$idx]$start):max(doublePeak.rle.dt[idx < doublePeak.rle.dt_p[peak+1]$idx]$end)])# - baseL
resolved <-
breakH / dp.p_height_l * 100
breakP <-
which.min(pot.doubleP.v[min(doublePeak.rle.dt[idx > doublePeak.rle.dt_p[peak]$idx]$start):max(doublePeak.rle.dt[idx < doublePeak.rle.dt_p[peak+1]$idx]$end)]) +
doublePeak.rle.dt_p[peak]$end
peak.dt <- rbind(peak.dt,
data.table(breakP = breakP,
breakH = breakH,
resolved = resolved))
}
}
}
}
if(nrow(peak.dt) == 1) {return(NULL)} else{
return(na.omit(unique(peak.dt, by="breakP")))
}
}
Here are some example data:
testvector <- c(13126.177734375, 12040.060546875, 10810.6171875, 10325.94140625,
13492.8359375, 33648.5703125, 14402.603515625, 29920.12890625,
24316.224609375, 36019.26171875, 34492.4609375, 53799.82421875,
45988.72265625, 47930.453125, 67438.9140625, 61231.83984375,
56710.9140625, 62301.6796875, 54844.7578125, 70913.578125, 81028.1640625,
75234.203125, 59611.05078125, 79240.4375, 52313.3828125, 78758.2734375,
87918.5859375, 80764.7421875, 108035.5390625, 76263.875, 72401.6796875,
83167.640625, 76173.96875, 66241.4296875, 68687.4375, 52107.83984375,
45672.5390625, 51907.33203125, 39967.453125, 58856.90625, 52402.53125,
36980.3125, 43365.76171875, 40480.75, 39057.96484375, 31622.58984375,
23830.455078125, 27393.30078125, 30675.208984375, 27327.48046875,
25150.08984375, 23746.212890625, 9637.625, 19065.58984375, 21367.40625,
6789.0625, 9892.7490234375, 26820.685546875, 19965.353515625,
28281.462890625, 25495.0703125, 28808.416015625, 40244.03125,
35159.421875, 35257.984375, 39971.8046875, 34710.4453125, 60987.73828125,
50620.06640625, 58757.69140625, 52998.97265625, 55601.96484375,
69057.9453125, 58486.52734375, 66115.4765625, 80801.7578125,
77444.6015625, 43545.48828125, 79545.0703125, 50352.484375, 77401.8671875,
85118.421875, 80521.9296875, 68945.8125, 93098.0234375, 83065.8046875,
95970.8203125, 74141.8828125, 90298.75, 81251.0234375, 99658.3359375,
88812.2578125, 81939.4921875, 82632.1015625, 100125.0078125,
71627.84375, 70560.1484375, 77831.765625, 68122.328125, 79049.140625,
88000.890625, 64897.4453125, 57333.3046875, 68185.3046875, 67742.3515625,
58941.85546875, 63184.8671875, 36998.67578125, 45416.58984375,
31547.3359375, 32141.58203125, 35292.9765625, 30511.861328125,
25419.716796875, 23901.431640625, 15616.8759765625, 14469.16015625,
15026.0009765625, 18321.42578125, 15820.861328125, 19532.056640625,
13230.6240234375, 14586.76953125, 14912.642578125, 8541.5224609375,
21740.98046875, 19588.986328125, 18603.662109375, 19656.5625,
10812.94921875, 18379.3359375, 31242.716796875, 25626.0390625,
42446.71875, 27782.294921875, 38450.703125, 39070.97265625, 52914.375,
56484.47265625, 47741.88671875, 52397.18359375, 79378.2109375,
77866.078125, 55902.09765625, 66988.2265625, 63571.01171875,
66192.53125, 79989.8046875, 57204.59765625, 51172.9921875, 49612.16015625,
60508.0390625, 69518.09375, 48079.5625, 48691.0390625, 33679.12890625,
30697.470703125, 31209.359375, 49656.16796875, 32041.912109375,
13851.48828125, 29316.44921875, 31586.216796875, 45422.19921875,
24208.515625, 31496.083984375, 26250.646484375, 14318.302734375
)
For this vector the minima at 56 and 125 should be returned.
Those should be returned because when scanning with the red line through the points of the vector there is at least one iteration at which there are more than Min.PpP = 10 consecutive points above the red line on each side of the valley, and with the same red line there are also more than Min.PpP = 10 points in the valley. The reason why point 4 should not be returned as minima is that no matter where we put the red line the valley will never exceed 3 points (which is lower than Min.PpP = 10) and the peak on the left side of that minima would only be 1 point (which is also lower than Min.PpP = 10).
I am aware of functions like pastecs::turnpoints. However, they do not seem to offer the implementation of criteria as I want to use them.
So it there any other more efficent way to achive that?
Ps.:
I have also put another criteria in the example code which says that there should be at least halve as many points in the vally as there are for the peak with the smaller number of points even when Min.PpP is exceeded:
if(sum(doublePeak.rle.dt_v[values == FALSE]$lengths) >= max(max(doublePeak.rle.dt_p[peak]$lengths, doublePeak.rle.dt_p[peak+1]$lengths) * 0.5, Min.PpP))
However I guess thats not really important for this problem.

Octave plot is not correctly printed in pdfcairo

I'm trying to subplot my data, but printing in PDF brings results I can't use: Title and x-axis title are cut (and the legend's box is covered by the graph, but I can handle this with other positions). I have to use gnuplot and pdfcairo because other seup isn't working with special characters, umlaut, etc.
clear;clc;close all;clf;clear all;
graphics_toolkit("gnuplot")
x = 0:.1:10;
y1 = exp(-x).*sin(x);
y2 = exp(x);
h=figure(1);
subplot(2,1,1);
plot(x,y1)
h1 = plot(x,y1);
set(h1,'LineWidth',4)
set(gca,'FontSize',32)
set(gca,'FontName','Times')
set(get(gca,'Ylabel'),'String','TTEST test \rho \rightarrow','FontWeight','Bold','FontSize',32)
set(get(gca,'Xlabel'),'String','abc / - \rightarrow','FontWeight','Bold','FontSize',32)
legend({
'h_{ref}(t)'
},"location", 'northeast');
title('TITLE')
l1 = legend;
set(l1,'FontName','Times')
subplot(2,1,2);
h2 = plot(x,y2);
set(h2,'LineWidth',4)
set(gca,'FontSize',32)
set(gca,'FontName','Times')
set(get(gca,'Ylabel'),'String','TTEST test \rho \rightarrow','FontWeight','Bold','FontSize',32)
set(get(gca,'Xlabel'),'String','agc / -\rightarrow','FontWeight','Bold','FontSize',32)
legend({
'h_{ref}(t)'
},"location", 'northeast');
l2 = legend;
set(l2,'FontName','Times')
print ('title_axis.pdf', '-dpdfcairo', '-S1000,600');

Using inttrap and diff to get the length of a curve in Scilab

How can you get the length of the curve down below between 0 and 4*pi? The commands you should use are inttrap and diff. Here is what I have now:
t=linspace(0,4*%pi)
x=(4+sin(a*t)).*cos(3*t)
y=(4+sin(a*t)).*sin(3*t)
z=cos(3*t)
xx=diff(x)
yy=diff(y)
zz=diff(z)
aid=sqrt(xx^2+yy^2+zz^2)
length=inttrap([t],aid)
Getting error message, the last step is not right.
The reason for error message is that t and aid have different sizes. And that is because diff returns a vector with 1 entry fewer than the input. You can see how it works on an example: diff([3 1 5]) is [-2 4].
To fix this, use t(1:$-1), which omits the last entry of t. That is,
len = inttrap(t(1:$-1), aid)
(Please don't use length, which is a function name in Scilab.)
Another problem you have is that diff is just differences, not a derivative. To get the derivative, you need to divide by the step size, which in your case is t(2)-t(1).
Also, the syntax xx^2 is deprecated for elementwise power; use xx.^2 instead
t = linspace(0,4*%pi)
a = 1
x = (4+sin(a*t)).*cos(3*t)
y = (4+sin(a*t)).*sin(3*t)
z = cos(3*t)
step = t(2)-t(1)
xx = diff(x)/step
xy = diff(y)/step
xz = diff(z)/step
aid = sqrt(xx.^2+yy.^2+zz.^2)
len = inttrap(t(1:$-1), aid)

Julia: using CurveFit package non linear

why the code below does not work?
xa = [0 0.200000000000000 0.400000000000000 1.00000000000000 1.60000000000000 1.80000000000000 2.00000000000000 2.60000000000000 2.80000000000000 3.00000000000000 3.80000000000000 4.80000000000000 5.00000000000000 5.20000000000000 6.00000000000000 6.20000000000000 7.40000000000000 7.60000000000000 7.80000000000000 8.60000000000000 8.80000000000000 9.00000000000000 9.20000000000000 9.40000000000000 10.0000000000000 10.6000000000000 10.8000000000000 11.2000000000000 11.6000000000000 11.8000000000000 12.2000000000000 12.4000000000000];
ya = [-0.183440428023042 -0.131101157495126 0.0268875670852843 0.300000000120000 0.579048247883555 0.852605831272159 0.935180993484717 1.13328608090532 1.26893326843583 1.10202945535186 1.09201137189664 1.14279083803453 0.811302535321072 0.909735376251797 0.417067545528244 0.460107770989798 -0.516307074859654 -0.333994077331822 -0.504124744955962 -0.945794320817293 -0.915934553082780 -0.975458595671737 -1.09943707404275 -1.11254211607374 -1.29739980589100 -1.23440439602665 -0.953807504156356 -1.12240274852172 -0.609284630192522 -0.592560286759450 -0.402521296049042 -0.510090363150962];
x0 = vec(xa)
y0 = vec(ya)
fun(x,a) = a[1].*sin(a[2].*x - a[3])
a0 = [1,2,3]
eps = 0.000001
maxiter=200
coefs, converged, iter = CurveFit.nonlinear_fit(x0 , fun , a0 , eps, maxiter )
y0b = fit(x0)
Winston.plot(x0, y0, "ob", x0, y0b, "r-", linewidth=3)
Error: LoadError: MethodError: convert has no method matching convert(::Type{Float64}, ::Array{Float64,1}) This may have arisen from
a call to the constructor Float64(...), since type constructors fall
back to convert methods. Closest candidates are: call{T}(::Type{T},
::Any) convert(::Type{Float64}, !Matched::Int8)
convert(::Type{Float64}, !Matched::Int16)
while loading In[269], in expression starting on line 8
in nonlinear_fit at /home/jmarcellopereira/.julia/v0.4/CurveFit/src/nonlinfit.jl:75
The fun function has to return a residual value r of type Float64, calculated at each iteration of the data, as follows:
r = y - fun(x, coefs)
so your function y=a1*sin(x*a2-a3) will be defined as:
fun(x,a) = x[2]-a[1]*sin(a[2]*x[1] - a[3])
Where:
x[2] is a value of 'y' vector
x[1] is a value of 'x' vector
a[...] is the set of parameters
The fun function has to return a single Float64, so the operators can't be 'dot version' (.*).
By calling the nonlinear_fit function, the first parameter must be an array Nx2, with the first column containing N values of x and the second, containing N values of y, so you must concatenate the two vectors x and y in a two columns array:
xy = [x y]
and finally, call the function:
coefs, converged, iter = CurveFit.nonlinear_fit(xy , fun , a0 , eps, maxiter )
Answering to your comment about the returned coefficients are not correct:
The y = 1 * sin (x * a2-a3) is a harmonic function, so the coefficients returning from the function call, depend heavily on the parameter a0 ("initial guess for each fitting parameter") you will send as the third parameter (with maxiter=200_000):
a0=[1.5, 1.5, 1.0]
coefficients: [0.2616335317043578, 1.1471991302529982,0.7048665905560775]
a0=[100.,100.,100.]
coefficients: [-0.4077952060368059, 90.52328921205392, 96.75331155303707]
a0=[1.2, 0.5, 0.5]
coefficients: [1.192007321713507, 0.49426296880933257, 0.19863645732313934]
I think the results you're getting are harmonics, as the graph:
Where:
blue line:
f1(xx)=0.2616335317043578*sin(xx*1.1471991302529982-0.7048665905560775)
yellow line:
f2(xx)=1.192007321713507*sin(xx*0.49426296880933257-0.19863645732313934)
pink line:
f3(xx)=-0.4077952060368059*sin(xx*90.52328921205392-96.75331155303707)
blue dots are your initial data.
The graph was generated with Gadfly:
plot(layer(x=x,y=y,Geom.point),layer([f1,f2,f3],0.0, 15.0,Geom.line))
tested with Julia Version 0.4.3
from Doc:
we are trying to fit the relationship fun(x, a) = 0
So, if you want to find elements of a in a way that: for each xi,yi in [x0 y0] => a[1].*sin(a[2].*xi - a[3])==yi, then the right way is:
fun(xy,a) = a[1].*sin(a[2].*xy[1] - a[3])-xy[2];
xy=hcat(x0,y0);
coefs,converged,iter = CurveFit.nonlinear_fit(xy,fun,a0,eps,maxiter);
I found the LsqFit package a bit simpler to use, just define first the model and "fit it" with your data:
using DataFrames, Plots, LsqFit
xa = [0 0.200000000000000 0.400000000000000 1.00000000000000 1.60000000000000 1.80000000000000 2.00000000000000 2.60000000000000 2.80000000000000 3.00000000000000 3.80000000000000 4.80000000000000 5.00000000000000 5.20000000000000 6.00000000000000 6.20000000000000 7.40000000000000 7.60000000000000 7.80000000000000 8.60000000000000 8.80000000000000 9.00000000000000 9.20000000000000 9.40000000000000 10.0000000000000 10.6000000000000 10.8000000000000 11.2000000000000 11.6000000000000 11.8000000000000 12.2000000000000 12.4000000000000];
ya = [-0.183440428023042 -0.131101157495126 0.0268875670852843 0.300000000120000 0.579048247883555 0.852605831272159 0.935180993484717 1.13328608090532 1.26893326843583 1.10202945535186 1.09201137189664 1.14279083803453 0.811302535321072 0.909735376251797 0.417067545528244 0.460107770989798 -0.516307074859654 -0.333994077331822 -0.504124744955962 -0.945794320817293 -0.915934553082780 -0.975458595671737 -1.09943707404275 -1.11254211607374 -1.29739980589100 -1.23440439602665 -0.953807504156356 -1.12240274852172 -0.609284630192522 -0.592560286759450 -0.402521296049042 -0.510090363150962];
x0 = vec(xa)
y0 = vec(ya)
xbase = collect(linspace(minimum(x0),maximum(x0),100))
p0 = [1.2, 0.5, 0.5] # initial value of parameters
fun(x0, p) = p[1] .* sin.(p[2] .* x0 .- p[3]) # definition of the model
fit = curve_fit(fun,x0,y0,p0) # actual fitting job
yFit = [fit.param[1] * sin(fit.param[2] * x - fit.param[3]) for x in xbase] # building the fitted values
# Plotting..
scatter(x0, y0, label="obs")
plot!(xbase, yFit, label="fitted")
Note that using LsqFit does not solve the problem of dependency from initial conditions highlighted by Gomiero..

Resources