How to save persistent variable into .mat file? - matlab

I have a model of device which have internal state between calls.
Previously I passed that state in function call and returned a new state when exited from function.
Then, I found out about persistent variables which was exactly what I need. But problem is when I need to debug model or design between multiple calls it's hard to reproduce the exact call that I need.
For example, I have function foo:
function [y] = foo(x)
persistent k;
if isempty(k)
k = 0;
end
y = k*x;
k = k+1; %% or even k = rand
end
I have multiple runs:
x = 1:5;
for i = 1:5
y = foo(x(i))
end
and have an error in 4'th call. Currently I need to run first three calls to get function state that actual for 4'th call (and if k was equal rand, I will not be able reach that state at all).
I tried to save workspace between calls to have an option to load all states but that doesn't work:
for i = 1:3
y = foo(x(i))
end
save foo3.mat
for i = 4:5
y = foo(x(i))
end
clear all
load foo3.mat
foo(3)
ans =
0
So how can I save that function state?
Actually, I can save that variable while function is run by putting save statement in code of function but for me that's seems not right. I think that statement should be at the top-script.

I suppose the most appropriate solution to my question is replace persistent variable by global one. In that case I have minimum changes to original code:
function [y] = foo(x)
global k;
if isempty(k)
k = 0;
end
y = k*x;
k = k+1; %% or even k = rand
end
And debugging like:
x = 1:5;
for i = 1:3
y = foo(x(i))
end
global k;
save("foo3.mat","k")
clear all
load foo3.mat
foo(4)
The best solution I found is to create class-based model and move variables that stores state into class property. I can save class-object like any other variable so I can save any intermediate state of model:
classdef foo < handle
properties(Access = private)
k;
end
methods
function self = foo()
self.k = 0;
end
function [y] = bar(self, x)
y = self.k*x;
self.k = self.k+1; %% or even k = rand
end
end
end
And debug like:
f = foo();
x = 1:5;
for i = 1:3
y = f.bar(x(i))
end
save bar3.mat
for i = 4:5
y = f.bar(x(i))
end
clear f
load bar3.mat
f.bar(4)
In that case I don't need to pass and return states and I can load any inermediate state.

A couple of options:
clear
Dont use 'clear all'. You rarely if ever need to do clear all, a simple clear is usually sufficient.
mlock
Put mlock in your function, note this has other implications which you should understand by looking at the documentation. Primarily you have to unlock (munlock) it to edit the function file.
Note this will keep your persistent variable for the matlab session only.
function [y] = foo(x)
persistent k;
mlock;
if isempty(k)
k = 0;
end
y = k*x;
k = k+1; %% or even k = rand
end

Related

How to save a variable from within the integration with ode113?

