Puzzling "Subscripted assignment dimension mismatch" only during loop using portopt & ewstats - matlab

I am tearing my hair out over this one.
I have a set of daily returns of 4 assets, using a 10 day window I loop over the whole dataset (from i = 1 to 50) performing a number of calculations and building optimal portfolios. This involves using portopt.
[PortRisk(:,i), PortReturn(:,i), PortWts(:,:,i)] = portopt(ExpReturn(i,:), ExpCovariance(:,:,i), [], [], ConSet);
The inputs, ExpReturn and ExpCovariance are generated using ewstats
[ExpReturn(i,:), ExpCovariance(:,:,i)] = ewstats(RetSeries, 0.94)
Now, on the final 50th iteration (and only the 50th - all previous work fine), I get the following error:
??? Subscripted assignment dimension mismatch. Error in ==> Script at 10
[PortRisk(:,i), PortReturn(:,i), PortWts(:,:,i)] = portopt(ExpReturn(i,:), ExpCovariance(:,:,i), [], [], ConSet);
Note, I see no issue with RetSeries as ExpReturn and ExpCovariance generated by ewstats are size <50x4> and <4x4x50> respectively.
I have tried everything i can think of to hunt down the error, including checking size(), using breakpoints, preallocating the matrices etc etc. Oddly, if i remove the loop, set i = 50, it works. Furthermore, if instead of ewstats I simply use mean() and cov() - they work on the 50th iteration. If i replace one, ExpReturn for example, with a mean(RetSeries), it works. Similarly, replacing ExpCovariance with cov(RetSeries) - works. But both ExpReturn and ExpCovariance together always fail.
What is causing the error?
EDIT:
Using dbstop if error, I can see:
PortRisk <10x50>
PortReturn <10x50>
PortWts<10x4x49>
ExpReturn <50x4>
ExpCovariance<4x4x50>
so the problem is PortWts but I do not understand why now it is not the right dimensions when it was for 49 other iterations. Also, the offending error line is the first point in the loop PortWts is mentioned, so nothing is messing with it beforehand

Try setting dbstop if error, and run your code again. MATLAB will enter debug mode at the exact point where the error occurs.
Here is a screencast by Doug Hull showing how
EDIT
Change the offending line to:
[a,b,c] = portopt(ExpReturn(i,:), ExpCovariance(:,:,i), [], [], ConSet);
then assign each individually:
PortRisk(:,i) a;
PortReturn(:,i) = b;
PortWts(:,:,i) = c;
Now when it fails, it will show you exactly which output did not have the expected size. Combined with the above trick, you can now inspect the variables in your workspace at the time of the error, and figure out what is wrong..
EDIT2
In addition, add the following test in between the two (before assigning):
if isempty(a) || isempty(b) || isempty(c)
keyboard %# enter debug mode. Or issue an error
end

Related

Unexpected length of array and plotting error as a result

