Updating parameters in a function being called by Octave's fsolve - octave

I am working on modeling the motion of a single actuated leg in Octave. The leg has 3 points: a stationary hip (point A), a foot (point B) that moves along a known path, and a knee (point C) whose location and angle I am trying to solve for.
Using the code below I can successfully solve for the knee's XYZ position and relevant angles for a single value of the parameters s0 and Theta_H.
Now I want to be able to loop through multiple s0 and Theta_H values and run the solver. My problem is that I can't figure out how to pass new values for those variables into the equations function.
The reason this is tricky is that the function format necessary to use Octave's fsolve prevents entering inputs other than the unknowns into the function. I've tried updating a global variable as an indexer but to do that I would need to clear all workspace variables which causes other problems.
Any ideas on how to update the parameters in this function while still being able to input it into fsolve would be really appreciated!
The code below calls the solver:
global AC = 150; % length of the thigh limb
global CB = 150; % length of the shin limb
global lspan = 75; % width span of the foot touch down wrt the hip
global bob = 10; % height of the hip joint off the ground during a step
inits = [ .75; 2.35; 37; 0; 125]; % initial guesses at horizontal step position
% x(1): hip joint - guessing a 45 deg (.75 rad) angle for hip joint
% x(2): knee joint - guessing a 135 deg (2.35 rad) angle (wrt to vert)
% x(3): X position of the knee joint - guessing middle of the leg span in mm
% x(4): Y position of the knee joint - know it is 0 mm at the horizontal step position
% x(5): Z position of the knee joint - guessing the height to be ~80% of the height of a limb
[x, fval, info] = fsolve(#Rug_Bug_Leg, inits); % when running fsolve for the first time often have to remove the output suppress
The code below shows the function containing the system of equations to be solved by Octave's fsolve function:
function y = Rug_Bug_Leg(x)
global AC;
global CB;
global lspan;
global bob;
s0 = 0; % fore/aft (Y) position of the foot during the step. Trying to iterate this
Theta_H = 0; % hip angle during the step. Trying to iterate this
y = zeros(6,1); % zeros for left side of each equation
% First set of equations, Joint C wrt to Joint A
y(1) = -1*x(3)+AC*sin(x(1))*cos(Theta_H);
y(2) = -1*x(4)+AC*sin(x(1))*sin(Theta_H);
y(3) = -1*bob - x(5)+AC*cos(x(1));
% Second set of equations, Joint B wrt to Joint C
y(4) = x(3)-lspan +CB*sin(x(2))*cos(Theta_H);
y(5) = x(4) - s0 +sin(x(2))*sin(Theta_H);
y(6) = x(5) + bob + CB*cos(x(2));
end function

You can definitely do that!
All you need to do is create a function that returns a function.
First have your Rug_Bug_Leg function take s0 and Theta_H as inputs:
function y = Rug_Bug_Leg(x, s0, Theta_H)
% ...
endfunction
Then, you can write a "wrapper" function around Rug_Bug_Leg like this:
rbl = #(s0, Theta_H) #(x) Rug_Bug_Leg(x, s0, Theta_H)
Now, if you call rbl with some values (s0,Theta_H), it will return a function that takes x as input and returns Rug_Bug_Leg(x,s0,Theta_H).
For instance, rbl(0,0) returns the function:
#(x) Rug_Bug_Leg(x,0,0)
Here's a sample usage:
for s0=1:10
for Theta_H=1:10
[x, fval, info] = fsolve( rbl(s0,Theta_H), inits );
endfor
endfor

Related

Non-linear fit Gnu Octave

I have a problem in performing a non linear fit with Gnu Octave. Basically I need to perform a global fit with some shared parameters, while keeping others fixed.
The following code works perfectly in Matlab, but Octave returns an error
error: operator *: nonconformant arguments (op1 is 34x1, op2 is 4x1)
Attached my code and the data to play with:
clear
close all
clc
pkg load optim
D = dlmread('hd', ';'); % raw data
bkg = D(1,2:end); % 4 sensors bkg
x = D(2:end,1); % input signal
Y = D(2:end,2:end); % 4 sensors reposnse
W = 1./Y; % weights
b0 = [7 .04 .01 .1 .5 2 1]; % educated guess for start the fit
%% model function
F = #(b) ((bkg + (b(1) - bkg).*(1-exp(-(b(2:5).*x).^b(6))).^b(7)) - Y) .* W;
opts = optimset("Display", "iter");
lb = [5 .001 .001 .001 .001 .01 1];
ub = [];
[b, resnorm, residual, exitflag, output, lambda, Jacob\] = ...
lsqnonlin(F,b0,lb,ub,opts)
To give more info, giving array b0, b0(1), b0(6) and b0(7) are shared among the 4 dataset, while b0(2:5) are peculiar of each dataset.
Thank you for your help and suggestions! ;)
Raw data:
0,0.3105,0.31342,0.31183,0.31117
0.013229,0.329,0.3295,0.332,0.372
0.013229,0.328,0.33,0.33,0.373
0.021324,0.33,0.3305,0.33633,0.399
0.021324,0.325,0.3265,0.333,0.397
0.037763,0.33,0.3255,0.34467,0.461
0.037763,0.327,0.3285,0.347,0.456
0.069405,0.338,0.3265,0.36533,0.587
0.069405,0.3395,0.329,0.36667,0.589
0.12991,0.357,0.3385,0.41333,0.831
0.12991,0.358,0.3385,0.41433,0.837
0.25368,0.393,0.347,0.501,1.302
0.25368,0.3915,0.3515,0.498,1.278
0.51227,0.458,0.3735,0.668,2.098
0.51227,0.47,0.3815,0.68467,2.124
1.0137,0.61,0.4175,1.008,3.357
1.0137,0.599,0.422,1,3.318
2.0162,0.89,0.5335,1.645,5.006
2.0162,0.872,0.5325,1.619,4.938
4.0192,1.411,0.716,2.674,6.595
4.0192,1.418,0.7205,2.691,6.766
8.0315,2.34,1.118,4.195,7.176
8.0315,2.33,1.126,4.161,6.74
16.04,3.759,1.751,5.9,7.174
16.04,3.762,1.748,5.911,7.151
32.102,5.418,2.942,7.164,7.149
32.102,5.406,2.941,7.164,7.175
64.142,7.016,4.478,7.174,7.176
64.142,7.018,4.402,7.175,7.175
128.32,7.176,6.078,7.175,7.176
128.32,7.175,6.107,7.175,7.173
255.72,7.165,7.162,7.165,7.165
255.72,7.165,7.164,7.166,7.166
511.71,7.165,7.165,7.165,7.165
511.71,7.165,7.165,7.166,7.164
Giving the function definition above, if you call it by F(b0) in the command windows, you will get a 34x4 matrix which is correct, since variable Y has the same size.
In that way I can (in theory) compute the standard formula for lsqnonlin (fit - measured)^2

