Obtaining approximate derivatives with variable x spacing in MATLAB? [duplicate] - arrays

This question already has answers here:
Numerical derivative of a vector
(3 answers)
Closed 7 years ago.
I have two arrays: x and y. In practice, y is dependent on x, but both arrays are measured values. I would like to obtain the derivative of y with respect to x. If x were uniformly spaced (i.e. x=[1 2 3 4 5]), I could do something with diff like this:
h = 0.001;
x = -pi:h:pi;
f = sin(X);
y = diff(f)/h;
However, x is not uniformly spaced (i.e. x=[1 1.9 2.8 4.1]). How can I obtain the partial derivative of this data set?

A good way to do it is gradient,
dydx = gradient(y, x);
I like it because it returns a vector which is the same length as x and y. The downside though, is it's first order accurate. This can sometimes be a problem, a fix could be to write your own,
x = unique([linspace(0, 2*pi, 50), logspace(0, log10(2*pi), 50)]);
y = cos(x) ;
subplot(2,1,1) ;
plot(x, Gradient(y, x), x, gradient(y,x), x, -sin(x));
legend('2^{nd} order', '1^{st} order', 'exact') ;
subplot(2,1,2) ;
plot(x, Gradient(y, x) + sin(x), x, gradient(y,x) + sin(x));
legend('2^{nd} order - exact', '1^{st} order - exact')
With Gradient being
function dydx = Gradient(y,x)
y = y(:);
p = x(3:end) - x(2:end-1);
p = p(:);
m = x(2:end-1) - x(1:end-2);
m = m(:);
p1 = x(2) - x(1);
p2 = x(3) - x(1);
m1 = x(end) - x(end-1);
m2 = x(end) - x(end-2);
dydx = reshape([ ((-p1^2 + p2^2)*y(1) - p2^2*y(2) + p1^2*y(3))/(p1*(p1 - p2)*p2);
((-m.^2 + p.^2).*y(2:end-1) - p.^2.*y(1:end-2) + m.^2.*y(3:end))./(m.*p.*(m + p));
((m1^2 - m2^2)*y(end) + m2^2*y(end-1) - m1^2*y(end-2))/(m1^2*m2 - m1*m2^2) ...
], size(x));
end
Edit:
Improved it for multidimensional array and constant spacing support
function dydx = Gradient(y,x)
if length(y) < 3
dydx = gradient(y,x);
return
end
[~, n] = max(size(y));
N = ndims(y);
i = repmat({':'},1,N-1);
y = permute(y, [n, 1:n-1, n+1:N]);
if isscalar(x)
%"x" is actually a spacing value
p = x;
m = x;
p1 = x;
p2 = x;
m1 = x;
m2 = x;
else
if isvector(x)
x = repmat(x(:), size(y(1, i{:})));
else
x = permute(x, [n, 1:n-1, n+1:N]);
end
if all(size(x) ~= size(y))
error('Sizes of arrays must be the same.')
end
p = x(3:end, i{:}) - x(2:end-1, i{:});
m = x(2:end-1, i{:}) - x(1:end-2, i{:});
p1 = x(2, i{:}) - x(1, i{:});
p2 = x(3, i{:}) - x(1, i{:});
m1 = x(end, i{:}) - x(end-1, i{:});
m2 = x(end, i{:}) - x(end-2, i{:});
end
dydx = ipermute([ ((-p1.^2 + p2.^2).*y(1,i{:}) - p2.^2.*y(2,i{:}) + p1.^2.*y(3,i{:}))./(p1.*(p1 - p2).*p2);
((-m.^2 + p.^2).*y(2:end-1,i{:}) - p.^2.*y(1:end-2,i{:}) + m.^2.*y(3:end,i{:}))./(m.*p.*(m + p));
((m1.^2 - m2.^2).*y(end,i{:}) + m2.^2.*y(end-1,i{:}) - m1.^2.*y(end-2,i{:}))./(m1.^2.*m2 - m1.*m2.^2) ...
], [n, 1:n-1, n+1:N]);
end

Related

MATLAB array indexing and slicing

