As shown by the solid and dashed line, I'd like to create a function where I set a threshold for y (Intensity) from that threshold it gives me corresponding x value (dashed line). Very simple but my while statement is off. Any help would be much appreciated!
%% Curve fit plotting %%
x1 = timeStamps(1:60); % taking timestamps from 1 - 120 given smoothed y1 values
y1 = smooth(tic_lin(1:60),'sgolay',1);
% Find coefficients for polynomial (order = 4 and 6, respectively)
fitResults1 = polyfit(x1',y1, 7);
% evaluate the fitted y-values
yplot1 = polyval(fitResults1,x1');
% interpolates to find yi, the values of the underlying function Y at the points in the vector or array xi. x must be a vector.
Time_points = interp1(yplot1, x1', yplot1);
figure( 'Name', 'Curvefit1_poly' );
h = plot(x1', y1);%smoothed-points
hold on;
plot(x1', yplot1);%polyfit points
hold on;
plot(Time_points, yplot1, '*r');%interpolated points of x given y
%given y-threshold, output x(corresponding time_point).
broken = false;
while broken == false
if yplot1 >= 2024671226502.99
index = find(yplot1);
xDesired = x1(index);
broken = true;
else
disp("next iteration through");
end
end
No while loop is needed here... You can do this with logical indexing for the threshold condition and find to get the first index:
% Start with some x and y data
% x = ...
% y = ...
% Get the first index where 'y' is greater than some threshold
thresh = 10;
idx = find( y >= thresh, 1 ); % Find 1st index where y >= thresh
% Get the x value at this index
xDesired = x( idx );
Note that xDesired will be empty if there was no y value over the threshold.
Alternatively, you already have a polynomial fit, so you could use fzero to get the x value on that polynomial for a given y (in this case your threshold).
% x = ...
% y = ...
thresh = 10;
p = polyfit( x, y, 3 ); % create polynomial fit
% Use fzero to get the root of y = a*x^n + b*x^(n-1) + ... + z when y = thresh
xDesired = fzero( #(x) polyval(p,x) - thresh, x(1) )
Note, this method may give unexpected results if the threshold is not within the range of y.
Related
I have the following function :
ySol2=(2*(x^3 + 1)^(1/2))/cos(x) +2/cos(x)
my question is how can I draw it in the interval 1000;5000 with the constrains cos(x) != 0 and x> -1?
Something like this perhaps?
% your function. Note element-wise operations (.^, ./)
ySol2 = #(x) (2*(x.^3 + 1).^(1/2))./cos(x) +2./cos(x);
% your x interval, with step 0.1. Note also that the argument for 'cos' is in [rad].
x = 1000:0.1:5000;
% calculate function values
y = ySol2(x);
% keep only non-constrained values
ind = (cos(x)~=0) | (x>-1);
x = x(ind);
y = y(ind);
% plot
figure;
plot(x,y);
Given the following:
Time series with x (time [s]) and y (here discharge [m³/s])
Value V1 (same units integrated y), smaller than the integral over all of x. In this case a small volume [m³].
I would like to calculate:
The y value y_V1 such that the integral between the line y = y_V1 and the curve y equals V1.
The following plot shows this, the orange region is V1, I want the circled value on the y axis:
The V1 must be placed around the peak.
I think this must be an iterative process, where also a the fitting criteria (and the degree of exactness) must be set by the user.
Until now, I haven't found a way to start; besides the pure integration.
The idea is to specify an area. The y value left and right of the peak which envelops this area should be calculated.
Edit
This is the result, if the accepted answer is applied.
You can do this by decreasing some y value until your area target is met. See the comments below for details.
% Input data
x = 0:0.01:pi;
y = sin(x);
target = 1; % Target area
yi = max( y ); % Initialise yi to be max possible y
dy = 0.001; % Step change in yi
Ai = 0; % Area each iteration
thresh = 0; % Threshold for stopping loop
while target - Ai > thresh && yi >= min(y)
yi = yi - dy;
ix = y >= yi;
% Approximate integral above the line
Ai = trapz( x(ix), y(ix) - yi );
end
% Plot
figure(1); clf; hold on
plot( x, y );
patch( x(ix), y(ix), [1,0.5,0.5], 'facealpha', 0.5 );
plot( x, ones(size(x))*yi, '--', 'linewidth', 2 )
xlim( [min(x),max(x)] )
Output:
I have written a 2D histogram algorithm for 2 matlab vectors. Unfortunately, I cannot figure out how to vectorize it, and it is about an order of magnitude too slow for my needs. Here is what I have:
function [ result ] = Hist2D( vec0, vec1 )
%Hist2D takes two vectors, and computes the two dimensional histogram
% of those images. It assumes vectors are non-negative, and bins
% are the integers.
%
% OUTPUTS
% result -
% size(result) = 1 + [max(vec0) max(vec1)]
% result(i,j) = number of pixels that have value
% i-1 in vec0 and value j-1 in vec1.
result = zeros(max(vec0)+1, max(vec1)+1);
fvec0 = floor(vec1)+1;
fvec1 = floor(vec0)+1;
% UGH, This is gross, there has to be a better way...
for i = 1 : size(fvec0);
result(fvec0(i), fvec1(i)) = 1 + result(fvec0(i), fvec1(i));
end
end
Thoughts?
Thanks!!
John
Here is my version for a 2D histogram:
%# some random data
X = randn(2500,1);
Y = randn(2500,1)*2;
%# bin centers (integers)
xbins = floor(min(X)):1:ceil(max(X));
ybins = floor(min(Y)):1:ceil(max(Y));
xNumBins = numel(xbins); yNumBins = numel(ybins);
%# map X/Y values to bin indices
Xi = round( interp1(xbins, 1:xNumBins, X, 'linear', 'extrap') );
Yi = round( interp1(ybins, 1:yNumBins, Y, 'linear', 'extrap') );
%# limit indices to the range [1,numBins]
Xi = max( min(Xi,xNumBins), 1);
Yi = max( min(Yi,yNumBins), 1);
%# count number of elements in each bin
H = accumarray([Yi(:) Xi(:)], 1, [yNumBins xNumBins]);
%# plot 2D histogram
imagesc(xbins, ybins, H), axis on %# axis image
colormap hot; colorbar
hold on, plot(X, Y, 'b.', 'MarkerSize',1), hold off
Note that I removed the "non-negative" restriction, but kept integer bin centers (this could be easily changed into dividing range into equally-sized specified number of bins instead "fractions").
This was mainly inspired by #SteveEddins blog post.
You could do something like:
max0 = max(fvec0) + 1;
max1 = max(fvec1) + 1;
% Combine the vectors
combined = fvec0 + fvec1 * max0;
% Generate a 1D histogram
hist_1d = hist(combined, max0*max1);
% Convert back to a 2D histogram
hist_2d = reshape(hist, [max0 max1]);
(Note: untested)
I want to plot a function y[n] = x[n+2]. My problem is that it does not plot in right range or even does not draw the zero sample points.
n = 1:6;
x = 1:1:8;
f = figure;
subplot(1,2,1)
stem(n, x(n));
axis([-3,8, 0, 7]);
xlabel('n');
ylabel('x[n]');
title('Subplot 1')
subplot(1,2,2)
stem(n, x(n + 2));
xlabel('n');
ylabel('y[n]');
title('Subplot 2')
How to change the variables n or x to get the right plot?
In the end, it ought to look like this:
You are confusing the concept of indices with your dependent variable. You should construct a function x which transforms an input n using the relationship that you know
function y = x(n)
% Set all outputs to 0
y = zeros(size(n));
% Replace the values that fall between 0 and 6 with their same value
y(n >= 0 & n <= 6) = n(n >= 0 & n <= 6);
end
Then you should pass this function a range of n values to evaluate.
nvalues = -3:8;
yvalues = x(nvalues);
stem(nvalues, yvalues)
You can also apply a transformation to the n values
nvalues = -3:8;
yvalues = x(nvalues + 2);
stem(nvalues, yvalues)
I'm having issues unterstanding the function fill in MATLAB , I have a PSD of a file the I want to change it background like :
[xPSD,f] = pwelch(x,hanning(4096),2048,4096*2 ,fs);
plot(f,10*log10(xPSD));
x= f(100:150);
y= 10*log10(xPSD(100:150))
fill(x,y,'y')
the result is in the right direction but not what I need :
I would like get the color tell x axis like :
is their a way to do this
A working solution is:
[xPSD,f] = pwelch(x,hanning(4096),2048,4096*2 ,fs);
plot(f,10*log10(xPSD));
hold on
x= f(100:150);
y= 10*log10(xPSD(100:150));
yMax = ylim;
yMax = yMax(2);
x = x'; % Use this line only in the case that the size(x, 1) > 1
X = [x fliplr(x)];
Y = [y' ones(1, length(y)) .* yMax];
fill(X, Y, 'y')
What you were missing is that fill method looks for an area to fill. In the above code the area is defined by pairs of points. That, for the first (i.e. lower part) of the area we have the x vector and the y points. The second area (i.e. the upper part) is defined by the reversed vector x (image your pencil to first starting drawing towards rights for the lower part and then for the upper going left) and the points of the upper limit of your axes.
Edit:
Minimal example with the handel data from MATLAB:
load handel;
x = y; % Just to be consistent with the OP
fs = Fs; % Just to be consistent with the OP
[xPSD,f] = pwelch(x,hanning(4096),2048,4096*2 ,fs);
plot(f,10*log10(xPSD));
hold on
x= f(100:150);
y= 10*log10(xPSD(100:150));
yMax = ylim;
yMax = yMax(2);
x = x'; % Use this line only in the case that the size(x, 1) > 1
X = [x fliplr(x)];
Y = [y' ones(1, length(y)) .* yMax];
fill(X, Y, 'y')
xlim([0 200]) % To focus on the result
The result is:
Yes, there is always a way ;)
In your case, you simply need to add two points in x and y that go to the top boudary of the plot:
x = f(100:150);
y = 10*log10(xPSD(100:150))
% Add two points
Y = ylim;
x = [x(1) ; x(:) ; x(end)];
y = [Y(2) ; y(:) ; Y(2)];
% Display filled area
fill(x,y,'y')
Best,