I'm trying to find zeros of a function. See my code below.
Because fft expects a numerical array, I didn't define the symbolic function to use fzero.
However, this approach is not accurate and depend on step. Do you have a better idea?
step=2000;
x=0:pi/step:2*pi;
y= 4+5*cos(10*x)+20*cos(40*x)+cos(100*x);
fy = fft(y');
fy(1:8) =0;
fy(12:end-10)=0;
fy(end-6:end)=0;
ffy = ifft(fy);
t=diff(ffy);
x=0:pi/step:2*pi-pi/step;
plot(x,t)
indices= find(t<5e-4 & t>-5e-4);
You could proceed along the array t and look for points where the values change sign. That would indicate the presence of a zero.
Actaully, MATLAB's fzero function uses a similar method. You said you didn't use it because you required an array, rather than an anonymous function, but you could convert the array into an anonymous function using simple linear interpolation like so:
func = #(k) interp1(x,t,k); % value of t(x) interpolated at x=k
fzero(func,initial_value);
EDIT : Just to clarify what I mean. If you have an array t and you want to find its zeros...
f = 5; % frequency of wave in Hz
x = 0:0.01:1; % time index
t = cos( 2*pi*f*x ); % cosine wave of frequency f
zeroList = []; % start with an empty list of zeros
for i = 2:length(t) % loop through the array t
current_t = t(i); % current value of t
previous_t = t(i-1); % previous value of t
if current_t == 0 % the case where the zero is exact
newZero = x(i);
zeroList = [zeroList,newZero];
elseif current_t*previous_t < 0 % a and b have opposite sign if a*b is -ve
% do a linear interpolation to find the zero (solve y=mx+b)
slope = (current_t-previous_t)/(x(i)-x(i-1));
newZero = x(i) - current_t/slope;
zeroList = [zeroList,newZero];
end
end
figure(1); hold on;
axis([ min(x) max(x) -(max(abs(t))) (max(abs(t))) ]);
plot(x,t,'b');
plot(x,zeros(length(x)),'k-.');
scatter(zeroList,zeros(size(zeroList)),'ro');
The zeros I get are correct:
Related
I am struggling with solving a problem as efficient as possible.
I have two equations and want to solve them together. Furthermore, I want to solve them for four different cases. I can solve them independently altering the code for each case. I can also solve them by accessing a vector that contains the desired value for one of them (e.g., the first value of A) by using arrayfun. However I can't manage to do all of them together.
My code:
clc
clear all
close all
% scalar parameters
g = 9.807; % Gravity constant, m/s2
d = 1.225; % Density of air, kg/m3
x = 1000; % Height, m
% vector parameters
%t = 0:2:10; % time, seconds
A = [1.2; 1.7; 1.8; 0.3]; % Area, m^2
m = [82; 84; 90; 25]; % Mass, kg
Cd = [0.3; 1.14; 0.29; 0.045]; % Drag coefficient, -
syms v t
eqn1 = 2*m./(A.*Cd*d).* log(abs(cosh(t.*sqrt(A.*Cd*d*g./(2*m))))) == x;
eqn2 = (2*g*m./(d*A.*Cd)).*tanh(t.* sqrt((g*d*Cd.*A)./(2*m))) - v == 0;
eqns=[eqn1 eqn2];
variables = [v t];
result = arrayfun(#vpasolve, eqns, 'uniform', 0)
%disp('v='),disp(eval(v));
%disp('t='),disp(eval(t));
I get a result for t (which is weirdly negative and I don't know why), but I only get a {1×1 struct} for v, which I don't want. I know I can solve this also by using a for loop, but I wanted to make it more efficient.
I tried the code written above and solved it in various forms, however not as desired.
The way you have it implemented you're effectively trying to solve four equations with two unknowns, which isn't supported by vpasolve except in the case of polynomial systems.
It looks like you're trying to solve the same system for four different combinations of values for the parameters A, m, and Cd. The easiest way to do that is to just break this out as a for loop (there is simply no benefit to using arrayfun here – speed or otherwise). You'll need to create some temporary symbolic variable for the parameter (there are a few ways this could be done). Here is example code to do just that:
% scalar parameters
g = 9.807; % Gravity constant, m/s2
d = 1.225; % Density of air, kg/m3
x = 1000; % Height, m
% vector parameters
%t = 0:2:10; % time, seconds
A = [1.2; 1.7; 1.8; 0.3]; % Area, m^2
m = [82; 84; 90; 25]; % Mass, kg
Cd = [0.3; 1.14; 0.29; 0.045]; % Drag coefficient, -
syms v t real
syms A_sym m_sym Cd_sym real % Temporary symbolic variables
eqn1 = 2*m_sym./(A_sym.*Cd_sym*d).* log(abs(cosh(t.*sqrt(A_sym.*Cd_sym*d*g./(2*m_sym))))) == x;
eqn2 = (2*g*m_sym./(d*A_sym.*Cd_sym)).*tanh(t.* sqrt((g*d*Cd_sym.*A_sym)./(2*m_sym))) - v == 0;
eqns=[eqn1 eqn2];
variables = [v t];
n = length(A); % Number of prameter sets
result = cell(n,1); % Preallocate resultant cell array
for i = 1:n
% Substitute in numeric values for i-th parameter set
eqns_sub = subs(eqns,{A_sym,m_sym,Cd_sym},{A(i),m(i),Cd(i)});
% Solve and store in cell array
result{i} = vpasolve(eqns_sub,variables);
end
The output, result, is a 4-by-1 cell array of structs with your two variables, v and t, as VPA-valued fields for each.
You could replace the last few lines with the following if what you want is a numeric array as the output (this assumes that only one solution is found for each parameter set):
n = length(A); % Number of prameter sets
result = zeros(n,length(variables)); % Preallocate resultant array
for i = 1:n
% Substitute in numeric values for i-th parameter set
eqns_sub = subs(eqns,{A_sym,m_sym,Cd_sym},{A(i),m(i),Cd(i)});
% Solve, convert to double precision, and store in array
out = vpasolve(eqns_sub,variables);
result(i,:) = double([out.v out.t]);
end
I attempted to solve the problem, and would like a solution to compare to.
The question is:
Write a function that determines the (n-1)th order Newton polynomial and interpolates for a
set of values. The inputs of your function should be: a vector of x values, a corresponding
vector of y values, and a vector of values to interpolate. Your outputs should be the
coefficients of the polynomial (as a vector, [a1 a2 ···an]) and the corresponding function
values for the interpolation. Thoroughly comment your code to show that you
know what you are doing.
My attempt is:
function yint = Newtint(x,y,xx)
n = length(x);
if length(y)~=n, error('x and y must be same length'); end
b = zeros(n,n);
b(:,1) = y(:); % the (:) ensures that y is a column vector.
for j = 2:n
for i = 1:n-j+1
b(i,j) = (b(i+1,j-1)-b(i,j-1))/(x(i+j-1)-x(i));
end
end
xt = 1;
yint = b(1,1);
for j = 1:n-1
xt = xt*(xx-x(j));
yint = yint+b(1,j+1)*xt;
end
% input:
% x = independent variable
% y = dependent variable
% xx = value of independent variable at which
% interpolation is calculated
% output:
% yint = interpolated value of dependent variable
% compute the finite divided differences in the form of a
% difference table
I have 2 vectors and a scalar:
grid which is (N x 1);
Value which is (N x 1);
sval which is (1,1);
If I want to interpolate sval on grid I know that I can simply do:
intervalue = interp1(grid, Value, sval, 'PCHIP');
What if now I want the derivatives, i.e. the slope of the function Value at that particular point sval?
As mentioned in the comments, you can approximate the derivative by forward finite difference approximation:
slope = diff(Value) ./ diff(grid);
Alternatively:
slope = gradient(Value(1:end-1),grid);
This is a simple method of numerical differentiation. For a detailed guide on numerical differentiation in MATALB, see this answer.
Here is an example of the finite difference method with the desired interpolation:
% Define function y = x^3
grid = 1:100;
Value = grid .^ 3;
% Approximate derivative via the local slope
slope = diff(Value) ./ diff(grid);
% Or: slope = gradient(Value(1:end-1),grid);
slope_grid = grid(1:end-1);
% Interpolate derivative
sval = 33.5;
sval_slope = interp1(slope_grid, slope, sval, 'PCHIP');
We can visualize the result:
figure;
plot(grid, 3*grid.^2)
hold on
plot(slope_grid, slope)
legend('Reference', 'Approximation', 'Location', 'NorthWest')
I have a custom function called dissmeasure that outputs a scalar from an input vector of frequencies. Another function called music.tone2freq converts integers numbers to frequencies.
My objective is to create a surface plot of dissmeasure for all pairs of x,y integers where X and Y equal [0:1:11].
It should look something like this (this is mesh(X,Y, ones(12,12) ) ):
Following from the mesh docs, what I have tried is doing:
[X,Y] = meshgrid(0:1:12)
Z = dissmeasure(music.tone2freq([X., Y.]))
But I get Error: Expression or statement is incorrect--possibly unbalanced (, {, or [..
Z = dissmeasure(music.tone2freq([X(:), Y(:)]))
But [X(:), Y(:)] doesn't seem to have the correct size. Also my function that accepts a vector returns one scalar for that whole input. What I need is multiple returns.
Note that both dissmeasure(music.tone2freq([X(:), Y(:)])) and dissmeasure(music.tone2freq([X, Y])) work, but the result from dissmeasure is a single scalar number, not a matrix of the result of this function for each x,y pair.
Any help? Thank you
tone2freq.m
function f = tone2freq(T)
% MUSIC.TONE2FREQ converts a musical semitone to a frequency.
% F = MUSIC.TONE2FREQ(T) converts the musical semitones in T to frequencies.
%
% Example
% f = music.tone2freq(0:2); % returns [261.63 277.19 293.67]
%
% See also music.tone2interval, music.tone2note, music.freq2tone.
% Author: E. Johnson
% Copyright 2010 The MathWorks, Inc.
fC4 = 261.625565300599; % Middle C (C4) is 261.63 Hz
f = fC4 .* 2 .^ (T / 12);
dissmeasure.m:
% calculate dissonace
% input param fvec - list of frequencies
% input param amp - list of amplitudes
% output is sum of dissonances of each pair of partials (scalar)
function d = dissmeasure(fvec, amp)
if ~exist('amp','var')
amp = ones(size(fvec));
end
Xstar = 0.24; % place with maximum dissonance
S1 = 0.0207; % to fit frequency dependend curves
S2 = 18.96; % so max. dissonance occures at 1/4 critical bandwidth
C1 = 5;
C2 = -5;
B1 = -3.51; % derived from model of Levelt & Plomp
B2 = -5.75;
N = length(fvec);
[fvec, idx_list] = sort(fvec); % sort partial frequencies ascending
amp = amp(idx_list); % rearrange amplitude values
%amp = loudness(amp);
D = 0;
for i=2:N
Fmin = fvec(1 : N-i+1); % get slice as list of Fmin
S = Xstar./(S1*Fmin+S2); % calc list of s-scalings with list of Fmin
% treat vector as tail and head ...
Fdif = fvec(i:N) - fvec(1:N-i+1); % build element wise difference
a = min(amp(i:N), amp(1:N-i+1)); % select element wise a minimum
Dnew = a .* (C1*exp(B1*S.*Fdif) + C2*exp(B2*S.*Fdif));
D = D + sum(Dnew); % sum up last D and vector elements
end
d=D;
Your function dissmeasure does not support vectorized operations, which means that for inputs of size N the function is evaluated for each element and an output of size N is returned.
Instead your function returns the summarized dissonance.
%assuming you have X and Y already converted
Z=X*0 % initialize Z of same size
for ix = 1:numel(X)
Z(ix)=dissmeasure(X(ix),Y(ix));
end
I have implemented a script that does constrained optimization for solving the optimal parameters of Support Vector Machines model. I noticed that my script for some reason gives inaccurate results (although very close to the real value). For example the typical situation is that the result of a calculation should be exactly 0, but instead it is something like
-1/18014398509481984 = -5.551115123125783e-17
This situation happens when I multiply matrices with vectors. What makes this also strange is that if I do the multiplications by hand in the command window in Matlab I get exactly 0 result.
Let me give an example: If I take the vectors Aq = [-1 -1 1 1] and x = [12/65 28/65 32/65 8/65]' I get exactly 0 result from their multiplication if I do this in the command window, as you can see in the picture below:
If on the other hand I do this in my function-script I don't get the result being 0 but rather the value -1/18014398509481984.
Here is the part of my script that is responsible for this multiplication (I've added the Aq and x into the script to show the contents of Aq and x as well):
disp('DOT PRODUCT OF ACTIVE SET AND NEW POINT: ')
Aq
x
Aq*x
Here is the result of the code above when run:
As you can see the value isn't exactly 0 even though it really should be. Note that this problem doesn't occur for all possible values of Aq and x. If Aq = [-1 -1 1 1] and x = [4/13 4/13 4/13 4/13] the result is exactly 0 as you can see below:
What is causing this inaccuracy? How can I fix this?
P.S. I didn't include my whole code because it's not very well documented and few hundred lines long, but I will if requested.
Thank you!
UPDATE: new test, by using Ander Biguri's advice:
UPDATE 2: THE CODE
function [weights, alphas, iters] = solveSVM(data, labels, C, e)
% FUNCTION [weights, alphas, iters] = solveSVM(data, labels, C, e)
%
% AUTHOR: jjepsuomi
%
% VERSION: 1.0
%
% DESCRIPTION:
% - This function will attempt to solve the optimal weights for a Support
% Vector Machines (SVM) model using active set method with gradient
% projection.
%
% INPUTS:
% "data" a n-by-m data matrix. The number of rows 'n' corresponds to the
% number of data points and the number of columns 'm' corresponds to the
% number of variables.
% "labels" a 1-by-n row vector of data labels from the set {-1,1}.
% "C" Box costraint upper limit. This will constrain the values of 'alphas'
% to the range 0 <= alphas <= C. If hard-margin SVM model is required set
% C=Inf.
% "e" a real value corresponding to the convergence criterion, that is if
% solution Xi and Xi-1 are within distance 'e' from each other stop the
% learning process, i.e. IF |F(Xi)-F(Xi-1)| < e ==> stop learning process.
%
% OUTPUTS:
% "weights" a vector corresponding to the optimal decision line parameters.
% "alphas" a vector of alpha-values corresponding to the optimal solution
% of the dual optimization problem of SVM.
% "iters" number of iterations until learning stopped.
%
% EXAMPLE USAGE 1:
%
% 'Hard-margin SVM':
%
% data = [0 0;2 2;2 0;3 0];
% labels = [-1 -1 1 1];
% [weights, alphas, iters] = solveSVM(data, labels, Inf, 10^-100)
%
% EXAMPLE USAGE 2:
%
% 'Soft-margin SVM':
%
% data = [0 0;2 2;2 0;3 0];
% labels = [-1 -1 1 1];
% [weights, alphas, iters] = solveSVM(data, labels, 0.8, 10^-100)
% STEP 1: INITIALIZATION OF THE PROBLEM
format long
% Calculate linear kernel matrix
L = kron(labels', labels);
K = data*data';
% Hessian matrix
Qd = L.*K;
% The minimization function
L = #(a) (1/2)*a'*Qd*a - ones(1, length(a))*a;
% Gradient of the minimizable function
gL = #(a) a'*Qd - ones(1, length(a));
% STEP 2: THE LEARNING PROCESS, ACTIVE SET WITH GRADIENT PROJECTION
% Initial feasible solution (required by gradient projection)
x = zeros(length(labels), 1);
iters = 1;
optfound = 0;
while optfound == 0 % criterion met
% Negative of the gradient at initial solution
g = -gL(x);
% Set the active set and projection matrix
Aq = labels; % In plane y^Tx = 0
P = eye(length(x))-Aq'*inv(Aq*Aq')*Aq; % In plane projection
% Values smaller than 'eps' are changed into 0
P(find(abs(P-0) < eps)) = 0;
d = P*g'; % Projection onto plane
if ~isempty(find(x==0 | x==C)) % Constraints active?
acinds = find(x==0 | x==C);
for i = 1:length(acinds)
if (x(acinds(i)) == 0 && d(acinds(i)) < 0) || x(acinds(i)) == C && d(acinds(i)) > 0
% Make the constraint vector
constr = zeros(1,length(x));
constr(acinds(i)) = 1;
Aq = [Aq; constr];
end
end
% Update the projection matrix
P = eye(length(x))-Aq'*inv(Aq*Aq')*Aq; % In plane / box projection
% Values smaller than 'eps' are changed into 0
P(find(abs(P-0) < eps)) = 0;
d = P*g'; % Projection onto plane / border
end
%%%% DISPLAY INFORMATION, THIS PART IS NOT NECESSAY, ONLY FOR DEBUGGING
if Aq*x ~= 0
disp('ACTIVE SET CONSTRAINTS Aq :')
Aq
disp('CURRENT SOLUTION x :')
x
disp('MULTIPLICATION OF Aq and x')
Aq*x
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Values smaller than 'eps' are changed into 0
d(find(abs(d-0) < eps)) = 0;
if ~isempty(find(d~=0)) && rank(P) < length(x) % Line search for optimal lambda
lopt = ((g*d)/(d'*Qd*d));
lmax = inf;
for i = 1:length(x)
if d(i) < 0 && -x(i) ~= 0 && -x(i)/d(i) <= lmax
lmax = -x(i)/d(i);
elseif d(i) > 0 && (C-x(i))/d(i) <= lmax
lmax = (C-x(i))/d(i);
end
end
lambda = max(0, min([lopt, lmax]));
if abs(lambda) < eps
lambda = 0;
end
xo = x;
x = x + lambda*d;
iters = iters + 1;
end
% Check whether search direction is 0-vector or 'e'-criterion met.
if isempty(find(d~=0)) || abs(L(x)-L(xo)) < e
optfound = 1;
end
end
%%% STEP 3: GET THE WEIGHTS
alphas = x;
w = zeros(1, length(data(1,:)));
for i = 1:size(data,1)
w = w + labels(i)*alphas(i)*data(i,:);
end
svinds = find(alphas>0);
svind = svinds(1);
b = 1/labels(svind) - w*data(svind, :)';
%%% STEP 4: OPTIMALITY CHECK, KKT conditions. See KKT-conditions for reference.
weights = [b; w'];
datadim = length(data(1,:));
Q = [zeros(1,datadim+1); zeros(datadim, 1), eye(datadim)];
A = [ones(size(data,1), 1), data];
for i = 1:length(labels)
A(i,:) = A(i,:)*labels(i);
end
LagDuG = Q*weights - A'*alphas;
Ac = A*weights - ones(length(labels),1);
alpA = alphas.*Ac;
LagDuG(any(abs(LagDuG-0) < 10^-14)) = 0;
if ~any(alphas < 0) && all(LagDuG == zeros(datadim+1,1)) && all(abs(Ac) >= 0) && all(abs(alpA) < 10^-6)
disp('Optimal found, Karush-Kuhn-Tucker conditions satisfied.')
else
disp('Optimal not found, Karush-Kuhn-Tucker conditions not satisfied.')
end
% VISUALIZATION FOR 2D-CASE
if size(data, 2) == 2
pinds = find(labels > 0);
ninds = find(labels < 0);
plot(data(pinds, 1), data(pinds, 2), 'o', 'MarkerFaceColor', 'red', 'MarkerEdgeColor', 'black')
hold on
plot(data(ninds, 1), data(ninds, 2), 'o', 'MarkerFaceColor', 'blue', 'MarkerEdgeColor', 'black')
Xb = min(data(:,1))-1;
Xe = max(data(:,1))+1;
Yb = -(b+w(1)*Xb)/w(2);
Ye = -(b+w(1)*Xe)/w(2);
lineh = plot([Xb Xe], [Yb Ye], 'LineWidth', 2);
supvh = plot(data(find(alphas~=0), 1), data(find(alphas~=0), 2), 'g.');
legend([lineh, supvh], 'Decision boundary', 'Support vectors');
hold off
end
NOTE:
If you run the EXAMPLE 1, you should get an output starting with the following:
As you can see, the multiplication between Aq and x don't produce value 0, even though they should. This is not a bad thing in this particular example, but if I have more data points with lots of decimals in them this inaccuracy becomes bigger and bigger problem, because the calculations are not exact. This is bad for example when I'm searching for a new direction vector when I'm moving towards the optimal solution in gradient projection method. The search direction isn't exactly the correct direction, but close to it. This is why I want the exactly correct values...is this possible?
I wonder if the decimals in the data points have something to do with the accuracy of my results. See the picture below:
So the question is: Is this caused by the data or is there something wrong in the optimization procedure...
Do you use format function inside your script? It looks like you used somewhere format rat.
You can always use matlab eps function, that returns precision that is used inside matlab. The absolute value of -1/18014398509481984 is smaller that this, according to my Matlab R2014B:
format long
a = abs(-1/18014398509481984)
b = eps
a < b
This basically means that the result is zero (but matlab stopped calculations because according to eps value, the result was just fine).
Otherwise you can just use format long inside your script before the calculation.
Edit
I see inv function inside your code, try replacing it with \ operator (mldivide). The results from it will be more accurate as it uses Gaussian elimination, without forming the inverse.
The inv documentation states:
In practice, it is seldom necessary to form the explicit inverse of a
matrix. A frequent misuse of inv arises when solving the system of
linear equations Ax = b. One way to solve this is with x = inv(A)*b. A
better way, from both an execution time and numerical accuracy
standpoint, is to use the matrix division operator x = A\b. This
produces the solution using Gaussian elimination, without forming the
inverse.
With the provided code, this is how I tested:
I added a break-point on the following code:
if Aq*x ~= 0
disp('ACTIVE SET CONSTRAINTS Aq :')
Aq
disp('CURRENT SOLUTION x :')
x
disp('MULTIPLICATION OF Aq and x')
Aq*x
end
When the if branch was taken, I typed at console:
K>> format rat; disp(x);
12/65
28/65
32/65
8/65
K>> disp(x == [12/65; 28/65; 32/65; 8/65]);
0
1
0
0
K>> format('long'); disp(max(abs(x - [12/65; 28/65; 32/65; 8/65])));
1.387778780781446e-17
K>> disp(eps(8/65));
1.387778780781446e-17
This suggests that this is a displaying problem: the format rat deliberately uses small integers for expressing the value, on the expense of precision. Apparently, the true value of x(4) is the next one to 8/65 than can be possibly put in double format.
So, this begs the question: are you sure that numeric convergence depends on flipping the least significant bit in a double precision value?