Solving an ODE using ode45 in Octave

I am trying to solve the following ODE using Octave, and in particular the function ode45.
dx/dt = x(1-x/2), 0<= t <= 10
with the initial condition x(0) = 0.5
But the graphs I get are not what I expect.
I think that the graph with red crosses represents x' vs x and not x vs t.
The code is the following:
clear all
close all
% Differential Equation: x' = x(1-x/2)
function dx = f(x,t)
dx = x*(1-x./2);
endfunction
% Exacte Solution: 2*e^t/(3+e^t)
function xexac =solexac(t)
xexac = (2*exp(t))./(3+exp(t));
endfunction
x0=0.5; %%Initial condition
T=10; %% maximum time T
t=[0:0.1:T]; %% we choose the times t(k) where is calculated 'y'
sol=ode45(#f,[0,T],x0); %% numerical solution of (E)
tt=sol.x;y=sol.y; %% extraction of the results
clf;hold on ; %% plot the exact and numerical solutionss
plot(tt,y,'xr')
plot(t,solexac(t),'-b')
xlabel('t')
ylabel('x(t)')
title('Chemostat Model')
legend("Numerical Solution","Exacte Solution ")
It would we great that any of you could help me with this code.
ode45 expects the ODE function to have arguments in the order (time, state), so exactly the other way around. What you effectively did was integrate t-t^2/2, and the resulting function 0.5+t^2/2-t^3/6 is what you got in the plot.

GNU Octave: 1/N Octave Smoothing of actual FFT Data (not the representation of it)

I would like to smooth an Impulse Response audio file. The FFT of the file shows that it is very spikey. I would like to smooth out the audio file, not just its plot, so that I have a smoother IR file.
I have found a function that shows the FFT plot smoothed out. How could this smoothing be applied to the actual FFT data and not just to the plot of it?
[y,Fs] = audioread('test\test IR.wav');
function x_oct = smoothSpectrum(X,f,Noct)
%SMOOTHSPECTRUM Apply 1/N-octave smoothing to a frequency spectrum
%% Input checking
assert(isvector(X), 'smoothSpectrum:invalidX', 'X must be a vector.');
assert(isvector(f), 'smoothSpectrum:invalidF', 'F must be a vector.');
assert(isscalar(Noct), 'smoothSpectrum:invalidNoct', 'NOCT must be a scalar.');
assert(isreal(X), 'smoothSpectrum:invalidX', 'X must be real.');
assert(all(f>=0), 'smoothSpectrum:invalidF', 'F must contain positive values.');
assert(Noct>=0, 'smoothSpectrum:invalidNoct', 'NOCT must be greater than or equal to 0.');
assert(isequal(size(X),size(f)), 'smoothSpectrum:invalidInput', 'X and F must be the same size.');
%% Smoothing
% calculates a Gaussian function for each frequency, deriving a
% bandwidth for that frequency
x_oct = X; % initial spectrum
if Noct > 0 % don't bother if no smoothing
for i = find(f>0,1,'first'):length(f)
g = gauss_f(f,f(i),Noct);
x_oct(i) = sum(g.*X); % calculate smoothed spectral coefficient
end
% remove undershoot when X is positive
if all(X>=0)
x_oct(x_oct<0) = 0;
end
end
endfunction
function g = gauss_f(f_x,F,Noct)
% GAUSS_F calculate frequency-domain Gaussian with unity gain
%
% G = GAUSS_F(F_X,F,NOCT) calculates a frequency-domain Gaussian function
% for frequencies F_X, with centre frequency F and bandwidth F/NOCT.
sigma = (F/Noct)/pi; % standard deviation
g = exp(-(((f_x-F).^2)./(2.*(sigma^2)))); % Gaussian
g = g./sum(g); % normalise magnitude
endfunction
% take fft
Y = fft(y);
% keep only meaningful frequencies
NFFT = length(y);
if mod(NFFT,2)==0
Nout = (NFFT/2)+1;
else
Nout = (NFFT+1)/2;
end
Y = Y(1:Nout);
f = ((0:Nout-1)'./NFFT).*Fs;
% put into dB
Y = 20*log10(abs(Y)./NFFT);
% smooth
Noct = 12;
Z = smoothSpectrum(Y,f,Noct);
% plot
semilogx(f,Y,'LineWidth',0.7,f,Z,'LineWidth',2.2);
xlim([20,20000])
grid on
PS. I have Octave GNU, so I don't have the functions that are available with Matlab Toolboxes.
Here is the test IR audio file.
I think I found it. Since the FFT of the audio file (which is real numbers) is symmetric, with the same real part on both sides but opposite imaginary part, I thought of doing this:
take the FFT, keep the half of it, and apply the smoothing function without converting the magnitudes to dB
then make a copy of that smoothed FFT, and invert just the imaginary part
combine the two parts so that I have the same symmetric FFT as I had in the beginning, but now it is smoothed
apply inverse FFT to this and take the real part and write it to file.
Here is the code:
[y,Fs] = audioread('test IR.wav');
function x_oct = smoothSpectrum(X,f,Noct)
x_oct = X; % initial spectrum
if Noct > 0 % don't bother if no smoothing
for i = find(f>0,1,'first'):length(f)
g = gauss_f(f,f(i),Noct);
x_oct(i) = sum(g.*X); % calculate smoothed spectral coefficient
end
% remove undershoot when X is positive
if all(X>=0)
x_oct(x_oct<0) = 0;
end
end
endfunction
function g = gauss_f(f_x,F,Noct)
sigma = (F/Noct)/pi; % standard deviation
g = exp(-(((f_x-F).^2)./(2.*(sigma^2)))); % Gaussian
g = g./sum(g); % normalise magnitude
endfunction
% take fft
Y = fft(y);
% keep only meaningful frequencies
NFFT = length(y);
if mod(NFFT,2)==0
Nout = (NFFT/2)+1;
else
Nout = (NFFT+1)/2;
end
Y = Y(1:Nout);
f = ((0:Nout-1)'./NFFT).*Fs;
% smooth
Noct = 12;
Z = smoothSpectrum(Y,f,Noct);
% plot
semilogx(f,Y,'LineWidth',0.7,f,Z,'LineWidth',2.2);
xlim([20,20000])
grid on
#Apply the smoothing to the actual data
Zreal = real(Z); # real part
Zimag_neg = Zreal - Z; # opposite of imaginary part
Zneg = Zreal + Zimag_neg; # will be used for the symmetric Z
# Z + its symmetry with same real part but opposite imaginary part
reconstructed = [Z ; Zneg(end-1:-1:2)];
# Take the real part of the inverse FFT
reconstructed = real(ifft(reconstructed));
#Write to file
audiowrite ('smoothIR.wav', reconstructed, Fs, 'BitsPerSample', 24);
Seems to work! :) It would be nice if someone more knowledgeable could confirm that the thinking and code are good :)

Subscript indices must be real positive integers or logicals

function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)
%GRADIENTDESCENT Performs gradient descent to learn theta
% theta = GRADIENTDESENT(X, y, theta, alpha, num_iters) updates theta by
% taking num_iters gradient steps with learning rate alpha
% Initialize some useful values
m = length(y); % number of training examples
J_history = zeros(num_iters, 1);
for iter = 1:num_iters
% ====================== YOUR CODE HERE ======================
% Instructions: Perform a single gradient step on the parameter vector
% theta.
%
% Hint: While debugging, it can be useful to print out the values
% of the cost function (computeCost) and gradient here.
%
hypothesis = x*theta;
theta_0 = theta(1) - alpha(1/m)*sum((hypothesis-y)*x);
theta_1 = theta(2) - alpha(1/m)*sum((hypothesis-y)*x);
theta(1) = theta_0;
theta(2) = theta_1;
% ============================================================
% Save the cost J in every iteration
J_history(iter) = computeCost(X, y, theta);
end
end
I keep getting this error
error: gradientDescent: subscript indices must be either positive integers less than 2^31 or logicals
on this line right in-between the first theta and =
theta_0 = theta(1) - alpha(1/m)*sum((hypothesis-y)*x);
I'm very new to octave so please go easy on me, and
thank you in advance.
This is from the coursera course on Machine Learning from Week 2
99% sure your error is on the line pointed out by topsig, where you have alpha(1/m)
it would help if you gave an example of input values to your function and what you hoped to see as an output, but I'm assuming from your comment
% taking num_iters gradient steps with learning rate alpha
that alpha is a constant, not a function. as such, you have the line alpha(1/m) without any operator in between. octave sees this as you indexing alpha with the value of 1/m.
i.e., if you had an array
x = [3 4 5]
x*(2) = [6 8 10] %% two times each element in the array
x(2) = [4] %% second element in the array
what you did doesn't seem to make sense, as 'm = length(y)' which will output a scalar, so
x = [3 4 5]; m = 3;
x*(1/m) = x*(1/3) = [1 1.3333 1.6666] %% element / 3
x(1/m) = ___error___ %% the 1/3 element in the array makes no sense
note that for certain errors it always indicates that the location of the error is at the assignment operator (the equal sign at the start of the line). if it points there, you usually have to look elsewhere in the line for the actual error. here, it was yelling at you for trying to apply a non-integer subscript (1/m)