Im writing currently rewriting a Matlab script in C. When i get to the last few lines of the Matlab script a for loop is executed and it iterates through an array. Since i am trying to rewrite the program in C the slicing notation in the Matlab script is confusing me. I have attached the line of code that is troubling me below.
How would i write this line of code in a nested for loop indexing with i and j only, since you cant slice in c obviously. just for reference u = 1, Ubc is 2D array of size (NX+2, NY+2). Where NX = NY = 40.
Below is the line of code in Matlab i need to translate to for loop indexing.
Nx = 40;
Ny = 40;
u = 1;
Ubc = rand(Nx + 2, Ny + 2);
% First the i interfaces
F = 0.5* u *( Ubc(2:Nx+2,2:Ny+1) + Ubc(1:Nx+1,2:Ny+1))
- 0.5*abs(u)*( Ubc(2:Nx+2,2:Ny+1) - Ubc(1:Nx+1,2:Ny+1));
You can calculate the same in a loop as
Nx = 40;
Ny = 40;
u = 1;
Ubc = rand(Nx + 2, Ny + 2);
F = zeros(Nx + 1, Ny);
for z1 = 1 : Nx + 1
for z2 = 1 : Ny
F(z1, z2) = 0.5* u *( Ubc(z1 + 1, z2 + 1) + Ubc(z1, z2 + 1))
- 0.5*abs(u)*( Ubc(z1 + 1, z2 + 1) - Ubc(z1, z2 + 1));
end
end
You shouldn't use i and j as loop index in Matlab. Both are the imaginary unit.

Calling a function containing an array of x values

