Runge Kutta plot graphic - matlab

i have this code in octave for the runge kutta of the 4th order method but i cant create a graph
dy=#(x,y)-x^2+2*y;
f=#(x)exp(x^2/2);
a=0;
b=2;
y=1;
y0=1;
m=20;
h=(b-a)/m;
k=0;
fprintf('k \t x \t\t y (RK4) \t k1 \t\t k2 \t\t k3 \t\t k4 \n')
fprintf('%d \t %f \t %f \t\n', k,a,y);
for x=a:h:b-h
k1=dy(x,y)*h;
k2=dy((x+h)/2,(y+k1)/2)*h;
k3=dy((x+h)/2,(y+k2)/2)*h;
k4=dy((x+h)/2,(y+k3)/2)*h;
k=k+1;
y=y+dy(x,y)*h;
x=x+h;
fprintf('%d \t %f \t %f \t %f \t %f \t %f \t %f \t \n', k,x,y,k1,k2,k3,k4);
end
fprintf('yn= %f \n',RK4("fedo",a,b,y0,m));
fprintf('Eroarea comisa este de ordinul lui %d \n',h^2);
and i need to create a graph but i dont know what to plot
help?

First, there is an undefined RK4 function in your fprintf statements that doesn't allow us to see the full printed output you desired, but your other code runs, and it looks like the last line is just printing the error estimate. Let's look at the output that does display:
k x y (RK4) k1 k2 k3 k4
0 0.000000 1.000000
1 0.100000 1.200000 0.200000 0.119750 0.111725 0.110923
2 0.200000 1.439000 0.239000 0.142900 0.133290 0.132329
3 0.300000 1.722800 0.283800 0.170030 0.158653 0.157515
4 0.400000 2.058360 0.335560 0.201836 0.188464 0.187126
5 0.500000 2.454032 0.395672 0.239153 0.223501 0.221936
6 0.600000 2.919838 0.465806 0.282984 0.264702 0.262873
7 0.700000 3.467806 0.547968 0.334531 0.313187 0.311053
8 0.800000 4.112367 0.644561 0.395237 0.370304 0.367811
9 0.900000 4.870841 0.758473 0.466834 0.437670 0.434754
10 1.000000 5.764009 0.893168 0.551401 0.517224 0.513806
11 1.100000 6.816811 1.052802 0.651431 0.611294 0.607280
12 1.200000 8.059173 1.242362 0.769917 0.722673 0.717948
13 1.300000 9.527007 1.467835 0.910451 0.854712 0.849139
14 1.400000 11.263409 1.736401 1.077341 1.011435 1.004844
15 1.500000 13.320091 2.056682 1.275759 1.197667 1.189858
16 1.600000 15.759109 2.439018 1.511911 1.419200 1.409929
17 1.700000 18.654931 2.895822 1.793243 1.682985 1.671959
18 1.800000 22.096917 3.441986 2.128692 1.997362 1.984229
19 1.900000 26.192300 4.095383 2.528980 2.372340 2.356676
20 2.000000 31.069760 4.877460 3.006976 2.819928 2.801223
There is a lot here that you could plot. But there's a small problem here, which is that all of that data is not saved in any variables. It's just printed to the screen and then overwritten on the next iteration of your RK loop. For example, after the program runs your workspace contains the following variables:
>> whos
Variables visible from the current scope:
variables in scope: top scope
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x1 8 double
b 1x1 8 double
dy 1x1 0 function_handle
f 1x1 0 function_handle
h 1x1 8 double
k 1x1 8 double
k1 1x1 8 double
k2 1x1 8 double
k3 1x1 8 double
k4 1x1 8 double
m 1x1 8 double
x 1x1 8 double
y 1x1 8 double
y0 1x1 8 double
>> k1
k1 = 4.8775
where all of the variables only retain the last value, k1 shown as an example.
If you want to plot the information, you need to retain the information to plot. if I manually copied/pasted your data into the terminal to define a data variable (ignoring the first partial line):
>> data = [1 0.100000 1.200000 0.200000 0.119750 0.111725 0.110923
2 0.200000 1.439000 0.239000 0.142900 0.133290 0.132329
3 0.300000 1.722800 0.283800 0.170030 0.158653 0.157515
4 0.400000 2.058360 0.335560 0.201836 0.188464 0.187126
5 0.500000 2.454032 0.395672 0.239153 0.223501 0.221936
6 0.600000 2.919838 0.465806 0.282984 0.264702 0.262873
7 0.700000 3.467806 0.547968 0.334531 0.313187 0.311053
8 0.800000 4.112367 0.644561 0.395237 0.370304 0.367811
9 0.900000 4.870841 0.758473 0.466834 0.437670 0.434754
10 1.000000 5.764009 0.893168 0.551401 0.517224 0.513806
11 1.100000 6.816811 1.052802 0.651431 0.611294 0.607280
12 1.200000 8.059173 1.242362 0.769917 0.722673 0.717948
13 1.300000 9.527007 1.467835 0.910451 0.854712 0.849139
14 1.400000 11.263409 1.736401 1.077341 1.011435 1.004844
15 1.500000 13.320091 2.056682 1.275759 1.197667 1.189858
16 1.600000 15.759109 2.439018 1.511911 1.419200 1.409929
17 1.700000 18.654931 2.895822 1.793243 1.682985 1.671959
18 1.800000 22.096917 3.441986 2.128692 1.997362 1.984229
19 1.900000 26.192300 4.095383 2.528980 2.372340 2.356676
20 2.000000 31.069760 4.877460 3.006976 2.819928 2.801223];
Then I can plot all sorts of things, like y vs k, or y vs x, etc:
plot (data(:,1), data(:,3)); title ("y vs k");
figure
plot (data(:,2), data(:,3)); title ("y vs x");
So the big question is how to retain your data so you aren't reliant on copy/paste.
Octave and Matlab variables are arrays. In your case, the variables you store your data in are single element, 1x1 arrays, and you overwrite them every iteration. An alternative approach is to use a vector for each variable (just as your printed output appears), and to store values from each iteration in a different vector location, indexed by k.
I notice that some of your variables you print are actually not the variables you use for each step. E.g., for k = 1, you print x = 0.1 but all of those values are calculated with k= 0 and x = 0. You then increment x and k right before printing. So some of those details might need to be tweaked to get what you want to match with what follows:
Since you're using x to define your steps, you probably want to expand that to an array first:
>> x=[a:h:b-h];
>> x'
x =
0
0.1000
0.2000
0.3000
0.4000
0.5000
0.6000
0.7000
0.8000
0.9000
1.0000
1.1000
1.2000
1.3000
1.4000
1.5000
1.6000
1.7000
1.8000
1.9000
(Note the vector is normally a row vector, I used a ' (transpose operator) to makes it display as a column vector here. I do the same at the end for storing results.)
The following rewritten RK loop produces an output much like your previous output:
x=[a:h:b];
for k = 1:length(x)-1
k1(k+1) = dy(x(k),y(k))*h;
k2(k+1) = dy((x(k)+h)/2,(y(k)+k1(k+1))/2)*h;
k3(k+1) = dy((x(k)+h)/2,(y(k)+k2(k+1))/2)*h;
k4(k+1) = dy((x(k)+h)/2,(y(k)+k3(k+1))/2)*h;
y(k+1) = y(k) + dy(x(k),y(k))*h;
end
data = [x',y',k1',k2',k3',k4']
data =
0 1.0000 0 0 0 0
0.1000 1.2000 0.2000 0.1198 0.1117 0.1109
0.2000 1.4390 0.2390 0.1429 0.1333 0.1323
0.3000 1.7228 0.2838 0.1700 0.1587 0.1575
0.4000 2.0584 0.3356 0.2018 0.1885 0.1871
0.5000 2.4540 0.3957 0.2392 0.2235 0.2219
0.6000 2.9198 0.4658 0.2830 0.2647 0.2629
0.7000 3.4678 0.5480 0.3345 0.3132 0.3111
0.8000 4.1124 0.6446 0.3952 0.3703 0.3678
0.9000 4.8708 0.7585 0.4668 0.4377 0.4348
1.0000 5.7640 0.8932 0.5514 0.5172 0.5138
1.1000 6.8168 1.0528 0.6514 0.6113 0.6073
1.2000 8.0592 1.2424 0.7699 0.7227 0.7179
1.3000 9.5270 1.4678 0.9105 0.8547 0.8491
1.4000 11.2634 1.7364 1.0773 1.0114 1.0048
1.5000 13.3201 2.0567 1.2758 1.1977 1.1899
1.6000 15.7591 2.4390 1.5119 1.4192 1.4099
1.7000 18.6549 2.8958 1.7932 1.6830 1.6720
1.8000 22.0969 3.4420 2.1287 1.9974 1.9842
1.9000 26.1923 4.0954 2.5290 2.3723 2.3567
2.0000 31.0698 4.8775 3.0070 2.8199 2.8012
(Also note octave and matlab start indexing at 1 not zero, hence all the k+1's)
Now that all of the data is stored and retained in the individual variable vectors or in the data array, you can make any plots you want. Recommend you check out the Octave manual section on plotting.

Related

Normalize each slice of a 3D matrix

How do I normalize each slice of a 3D matrix? I tried like this:
a=rand(1,100,3481);
a= (a - min(a)) ./ (max(a)-min(a)); %
By right each slice of matrix should ranges from 0 to 1. But that is not the case, I don't find 1 in some of the slices. As I inspected, min(a) and max(a) returned the respective value in 3D. Thus it should be of no issue using the code above. Is there something I missed for 3D matrix? Thanks in advance!
We need to find the minimum and maximum values for each of those 2D slices and then we can use bsxfun to do those operations in a vectorized manner with help from permute to let the singleton dims align properly to let bsxfun do its broadcasting job (or use reshape there).
Hence, the implementation would be -
mins = min(reshape(a,[],size(a,3)));
maxs = max(reshape(a,[],size(a,3)));
a_offsetted = bsxfun(#minus, a, permute(mins,[1,3,2]));
a_normalized = bsxfun(#rdivide, a_offsetted, permute(maxs-mins,[1,3,2]))
Sample input, output -
>> a
a(:,:,1) =
2 8 2 2
8 3 8 2
a(:,:,2) =
8 1 1 5
4 9 8 6
a(:,:,3) =
7 9 3 5
6 2 6 5
a(:,:,4) =
9 3 4 9
7 1 9 9
>> a_normalized
a_normalized(:,:,1) =
0 1.0000 0 0
1.0000 0.1667 1.0000 0
a_normalized(:,:,2) =
0.8750 0 0 0.5000
0.3750 1.0000 0.8750 0.6250
a_normalized(:,:,3) =
0.7143 1.0000 0.1429 0.4286
0.5714 0 0.5714 0.4286
a_normalized(:,:,4) =
1.0000 0.2500 0.3750 1.0000
0.7500 0 1.0000 1.0000
My option would be without reshaping as it is sometimes bit difficult to understand. I use min max with the dimension you want want to use for normalization with repmat to clone...:
a=rand(1,100,3481);
a_min2 = min(a,[],2);
a_max2 = max(a,[],2);
a_norm2 = (a - repmat(a_min2,[1 size(a,2) 1]) ) ./ repmat( (a_max2-a_min2),[1 size(a,2) 1]);
or if normalization on 3rd dim...
a_min3 = min(a,[],3);
a_max3 = max(a,[],3);
a_norm3 = (a - repmat(a_min3,[1 1 size(a,3)]) ) ./ repmat( (a_max3-a_min3),[1 1 size(a,3)]);

getting x,y coordinates from a plotted graph and get the intersection with an other graph

I'm some kind of new to matlab,so the question may be elementary. I try to get the [x,y] coordinates of the points on a plotted graph in matlab.
The graph is simple. I already had the coordinates of some points (xb,yb), and plotted the graph using line(xb, yb).
Now I need to find the coordinates of all the points on the plotted lines in order to get the intersection points of these lines with another defined graph.
the code which i used is:
line(Xb,Yb)
hold on
X=min(Xb):.001:max(Xb);
y=0.03;
plot(X,y);
The Xb and Yb are 1*38 arrays, and shape the boundary of a region in real problem which I'm studying. But I don't have all the x, Y of the points on the boundary. I need to the intersection coordinates of the boundary with horizontal line which is plotted by plot(X,y).
The Xb and Yb are:
Xb = [-0.0400 -0.0550 -0.0700 -0.0850 -0.1000 -0.1000 -0.1000 -0.1000 -0.1000 -0.1000 -0.0800 -0.0600 -0.0400 -0.0200 0 0.0200 0.0400 0.0600 0.0800 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.0850 0.0700 0.0550 0.0400 0.0380 0.0324 0.0235 0.0124 0 -0.0124 -0.0235 -0.0324 -0.0380 -0.0400 ];'
Yb = [0 0 0 0 0 0.0200 0.0400 0.0600 0.0800 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.1000 0.0800 0.0600 0.0400 0.0200 0 0 0 0 0 0.0124 0.0235 0.0324 0.0380 0.0400 0.0380 0.0324 0.0235 0.0124 0];'
thank you very much from your kind help.
If your functions are given as arrays x1,y1 and x2,y2, then you can find their crossing using their linear interpolators:
%dummy input
x1=[0 1 2 3];
y1=[1 4 2 0];
x2=[-1 3 4 5];
y2=[-1 2 5 3];
x0 = (max(min(x1),min(x2))+min(max(x1),max(x2)))/2;
fun1 = #(x) interp1(x1,y1,x,'linear');
fun2 = #(x) interp1(x2,y2,x,'linear');
difffun = #(x) fun1(x)-fun2(x);
crossing = fzero(difffun,x0);
where your x0 should be fairly close to the actual crossing point, I chose a point inside both of your intervals. The anonymous functions fun1 and fun2 create a callable function using interp1, which can only tell you the interpolant at specific x coordinates. If you have the Curve Fitting Toolbox, you can get a function in a single step using fit. Then difffun is a function given by the difference of the two input functions, the zero(s) of which will give you the crossing of the two functions. fzero will do just that: find a zero of a function from a given starting point.
You can run into troubles if the starting x0 is way off, and in case of multiple zeros you will only find one at a time. In your case, the interpolating functions are not too well-behaved, so choosing a right x0 (probably manually setting a value) is paramount.
Results with the dummy input above:
output:
crossing =
2.272727272727273

Generating a grid in matlab with a general number of dimensions

Problem
I have a vector w containing n elements. I do not know n in advance.
I want to generate an n-dimensional grid g whose values range from grid_min to grid_max and obtain the "dimension-wise" product of w and g.
How can I do this for an arbitrary n?
Examples
For simplicity, let's say that grid_min = 0 and grid_max = 5.
Case: n=1
>> w = [0.75];
>> g = 0:5
ans =
0 1 2 3 4 5
>> w * g
ans =
0 0.7500 1.5000 2.2500 3.0000 3.7500
Case: n=2
>> w = [0.1, 0.2];
>> [g1, g2] = meshgrid(0:5, 0:5)
g1 =
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
g2 =
0 0 0 0 0 0
1 1 1 1 1 1
2 2 2 2 2 2
3 3 3 3 3 3
4 4 4 4 4 4
5 5 5 5 5 5
>> w(1) * g1 + w(2) * g2
ans =
0 0.1000 0.2000 0.3000 0.4000 0.5000
0.2000 0.3000 0.4000 0.5000 0.6000 0.7000
0.4000 0.5000 0.6000 0.7000 0.8000 0.9000
0.6000 0.7000 0.8000 0.9000 1.0000 1.1000
0.8000 0.9000 1.0000 1.1000 1.2000 1.3000
1.0000 1.1000 1.2000 1.3000 1.4000 1.5000
Now suppose a user passes in the vector w and we do not know how many elements (n) it contains. How can I create the grid and obtain the product?
%// Data:
grid_min = 0;
grid_max = 5;
w = [.1 .2 .3];
%// Let's go:
n = numel(w);
gg = cell(1,n);
[gg{:}] = ndgrid(grid_min:grid_max);
gg = cat(n+1, gg{:});
result = sum(bsxfun(#times, gg, shiftdim(w(:), -n)), n+1);
How this works:
The grid (variable gg) is generated with ndgrid, using as output a comma-separated list of n elements obtained from a cell array. The resulting n-dimensional arrays (gg{1}, gg{2} etc) are contatenated along the n+1-th dimension (using cat), which turns gg into an n+1-dimensional array. The vector w is reshaped into the n+1-th dimension (shiftdim), multiplied by gg using bsxfun, and the results are summed along the n+1-th dimension.
Edit:
Following #Divakar's insightful comment, the last line can be replaced by
sz_gg = size(gg);
result = zeros(sz_gg(1:end-1));
result(:) = reshape(gg,[],numel(w))*w(:);
which results in a significant speedup, because Matlab is even better at matrix multiplication than at bsxfun (see for example here and here).

inserting +- (i.e. \pm) between two numbers in matlab

I want to insert the symbol +- (\pm) between x and y in table created in matlab
x = (1:1:5)';
y = x*5/100;
table = [x y]
So, that the output is
1.0000 +/- 0.0500
2.0000 +/- 0.1000
3.0000 +/- 0.1500
4.0000 +/- 0.2000
5.0000 +/- 0.2500
If we can also write the minus exactly below plus.
You can use unicode characters in MATLAB. The following works:
>> fprintf('%f ± %f\n', table.')
1.000000 ± 0.050000
2.000000 ± 0.100000
3.000000 ± 0.150000
4.000000 ± 0.200000
5.000000 ± 0.250000
Note that fprintf cycles through all the elements of the input matrix in storage order (down the first column first). So it was necessary to transpose the data array (table.') to print it in one command.
This works for printing to file as well on MacOS:
f = fopen('mytextfile.txt','wt');
fprintf(f,'%f ± %f\n', table.');
fclose(f);
With output as a text file use the format spec for fprintf such as
FileID=fopen('FileName.txt','w');
fprintf(FileID,['%1.4f ',177,' %1.4f\n'],[x';y'])
fprintf(['%0.2f ' char(177) ' %0.2f\n'], [x;y]);

using matlab surf functions with x size 11 and y size 6

I am trying to use matlab for calculating the approximation of a function using the composite trapezoidal rule, and then displaying the function and approximation using a surf function and a bar3 function. the thing is is that when I try plot the function surf(x,y,Z) I receive and error saying dimension's mismatch.
my question is how would I get the surf function to plot the 3D graph when my x,y and z arrays differ in size.
I've tried to create zeros functions of the the x and y array's of the same size and then adding my values to each, then NaN'ing the extra 0's, but as u see each of my arrays start with 0's therefore NaN'ing where i find a zero in my arrays will effect my graph plot. and plus i still get the same error "dimensions mismatch" so i supposed thats because my Z array is bigger than my x and y.
Any help would be appreciated.
code for my x and y are:
`
x = linspace(a,b,h); %h being 11 and breaks up the difference because datapoints a and b into h number of sub intervals
y = linspace(c,d,k); %k being 6 and breaks up the difference because data points c and d into k number of sub intervals
Z = zeros(h,k);
for i = 1:1:h
for j = 1:1:k
Z(i,j) = f(x(i),y(j));
end
end
surf(x,y,Z);
`
x
0 0.3000 0.6000 0.9000 1.2000 1.5000 1.8000 2.1000 2.4000 2.7000 3.0000
y
0 0.6286 1.2571 1.8857 2.5143 3.1429
Z
0 0 0 0 0 0
0 0.1764 0.2854 0.2852 0.1761 -0.0004
0 0.3528 0.5707 0.5705 0.3522 -0.0008
0 0.5292 0.8561 0.8557 0.5283 -0.0011
0 0.7056 1.1415 1.1410 0.7044 -0.0015
0 0.8820 1.4268 1.4262 0.8804 -0.0019
0 1.0584 1.7122 1.7115 1.0565 -0.0023
0 1.2348 1.9975 1.9967 1.2326 -0.0027
0 1.4112 2.2829 2.2820 1.4087 -0.0030
0 1.5876 2.5683 2.5672 1.5848 -0.0034
0 1.7640 2.8536 2.8525 1.7609 -0.0038
Error using surf (line 75)
Data dimensions must agree.
Error in CompositeTrapazoidal>btnSolve_Callback (line 167)
surf(x,y,Z);
Try surf(x,y,Z'); (because x's length should match the Z's column count)