I wanted to plot the load voltage across the resistor in series with a diode using matlab. This is a rather simple example involving piecewise functions, however I ran into an unexpected error.
t=[0:0.001:10]
vs=4*sin(pi * t)
for i =1:length(vs)
if(vs(i)<=0.7)
v(i)=0;
else
v(i)=vs(i)-0.7;
end
end
plot(t,v)
t is the time, vs is the source voltage, and v is the load voltage. Now, running this gave me an error saying "error, t and v are of different sizes..". Using length() I found out that while t and vs are of lengths 10001, v is somehow of length 1000001.
This is truly baffling to me. How can v and vs possibly differ in size? every element of vs was mapped to an element of v, and yet the size of v comes out to be about 100 times the size of vs.
Being new to matlab, I still am not very comfortable with not explicitly declaring the array v before using it in the for loop. However, I went through with it, because the example I worked on prior to this, used the same thing and it worked without any problems. We simply had a plot a piecewise function:
x=[-2 : 0.00001 : 20];
for i=1: length(x)
if(x(i)>=-2 && x(i)<0)
y(i)=sqrt(x(i)^2+1);
else if(x(i)>=0 && x(i)<10)
y(i)=3*x(i)+1;
else
y(i)=9*sin(5*x(i)-50);
end
end
end
plot(x,y)
This code worked flawlessly, and in my opinion the initial code is fundamentally doing the same thing, so again, I'm clueless as to why it failed.
The original code works if you initialise v to be of the same size as t (and therefore, vs), but still, I want to know why the code involving x,y worked (where y wasn't initialised) and the code involving (t,v) failed.
Also, my friend copy pasted the entire code into the command window of matlab 2016, and it worked. (and I'm using the 2021 version).
Its good practice to initialize variables before entering a loop. It will help avoid undefinied behaviour when you run the script multiple times. If you run the script with different lengths for t, it would fail the second run. One solution would be:
t=0:0.001:10;
vs=4*sin(pi * t);
v=nan(size(t));
for i =1:length(vs)
if(vs(i)<=0.7)
v(i)=0;
else
v(i)=vs(i)-0.7;
end
end
figure;
plot(t,v);
You could also avoid the for loop and use matrix operations instead:
t=0:0.001:10;
vs=4*sin(pi * t);
v=vs-0.7;
v(vs<=0.7)=0;
figure;
plot(t,v);

(Matlab) Option to turn pause on and off from output callback of system(string)?

For an aerospace course aerelasticity I am doing an assignment with Nastran in Matlab (by using system(command) and bdf as input file).
I have attached a piece of my code as explanation. In this case the program Nastran produces a punch file (text) with displacements.
Currently the problem is that Matlab disregards the time Nastran needs for analysis to produce this punch file and continues on with the loop, however this punch file is not created yet so matlab turns out an error saying it does not exist and stops the loop.
I "have" a workaround for this by setting the pause times manually found from running it manually for increasing mesh sizes, this gives me at least some data on mesh convergence, however this is not a suitable method to use the rest of the assignment as it will take way too much time, therefore it must be automated.
I was thinking of setting a condition temporarily pausing the loop if the punch file does not exist and turning on again if it exists, however I got stuck with using a pause condition inside a while loop alltogether, it does not seem a solution to me.
Do you have any suggestions / ideas on what I could use / do how to get around this problem
or
know if there is a way to sent a callback from system(nastran) which i can use to create a condition to control the loop or something in that direction?
The following is a piece of code of the created function which turns out the Residual Mean squared error of the mesh which I use to see if the mesh converges:
%% Run Nastran
system('"C:\Users\$$$$\AppData\Roaming\MSC.Software\MSC_Nastran_Student_Edition\2014\Nastran\bin\nastranw.exe" nastranfile.bdf mem=1gb'); % Run the created bdf file
pause(15);
%% Read results and save all relevant results
fpc = fopen('nastranfile.pch','r')
line = 0;
for j=1:6;
line = line+1;
fgets(fpc);
end
line;
counter=0;
data = [];
while ~feof(fpc)
counter= counter+1;
str = fgets(fpc);
line=line+1;
str = str(61:73);
data(counter) = str2num(str)
fgets(fpc);
line=line+1;
end
line;
fclose(fpc);
% Find RMSE
mdl = fitlm(1:length(data),data);
RMEA = mdl.Rsquared.Adjusted;
RMSE = mdl.RMSE;

Looping over a Matlab structure

I am currently processing a bunch of files that I have imported into a structure, but have hit a bump in the road while trying to loop over the data.
First of all, here is my structure:
Ice
1.1 az160, az240, az300...
1.1.2 zen15, zen30,zen45...
1.1.2.1 Data
1.1.2.2 Textdata
I am trying to extract a value from each "textdata" cell array and use it to divide a column in data of the same structure. To do so, I am looping through the structure in the following way:
az_names = fieldnames(ice)
for m = 1:numel(az_names)
snames = fieldnames(ice.(az_names{m}))
for k = 1:numel(snames)
inttime = strrep(ice.(az_names{m}).(snames{k}).textdata(9,1), 'Integration > Time (usec): ','');
inttime = strrep(inttime, ' (USB2+E00040)','');
integration = cellfun(#str2num,inttime)
line 17 ice.(az_names{m}).(snames{k}).data(:,4) = ice.(az_names{m}).(snames{k}).data(:,3)/integration
end
end
I get the following error:
Index exceeds matrix dimensions
Edit: Matlab gives me the error at line 17. If I run the code up to "integration" and also write:
ice.(az_names{m}).(snames{k}).data(:,4)
I don't get a problem, Matlab prints to screen the right number and the data column.
I thought this would loop through each field in the structure and do the operation (dividing a column of values by a number), but I seem to be missing a point here. Can anybody see my mistake?
Regards,
If the error occurs when you try to execute this fragment:
ice.(az_names{m}).(snames{k}).data(:,4)
Then the cause is quite simple.
The variables m and k seem to be handled properly (due to the numel in the loop they should never be too big), meaning that the 4 is simply too big.
Check
ice.(az_names{m}).(snames{k}).data(:,4)
Or even more directly
size(ice.(az_names{m}).(snames{k}).data)
And you should find that the second element of the size is less than 4.
On second thought, this fragment works:
a.b=1;
a.b(:,4)=1
So I suspect that the error occurs when trying to read in this part:
ice.(az_names{m}). (snames{k}).data(:,3)
Meaning that the second element of the size should even be less than 3.
Also I would recommend removing the space.

Issue with assigning output from a function in MATLAB

I am having problem when I try to store rmabackadj function's output to a variable. The function works properly when no output variable is assigned. This function is part of bioinformatics toolbox.
So the issue is when I try to run the following it works properly:
rmabackadj(myprobeData.PMIntensities)
But when I try to run the following I get an error:
>> A = rmabackadj(myprobeData.PMIntensities)
Warning: Colon operands must be real scalars.
> In rmabackadj>findMaxDensity at 255
In rmabackadj at 164
Error using ksdensity>parse_args (line 162)
X must be a non-empty vector.
Error in ksdensity (line 114)
[axarg,yData,n,ymin,ymax,xispecified,xi,u,m,kernelname,...
Error in rmabackadj>findMaxDensity (line 255)
[f, x] = ksdensity(z, min(z):(max(z)-min(z))/npoints:max(z), 'kernel', 'epanechnikov');
Error in rmabackadj (line 164)
mu = findMaxDensity( o(o < mu));
I searched for it online as well, but I couldn't find any result. Does anybody have any idea about the cause of this error?
PS: When I assign ans variable to a new variable, it is properly assigned.
A = ans
I'm pretty sure this is a bug.
Firstly, the reason it errors only when you supply an output argument is because there's an internal switch in the function that calculates different things based on nargout. That's an odd design, but not necessarily a bug.
Internal to rmabackadj there are two subfunctions findMaxDensity and findMaxDensity2. The main routine calls findMaxDensity, which is supposed to find an initial guess for the parameter mu. However (when I run the documentation example that you mention in your comment), it finds a terrible guess right on the edge, leading to an error.
When I edit the file to call findMaxDensity2 rather than findMaxDensity, it seems to produce a reasonable guess, and runs fine with no error. I can't vouch for whether the guess is actually "correct", but it seems reasonable to me, and it's only functioning as an initial guess to start off a better estimation process. (NB if you do this yourself, make sure to save a copy of the old version first).
I would guess that this is a bug, either that findMaxdensity is generating an unusually poor guess that should be caught, or that really it should be calling findMaxDensity2 and the code has not been updated to call a new subfunction.
Either way, I would report it to MathWorks.
PS I am running MATLAB R2011b. Check first if the issue has been fixed, or behaves differently, in more recent versions.
Mathworks confirmed this bug and issued a work around for it and mentioned this may be fixed in future releases.
One possible workaround is to add the following conditional at line 163 of rmabackadj function
% estimate mu from left-of-the-mode data
if any(o < mu)
mu = findMaxDensity( o(o < mu));
end
The bug for N<1000 samples has been confirmed as well but no work around has been issued yet.
I will update the thread if the work around for N<1000 samples bug.

error related to white noise generation

i have a problem and please help me to fix it.suppose that we have following data
f1=100;
f2=200;
T=1./f1;
N=3;
m=500;
t=(0:(N*T)/m:(N*t))';
wn=rand(length(t),1).*2-1;
but when i tried to see value of wn,it shows me following one
0.6294
i need it for following code
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
A3 is amplitude for white noise.but main problem is follwing
1.should not wn be array instead of scalar?
2.why it shows me the same value of wn at each time i type wn?
as you see this is model of two deterministic periodic model +white noise
t=(0:(N*T)/m:(N*t))';
t is using itself in it's definition. That can't be right. I would suspect if you called clear and then run this script that line would error.