Calculate tangent for measurement data - matlab

I have some measurement data which I want to plot. I plot only the points and used the Curve Fitting Toolbox to generate a regression function which I plot.
Now I want to calculate and plot the tangent on a certain point. How can I do that using Matlab?

If you have point and function, you can calculate the tangent which is:
let say the desired index is 5. y = mx+n
m = (diff(y) ./ diff(y)) (5)
n = y(5)-x(5)*m
and then
hold on
plot (x, (m*x+n));
links:
http://www.kxcad.net/cae_MATLAB/toolbox/curvefit/bqxox7w.html
http://www.weizmann.ac.il/matlab/toolbox/curvefit/cfit.html
http://www.mathworks.com/matlabcentral/newsreader/view_thread/170100

With the help of #0x90 I got the solution:
zerocross = ceil(fzero(fit, 1000));
x_tan = zerocross-101:0.1:zerocross+100;
y_tan = feval(fit, x_tan);
k = (diff(y_tan) ./ diff(x_tan));
k = k(length(k) / 2); % get zero point
d = y_tan(5)-x_tan(5)*k;
plot (x_tan, (k*x_tan+d));

Related

Rescale curve so that it is at constant distance from original one

A question I strangely could not find on the internet. Given a complicated curve C (i.e. a curve that you can't fit with polynomials) defined by N points and centered around x0=0.5,0 (blue curve in figure), how can I rescale the curve so that the center is the same and the new curve is located at a constant distance d from the curve C (e.g. green curve in figure)?
So far the only way I could find is using the MATLAB function bwdist (https://fr.mathworks.com/help/images/ref/bwdist.html) which computes the Euclidean distance map of a binary image (see code below). However, I'm constrained by the size of my matrix i.e. a curve of 1e5 points is fine but a matrix of size (1e5,1e5) is big for bwdist...so the results using a coarse matrix is an ugly step-wise function. The code is
%%% profile
x = linspace(0,1,1e5);
y = -(x-0.5).^2/0.5^2 + 1 - 0.5*(exp(-(x-0.5).^2/2/0.2^2) - exp(-(-0.5).^2/2/0.2^2));
%%% define mask on a region that encompasses the curve
N=512;
mask = ones(N,N);
xm = linspace(0.9*min(x),1.1*max(x),N);
ym = linspace(0.9*min(y),1.1*max(y),N);
[Xm,Ym] = meshgrid(xm,ym);
%%% project curve on mask (i.e. put 0 below curve)
% get point of mask closer to each point of y
DT = delaunayTriangulation(Xm(:),Ym(:));
vi = nearestNeighbor(DT,x',y');
[iv,jv] = ind2sub(size(mask),vi);
% put 1 to indices of mask that are below projected curve
for p=1:length(iv)
mask(1:iv(p)-1,jv(p)) = 0;
end
%%% get euclidean distance
Ed = bwdist(logical(mask));
Ed = double(Ed);
%%% get contours of Ed at given values (i.e. distances)
cont = contour(Ed,linspace(0,1,50));
% cont has the various curves at given distances from original curve y
I add that I first tried moving a point of curve C for a distance d using the normal of the tangent but since the curve is non-linear, this direction is actually not necessarily the one giving the appropriate point. So at some distance, the curve becomes discontinuous because using the tangent does not give the point at a given distance from the curve, only from the considered point on curve C.
The code is
% profil
x = linspace(0,1,1e5);
y = -(x-0.5).^2/0.5^2 + 1 - 0.5*(exp(-(x-0.5).^2/2/0.2^2) - exp(-(-0.5).^2/2/0.2^2));
% create lines at Dist from original line
Dist = linspace(0,2e-1,6);
Dist = Dist(2:end);
Cdist(1).x = x;
Cdist(1).y = y;
Cdist(1).v = 0;
step = 10; % every step points compute normal to point and move points
points = [1:1:length(y)];
for d=1:length(Dist)
xd = x;
yd = y;
for p=1:length(points)
if points(p)==1
tang = [-(y(2)-y(1)) (x(2)-x(1))];
tang = tang/norm(tang);
xd(1) = xd(1) - Dist(d)*tang(1);
yd(1) = yd(1) - Dist(d)*tang(2);
elseif points(p)==length(y)
tang = [-(y(end)-y(end-1)) (x(end)-x(end-1))];
tang = tang/norm(tang);
xd(end) = xd(end) - Dist(d)*tang(1);
yd(end) = yd(end) - Dist(d)*tang(2);
else
tang = [-(y(p+1)-y(p-1)) (x(p+1)-x(p-1))];
tang = tang/norm(tang);
xd(p) = xd(p) - Dist(d)*tang(1);
yd(p) = yd(p) - Dist(d)*tang(2);
end
end
yd(yd<0)=NaN;
Cdist(d+1).x = xd;
Cdist(d+1).y = yd;
Cdist(d+1).v = Dist(d);
end
% plot
cmap=lines(10);
hold on
for c=1:length(Cdist)
plot(Cdist(c).x,Cdist(c).y,'linewidth',2,'color',cmap(c,:))
end
axis tight
axis equal
axis tight
Any idea ?
What you want to do is not possible.
Scaling a curve with respect to a center point while remaining equal distance to the original curve means that all the points on this curve are moving along its normal direction towards the center of scaling, and will eventually, reduce to a point.
Imagine drawing the normal direction of each point on this curve, and extend them to infinity. All these lines should pass through a same point, which is the center of scaling. Unfortunately, this is not the case for your curve.

Cross validation and ROC curve using Matlab: how plot mean ROC curve?

I am using k-fold cross validation with k = 10. Thus, I have 10 ROC curves.
I would like to average between the curves. I can't just average the values ​​on the Y axes (using perfcurve) because the vectors returned are not the same size.
[X1,Y1,T1,AUC1] = perfcurve(t_test(1),resp(1),1);
.
.
.
[X10,Y10,T10,AUC10] = perfcurve(t_test(10),resp(10),1);
How to solve this? How can I plot the average curve of the 10 ROC curves?
So, you have k curves with different number of points, all bound in [0..1] interval in both dimensions. First, you need to calculate interpolated values for each curve at specified query points. Now you have new curves with fixed number of points and can compute their mean. The interp1 function will do the interpolation part.
%% generating sample data
k = 10;
X = cell(k, 1);
Y = cell(k, 1);
hold on;
for i=1:k
n = 10+randi(10);
X{i} = sort([0 1 rand(1, n)]);
Y{i} = sort([0 1 rand(1, n)].^.5);
end
%% Calculating interpolations
% location of query points
X2 = linspace(0, 1, 50);
n = numel(X2);
% initializing values for different curves at different query points
Y2 = zeros(k, n);
for i=1:k
% finding interpolated values for i-th curve
Y2(i, :) = interp1(X{i}, Y{i}, X2);
end
% finding the mean
meanY = mean(Y2, 1);
Notice that different interpolation methods can affect your results. For example, the ROC plot data are kind of stairs data. To find the exact values on such curves, you should use the Previous Neighbor Interpolation method, instead of the Linear Interpolation which is the default method of interp1:
Y2(i, :) = interp1(X{i}, Y{i}, X2); % linear
Y3(i, :) = interp1(X{i}, Y{i}, X2, 'previous');
This is how it affects the final results:
I solved it using Matlab's perfcurve. For that, I had to pass as a parameter a list of vectors (size vectors 1xn) for "label" and "scores". Thus, the perfcurve function already understands as a set of resolutions made using k-fold and returns the average ROC curve and its confidence interval, in addition to the AUC and its confidence interval.
[X1,Y1,T1,AUC1] = perfcurve(t_test_list,resp_list,1);
t_test and resp they are lists of size 1xk (k is the number of folds / k-fold) and each element of the lists is a 1xn vector with scores and labels.
resp = nnet(x_test(i));
t_test_act = t_test(i);
resp has 2xn format (n is the number of predicted samples). There are two classes.
t_test_act contains the labels of the current set of tests, it has formed 2xn and is composed of 0 and 1 (each column has a 1 and a 0, indicating the true class of the sample).
resp_list{i} = resp(1,:) %(scores)
t_test_list{i} = t_test_act(1,:) %(labels)
[X1,Y1,T1,AUC1] = perfcurve(t_test_list,resp_list,1);

Potential flow, define theta in matlab

I have made this matlab script for a potential flow around a cylinder and I would like to add a point source. See the definition of point source in picture. How can you define theta in matlab? And plot this its streamlines Psi?
clear
% make axes
xymax = 2;
x = linspace(-xymax,xymax,100);
y = linspace(-xymax,xymax,100);
% note that x and y don't include 0
[xmesh,ymesh] = meshgrid(x,y);
x_c=0;
y_c=0;
q=1;
U=1
r = sqrt((xmesh-x_c).^2+(ymesh-y_c).^2);
sin_th= ((ymesh-y_c)./r)
%(ymesh-y_c)./r = sin(teta)
%(xmesh-x_c)./r = cos(teta)
psi1 = -q./r.*((ymesh-y_c)./r);
psi2 = r.*sin_th;
psi=psi1+psi2;
figure
contour(xmesh,ymesh,psi,[-xymax:.25:xymax],'-b');
To plot the streamlines in potential flow you are correct that you have to plot contour lines of constant stream function.
In the case of a point source, if you are plotting in cartesian coordinates in MATLAB you have to convert theta to cartesian coordinates using arctangent as follows: theta = arctan(y/x). In MATLAB use the function atan2 which will limit the number of discontinuities to between -PI and PI: https://www.mathworks.com/help/matlab/ref/atan2.html
Your code should read: psi2 = ( m/(2*PI) ) * atan2(y,x)
For more information on plotting elements of potential flow in 2D cartesian coordinates, see more information here:
https://potentialflow.com/flow-elements
https://potentialflow.com/equations

creatig random gaussians on an image

I am trying to create some Gaussian distributions and put them on an image. The Gaussians have randomly created parameter (amplitude, position and standard deviation). First I put the parameters into vectors or matrices, then I am using ngrid() function to get a 2d space to create the Gaussians, however i get an error (since possibly mathematical operations with ngrid values is not trivial...). The error is:
??? Error using ==> minus
Integers can only be combined
with integers of the same class,
or scalar doubles.
Error in ==> ss_gauss_fit at 23
gauss = amp(i)*
exp(-((x-xc).^2 +
(y-yc).^2)./(2*std(i)));
the code is here:
clear all;
image = uint8(zeros([300 300]));
imsize=size(image);
noOfGauss=10;
maxAmpGauss=160;
stdMax=15;
stdMin=3;
for i=1:noOfGauss
posn(:,:,i)=[ uint8(imsize(1)*rand()) uint8(imsize(2)*rand()) ];
std(i)=stdMin+uint8((stdMax-stdMin)*rand());
amp(i)= uint8(rand()* maxAmpGauss);
end
% draw the gaussians on blank image
for i=1:noOfGauss
[x,y] = ndgrid(1:imsize(1), 1:imsize(2));
xc = posn(1,1,i);
yc = posn(1,2,i);
gauss = amp(i)* exp(-((x-xc).^2 + (y-yc).^2)./(2*std(i)));
image = image + gauss;
end
Please tell me how fix this, plot 2d Gaussians with parameter vectors...
Thanks in advance
Apart from the craziness about "drawing on an image", which I don't really understand, I think you are trying to add up a bunch of separate gaussian distributions on a grid. Here's what I did with your code. Note that your bivariate gaussians are not normalized properly and you were using the variance and not standard deviation before. I fixed the latter; however, I didn't bother with the normalization because you are multiplying each by an amplitude value anyway.
clear all;
xmax = 50;
ymax = 50;
noOfGauss=10;
maxAmpGauss=160;
stdMax=10;
stdMin=3;
posn = zeros(noOfGauss, 2);
std = zeros(noOfGauss, 1);
amp = zeros(noOfGauss, 1);
for i=1:noOfGauss
posn(i,:)=[ xmax*rand() ymax*rand() ];
std(i)=stdMin+(stdMax-stdMin)*rand();
amp(i)= rand()* maxAmpGauss;
end
% draw the gaussians
[x,y] = ndgrid(1:xmax, 1:ymax);
z = zeros(xmax, ymax);
for i=1:noOfGauss
xc = posn(i,1);
yc = posn(i,2);
z = z + amp(i)* exp(-((x-xc).^2 + (y-yc).^2)./(2*std(i)^2));
end
surf(x, y, z);
Random output:

Calculate distance, given a set of coordinates

my question is quite trivial, but I'm looking for the vectorized form of it.
My code is:
HubHt = 110; % Hub Height
GridWidth = 150; % Grid length along Y axis
GridHeight = 150; % Grid length along Z axis
RotorDiameter = min(GridWidth,GridHeight); % Turbine Diameter
Ny = 31;
Nz = 45;
%% GRID DEFINITION
dy = GridWidth/(Ny-1);
dz = GridHeight/(Nz-1);
if isequal(mod(Ny,2),0)
iky = [(-Ny/2:-1) (1:Ny/2)];
else
iky = -floor(Ny/2):ceil(Ny/2-1);
end
if isequal(mod(Nz,2),0)
ikz = [(-Nz/2:-1) (1:Nz/2)];
else
ikz = -floor(Nz/2):ceil(Nz/2-1);
end
[Y Z] = ndgrid(iky*dy,ikz*dz + HubHt);
EDIT
Currently I am using this solution, which has reasonable performances:
coord(:,1) = reshape(Y,[numel(Y),1]);
coord(:,2) = reshape(Z,[numel(Z),1]);
dist_y = bsxfun(#minus,coord(:,1),coord(:,1)');
dist_z = bsxfun(#minus,coord(:,2),coord(:,2)');
dist = sqrt(dist_y.^2 + dist_z.^2);
I disagree with Dan and Tal.
I believe you should use pdist rather than pdist2.
D = pdist( [Y(:) Z(:)] ); % a compact form
D = squareform( D ); % square m*n x m*n distances.
I agree with Tal Darom, pdist2 is exactly the function you need. It finds the distance for each pair of coordinates specified in two vectors and NOT the distance between two matrices.
So I'm pretty sure in your case you want this:
pdist2([Y(:), Z(:)], [Y(:), Z(:)])
The matrix [Y(:), Z(:)] is a list of every possible coordinate combination over the 2D space defined by Y-Z. If you want a matrix containing the distance from each point to each other point then you must call pdist2 on this matrix with itself. The result is a 2D matrix with dimensions numel(Y) x numel(Y) and although you haven't defined it I'm pretty sure that both Y and Z are n*m matrices meaning numel(Y) == n*m
EDIT:
A more correct solution suggested by #Shai is just to use pdist since we are comparing points within the same matrix:
pdist([Y(:), Z(:)])
You can use the matlab function pdist2 (I think it is in the statistics toolbox) or you can search online for open source good implementations of this function.
Also,
look at this unswer: pdist2 equivalent in MATLAB version 7