How do I assign variables in matrices?

I can't make matrices with variables in it for some reason. I get following message.
>>> A= [a b ;(-1-a) (1-b); (1+a) b]
error: horizontal dimensions mismatch (2x3 vs 1x1)
Why is it? Please show me correct way if I'm wrong.
In Matlab you first need to assign a variable before you can use it,
a = 1;
b = a+1;
This will thus give an error,
clear;
b = a+1; % ERROR! Undefined function or variable 'a
Matlab does never accept unassigned variables. This is because, on the lowest level, you do not have a. You will have machine code which is assgined the value of a. This is handled by the JIT compiler in Matlab, so you do not need to worry about this though.
If you want to use something as the variable which you have in maths you can specifically express this to matlab. The object is called a sym and the syntax that define the sym x to a variable xis,
syms x;
That said, you can define a vector or a matrix as,
syms a b x y; % Assign the syms
A = [x y]; % Vector
B = A= [a b ;(-1-a) (1-b); (1+a) b]; % Matrix.
The size of a matrix can be found with size(M) or for dim n size(M,n). You can calcuate the matrix product M3=M1*M2 if and only if M1 have the size m * n and M2 have the size n * p. The size of M3 will then be m * p. This will also mean that the operation A^N = A * A * ... is only allowed when m=n so to say, the matrix is square. This can be verified in matlab by the comparison,
syms a b
A = [a,1;56,b]
if size(A,1) == size(A,2)
disp(['A is a square matrix of size ', num2str(size(A,1)]);
else
disp('A is not square');
end
These are the basic rules for assigning variables in Matlab as well as for matrix multiplication. Further, a google search on the error error: 'x' undefined does only give me octave hits. Are you using octave? In that case I cannot guarantee that you can use sym objects or that the syntaxes are correct.