I have an ODE to be integrated with ode113. Inside the function that describes the derivatives I compute some variables that I would like to "save" (either store into a file or into an array). How can I do that?
Here is an example (adapted from the documentation). Run the following script:
global number_of_calls
number_of_calls = 0;
[t, y] = ode113(#myfunc, [0 10], 0);
plot(t,y,'-o')
fprintf('Number of calls of ''myfunc'': %d\n', number_of_calls)
fprintf('Number of elements of ''t'' : %d\n', length(t))
which calls the function containing the ODE to be integrated:
function dydt = myfunc(t, y)
global number_of_calls
dydt = 2*t;
a = 2*y; % <--- how can I save a?
number_of_calls = number_of_calls + 1;
end
I thought of writing to file the values of a from inside myfunc, but as you can see myfunc is called multiple times before actually storing the current value for the independent variable, t, and in the end I would have two arrays a and t of different size.
Here's one way you can write myfunc to do this. It saves the results to a global vector a, which must be set to [] before each call to ode113. It uses a persistent variable to keep track of the previous time step:
function dydt = myfunc(t, y)
dydt = 2*t;
temp = 2*y; % Extra value to save
global a
persistent tPrevious
if isempty(a) % Initialize
a = temp;
elseif (t > tPrevious) % Moving to a new time step, so add an element
a = [a; temp];
else % Refining time step downwards or recomputing at the same time step
a(end) = temp;
end
tPrevious = t; % Store prior time step
end
And you can check that it's working like so:
global a;
a = [];
[t, y] = ode113(#myfunc, [0 10], 0);
isequal(2.*y, a)
ans =
logical
1 % a exactly equals 2.*y

AABB Intersections with Space Partitions, A Sample Code Performance and Reliability

I have originally written the following Matlab code to find intersection between a set of Axes Aligned Bounding Boxes (AABB) and space partitions (here 8 partitions). I believe it is readable by itself, moreover, I have added some comments for even more clarity.
function [A,B] = AABBPart(bbx,it) % bbx: aabb, it: iteration
global F
IT = it+1;
n = size(bbx,1);
F = cell(n,it);
A = Part([min(bbx(:,1:3)),max(bbx(:,4:6))],it,0); % recursive partitioning
B = F; % matlab does not allow
function s = Part(bx,it,J) % output to be global
s = {};
if it < 1; return; end
s = cell(8,1);
p = bx(1:3);
q = bx(4:6);
h = 0.5*(p+q);
prt = [p,h;... % 8 sub-parts (octa)
h(1),p(2:3),q(1),h(2:3);...
p(1),h(2),p(3),h(1),q(2),h(3);...
h(1:2),p(3),q(1:2),h(3);...
p(1:2),h(1),h(1:2),q(3);...
h(1),p(2),h(3),q(1),h(2),q(3);...
p(1),h(2:3),h(1),q(2:3);...
h,q];
for j=1:8 % check for each sub-part
k = 0;
t = zeros(0,1);
for i=1:n
if all(bbx(i,1:3) <= prt(j,4:6)) && ... % interscetion test for
all(prt(j,1:3) <= bbx(i,4:6)) % every aabb and sub-parts
k = k+1;
t(k) = i;
end
end
if ~isempty(t)
s{j,1} = [t; Part(prt(j,:),it-1,j)]; % recursive call
for i=1:numel(t) % collecting the results
if isempty(F{t(i),IT-it})
F{t(i),IT-it} = [-J,j];
else
F{t(i),IT-it} = [F{t(i),IT-it}; [-J,j]];
end
end
end
end
end
end
Concerns:
In my tests, it seems that probably few intersections are missing, say, 10 or so for 1000 or more setup. So I would be glad if you could help to find out any problematic parts in the code.
I am also concerned about using global F. I prefer to get rid of it.
Any other better solution in terms of speed, will be loved.
Note that the code is complete. And you can easily try it by some following setup.
n = 10000; % in the original application, n would be millions
bbx = rand(n,6);
it = 3;
[A,B] = AABBPart(bbx,it);

Undefined function or variable

I have a simple function as below:
function dz = statespace(t,z)
dz = A*z + B*k*z
end
My main script is :
clear all;close all;format short;clc;
% step 1 -- input system parameters
% structure data
M1 = 1; M2= 1; M3= 1; %Lumped Mass(Tons)
M= diag([M1,M2,M3]);
k(1)= 980; k(2)= 980; k(3)= 980; %Stiffness Coefficient(KN/M)
K = zeros(3,3);
for i=1:2
K(i,i)=k(i)+k(i+1);
end
K(3,3)=k(3);
for i=1:2
K(i,i+1)=-k(i+1);
end
for i=2:3
K(i,i-1)=-k(i);
end %Stiffness Matrix(KN/M)
c(1)= 1.407; c(2)= 1.407; c(3)= 1.407; %Damping Coefficient(KN.sec/M)
C = zeros(3,3);
for i=1:2
C(i,i)=c(i)+c(i+1);
end
C(3,3)=c(3);
for i=1:2
C(i,i+1)=-c(i+1);
end
for i=2:3
C(i,i-1)=-c(i);
end %Damping Matrix(KN.sec/M)
A = [zeros(3) eye(3);-inv(M)*K -inv(M)*C]
H = [1;0;0]
B = [0;0;0;inv(M)*H]
k = [-1 -1 -1 -1 -1 -1]
t = 0:0.004:10;
[t,z] = ode45(statespace,t);
When I run my main script it comes with following error:
Undefined function or variable 'A'.
Error in statespace (line 2)
dz = A*z + B*k*z
As you can see I defined A in main script. Why this problem happening?
There multiple things wrong with your code. First, you need to supply the values of A and B to your function but as you are invoking it (incorrectly without the # and additional parameter y0 as I commented below) in the toolbox ode45, you have to keep just two parameters so you cannot supply A and B as additional parameters. If you define A and B within your function or share them via global variables you will get further. However, as noted below the definitions don't seem to be correct as A * z and B * k * z don't have the same dimensions. z is a scalar so B * k needs to be same size and shape as A which currently it is not.
Edit from:
As Jubobs suggested change your function's parameters to include A, B and k. Also you don't need t as it is never used in the function. So:
function dz = statespace(A, B, k, z)
dz = A*z + B*k*z
end
As others have pointed out, A, B and k are not defined in the function workspace, so you either need to define them again (ugly, not recommended), declare them as global variables (slightly better, but still not good practice), or pass them as arguments to your function (the better solution). However, because you then want to use the function with ode45, you need to be a bit careful with how you do it:
function dz = statespace(t,z,A,B,k)
dz = A*z + B*k*z
end
and then the call to ode45 would like this:
[t,z] = ode45(#(t,z)statespace(t,z,A,B,k),[0 Tf],z0); % where Tf is your final time and z0 your initial conditions
See Error using ode45 and deval for a similar problem.

vectorization in matlab class

I have a class in MATLAB that represents an imaginary number. I have a constructor and two data members: real and imag. I am playing with overloading operator in a class and I want to make it work with matrices:
function obj = plus(o1, o2)
if (any(size(o1) ~= size(o2)))
error('dimensions must match');
end
[n,m] = size(o1);
obj(n,m) = mycomplex();
for i=1:n
for j=1:m
obj(i,j).real = o1(i,j).real + o2(i,j).real;
obj(i,j).imag = o1(i,j).imag + o2(i,j).imag;
end
end
end
But I don't want to use for loops. I want to do something like:
[obj.real] = [o1.real] + [o2.real]
But I don't understand why it does not work... the error says:
"Error in + Too many output arguments".
I know that in MATLAB it is good to avoid for loops for speed up... Can someone explain me why this does not work, and the right way to think about vectorization in MATLAB with an example for my function?
Thanks in advance.
EDIT: definition of my complex class:
classdef mycomplex < handle & matlab.mixin.CustomDisplay
properties (Access = public)
real;
imag;
end
methods (Access = public)
function this = mycomplex(varargin)
switch (nargin)
case 0
this.real = 0;
this.imag = 0;
case 1
this.real = varargin{1};
this.imag = 0;
case 2
this.real = varargin{1};
this.imag = varargin{2};
otherwise
error('Can''t have more than two arguments');
end
obj = this;
end
end
end
Consider the implementation below. First some notes:
the constructor can be called with no parameters. This is important to allow preallocating object arrays: obj(m,n) = MyComplex()
for convenience, the constructor accepts either scalar of array arguments. So we can call: c_scalar = MyComplex(1,1) or c_array = MyComplex(rand(3,1), rand(3,1))
the plus operator uses a for-loop for now (we will later change this).
(Note that I skipped some validations in the code, like checking that o1 and o2 are of the same size, similarly for a and b in the constructor).
classdef MyComplex < handle
properties
real
imag
end
methods
function obj = MyComplex(a,b)
% default values
if nargin < 2, b = 0; end
if nargin < 1, a = 0; end
% accepts scalar/array inputs
if isscalar(a) && isscalar(b)
obj.real = a;
obj.imag = b;
else
[m,n] = size(a);
obj(m,n) = MyComplex();
for i=1:m*n
obj(i).real = a(i);
obj(i).imag = b(i);
end
end
end
function obj = plus(o1, o2)
[m,n] = size(o1);
obj(m,n) = MyComplex(); % preallocate object array
for i=1:m*n % linear indexing
obj(i).real = o1(i).real + o2(i).real;
obj(i).imag = o1(i).imag + o2(i).imag;
end
end
end
end
An example of using the class:
% scalar objects
>> c1 = MyComplex(1,2);
>> c2 = MyComplex(3,4);
>> c3 = c1 + c2
c3 =
MyComplex with properties:
real: 4
imag: 6
% array of objects
>> c4 = [c1;c1] + [c2;c2]
c4 =
2x1 MyComplex array with properties:
real
imag
Now here is a vectorized version of the plus method:
function obj = plus(o1, o2)
[m,n] = size(o1);
obj(m,n) = MyComplex();
x = num2cell([o1.real] + [o2.real]);
[obj.real] = deal(x{:});
x = num2cell([o1.imag] + [o2.imag]);
[obj.imag] = deal(x{:});
end
I'm using the syntax: [objarray.propName] to reference a property in object arrays, this return the values as a vector.
For the opposite of assigning a property in an object array, I use comma-separated lists, thus I had to convert to a cell array to get the x{:} convenient syntax.
Note that the deal call is not strictly needed, we could write the assignment without it:
[obj.real] = x{:};
The line obj(n,m) = mycomplex() looks very suspicious. I think what you want to do there is obj = mycomplex(n,m) instead.
I can't see the rest of your code, but it's miraculous to me that this line even works. I suspect that you have an obj variable stored somewhere already, and this code simply overwrites one entry of that variable. I predict that if you clear all variables, it's going to fail on that line.
Again, it's very difficult to understand what happens without knowing what mycomplex() actually does.

use nested functions in matlab M-file

i have question,about which i am too much interested,suppose that i have two M-file in matlab, in the first one i have described following function for calculating peaks and peaks indeces
function [peaks,peak_indices] = find_peaks(row_vector)
A = [0 row_vector 0];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end
and in second M-file i have code for describing sinusoidal model for given data sample
function [ x ]=generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))';
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
end
my question is how to combine it together?one solution would be just create two M-file into folder,then call function from one M-file and made operation on given vector and get result,and then call second function from another M file on given result and finally get what we want,but i would like to build it in one big M-file,in c++,in java,we can create classes,but i am not sure if we can do same in matlab too,please help me to clarify everything and use find_peaks function into generate function
UPDATED:
ok now i would like to show simple change what i have made in my code
function [ x ] = generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
[pks,locs] = findpeaks(x);
end
i used findpeaks built-in function in matlab,but i am getting following error
generate(1000,50,50)
Undefined function 'generate' for input arguments of type 'double'.
also i am interested what would be effective sampling rate to avoid alliasing?
You can simply put both in one file. The file must have the same name as the first function therein, and you will not be able to access subsequently defined functions from outside that file. See the MATLAB documentation on functions http://www.mathworks.co.uk/help/matlab/ref/function.html (particularly the examples section).
Also note that MATLAB has a built-in function findpeaks().
(By the way, you're still sampling at too low a frequency and will most certainly get aliasing - see http://en.wikipedia.org/wiki/Aliasing#Sampling_sinusoidal_functions )
Edit: As you requested it, here is some more information on the sampling theorem. A good and simple introduction to these basics is http://www.dspguide.com/ch3/2.htm and for further reading you should search for the Shannon/Nyquist sampling theorem.
Try with this, within a single MATLAB script
function test()
clc, clear all, close all
x = generate(1000,50,50);
[p,i] = find_peaks(x)
end
function x = generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
end
function [peaks,peak_indices] = find_peaks(row_vector)
A = [0;row_vector;0];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end