I want to call a function in a program, that has the same format as the following, but where the x values are in the form of an array of shape = (426, 240). Can someone help with this?
The function is:
def f(x):
if x < 0:
return -2*x
else :
return -x
x = np.arange(-100, 100, 1)
plt.plot(x, list(map(f, x)), 'b-') # for python3
#plt.show()
The part of the code that calls the function would look like this:
def nucleation_and_motion_in_G_gradient_fluid_2D(writer, args, R=60):
dx = 2*R / args.height
x = (np.arange(args.width) - args.width // 2) * dx
y = (np.arange(args.height) - args.height // 2) * dx
x, y = np.meshgrid(x, y, indexing='ij')
def source_G(t):
center = np.exp(-0.5*(t-5)**2) * 10
gradient = (1+np.tanh(t-30)) * 0.0003
piecewise_1 = f(x) # ***function f(x) called here***
return -(
np.exp(-0.5*(x*x + y*y)) #+ np.exp(-0.5*((x)**2 + y*y))
) * center + piecewise_1 * gradient # piecewise function test
Main code here.
I already know the code works for a trapezoid function in combination with the x array, as follows:
(code requires: from scipy import signal)
def trapezoid_signal(x, width=2., slope=1., amp=10., offs=1):
a = slope * width * signal.sawtooth(2 * np.pi * 1/10 * x/width - 0.8, width=0.5)/4.
a[a>amp/2.] = amp/2.
a[a<-amp/2.] = -amp/2.
return a + amp/2. + offs
def source_G(t):
center = np.exp(-0.5*(t-5)**2) * 10
gradient = (1+np.tanh(t-30)) * 0.0003
trapezoid = trapezoid_signal(x, width=40, slope=5, amp=50)
return -(
np.exp(-0.5*(x**2 + y**2))
) * center + trapezoid * gradient # one soliton particle in 2 dimensions of xy with z axis as concentration potential
If you want to make this
def f(x):
if x < 0:
return -2*x
else :
return -x
compatible with vectorization, you can use the following (very common) trick:
def f(x):
neg = x < 0
return neg * (-2 * x) + (1 - neg) * -x
It works!
>>> f(np.arange(-5, 5))
array([10, 8, 6, 4, 2, 0, -1, -2, -3, -4])

I’m confused with how to convert RGB to YCrCb

Given that:
Y = 0.299R + 0.587G + 0.114B
What values do we put in for R,G, and B? I’m assuming 0-255. For arguments sake, if R, G, B are each 50, then does it mean Y=0.299(50) + 0.587(500) + 0.11(50)?
The next two are also confusing. How can B - Y even be possible if Y contains Blue then isn’t B - Y just taking away itself?
Cb = 0.564( B − Y )
Cr =0.713(R−Y)
It's just simple (confusing) math ...
Remark: There are few standards of YCbCr following formula applies BT.601, with "full range":
Equation (1): Y = 0.299R + 0.587G + 0.114B
The common definition of YCbCr assumes that R, G, and B are 8 bits unsigned integers in range [0, 255].
There are cases where R, G, B are floating point values in range [0, 1] (normalized values).
There are also HDR cases where range is [0, 1023] for example.
In case R=50, G=50, B=50, you just need to assign the values:
Y = 0.299*50 + 0.587*50 + 0.114*50
Result: Y = 50.
Since Y represents the Luma (line luminescence), and RGB=(50,50,50), is a gray pixel, it does make sense that Y = 50.
The following equations Cb = 0.564(B - Y), Cr = 0.713(R - Y) are incorrect.
Instead of Cb, and Cr they should be named Pb and Pr.
Equation (2): Pb = 0.564(B - Y)
Equation (3): Pr = 0.713(R - Y)
The equations mean that you can compute Y first, and then use the result for computing Pb and Pr.
Remark: don't round the value of Y when you are using it for computing Pb and Pr.
You can also assign Equation (1) in (2) and (3):
Pb = 0.564(B - Y) = 0.564(B - (0.299R + 0.587G + 0.114B)) = 0.4997*B - 0.3311*G - 0.1686*R
Pr = 0.713(R - Y) = 0.713(R - (0.299R + 0.587G + 0.114B)) = 0.4998*R - 0.4185*G - 0.0813*B
There are some small inaccuracies.
Wikipedia is more accurate (but still just a result of mathematical assignments):
Y = 0.299*R + 0.587*G + 0.114*B
Pb = -0.168736*R - 0.331264*G + 0.5*B
Pr = 0.5*R - 0.418688*G - 0.081312*B
In the above formulas the range of Pb, Pr is [-127.5, 127.5].
In the "full range" formula of YCbCr (not YPbPr), an offset of 128 is added to Pb and Pr (so result is always positive).
In case of 8 bits, the final result is limited to range [0, 255] and rounded.
What you're referencing is the conversion of RGB to YPbPr.
Conversion to YCbCr is as follows:
Y = 0.299 * R + 0.587 * G + 0.114 * B
Cb = -0.167 * R - 0.3313 * G - 0.5 * B + 128
Cr = 0.5 * R - 0.4187 * G - 0.0813 * B + 128
Yours is YPbPr (which is better for JPEG Compression, see below):
delta = 0.5
Y = 0.299 * R + 0.587 * G + 0.114 * B (same as above)
Pb: (B - Y) * 0.564 + delta
Pr: (B - Y) * 0.713 + delta
The above answer did a better job of explaining this.
I've been looking into JPEG Compression for implementation in Pytorch and found this thread (https://photo.stackexchange.com/a/8357) useful to explain why we use YPbPr for compression over YCbCr.
Pb and Pr versions are better for image compression because the luminance information (which contains the most detail) is retained in only one (Y) channel, while Pb and Pr would contain the chrominance information. Thus when you're doing down-sampling later down the line, there's less loss of valuable info.

Two dimensional convolution in matlab . Result differs from conv2 of matlab toolbox.Any tip?

[r,c] = size(x);
[m,n] = size(y);
h = rot90(y, 2);
center = floor((size(h)+1)/2);
Rep = zeros(r + m*2-2, c + n*2-2);
return
for x1 = m : m+r-1
for y1 = n : n+r-1
Rep(x1,y1) = x(x1-m+1, y1-n+1);
end
end
B = zeros(r+m-1,n+c-1);
for x1 = 1 : r+m-1
for y1 = 1 : n+c-1
for i = 1 : m
for j = 1 : n
B(x1, y1) = B(x1, y1) + (Rep(x1+i-1, y1+j-1) * h(i, j));
end
end
end
end
Con=conv2(Rep,h);
I have this code for 2d convolution.But Con and B are different(last column of correct convolution(=Con) does not exist in B,and other elements also differ.I cant understand what i do wrong.

Passing Arrays as a parameter to a VBA function

I have a user defined Excell worksheet function (Linear) that interpolates from an array of X and an array of Y values at a defined X1 value, which works fine. I have tried to use this within another function (NPL in the example code below) be setting it a a Private Static function within a VBA module and then calling the function using arrays of data created within the function.
When I use this in the spreadsheet I get a #VALUE error.
Any ideas what I am doing wrong?
Example code:
Function NPL(Length, Beam)
A = Array(1, 2, 3, 4)
B = Array(2, 4, 6, 8)
C = Linear(A, B, 1.5)
NPL = C
End Function
Private Static Function Linear(X, Y, X1)
N = 0
I = 1
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = X.Count
A = 0
I = 0
Do
I = I + 1
Loop Until X(I) > X1 Or I > N - 1
If X1 < X(N) And X1 > X(1) Then
Linear = Y(I - 1) + (X1 - X(I - 1)) * (Y(I) - Y(I - 1)) / (X(I) - X(I - 1))
ElseIf X1 > X(N) Or X1 = X(N) Then
Linear = Y(N)
Else
Linear = Y(1)
End If
End Function
Replace your
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = X.Count
with
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = UBound(X) - LBound(X) + 1
This should work for any 1D array.

Resources