Looking for a more efficient way of writing my MATLAB code - matlab

I have written in MATLAB the following
for i = 1:3
alpha11(i) = b+a.*randn(1,1);
alpha22(i) = b+a.*randn(1,1);
alpha12(i) = b+a.*randn(1,1);
alpha21(i) = b+a.*randn(1,1);
AoD11(i) = randi([-180/6 +180/6],1,1);
AoA11(i) = randi([-180/6 +180/6 ],1,1);
AoD22(i) = randi([-180/6 +180/6],1,1);
AoA22(i) = randi([-180/6 +180/6 ],1,1);
AoD21(i) = randi([-180 +180],1,1);
AoA21(i) = randi([-180 +180 ],1,1);
AoD12(i) = randi([-180 +180],1,1);
AoA12(i) = randi([-180 +180 ],1,1);
ctet11(i)= ((2*pi)/lambda)*d*sin(AoD11(i));
ctet22(i)= ((2*pi)/lambda)*d*sin(AoD22(i));
ctet12(i)= ((2*pi)/lambda)*d*sin(AoD12(i));
ctet21(i)= ((2*pi)/lambda)*d*sin(AoD21(i));
f_t11_ula{i}=transpose((1/sqrt(M))*[ 1 exp(j*ctet11(i)) exp(j*2*ctet11(i)) exp(j*3*ctet11(i)) ]);
f_t22_ula{i}=transpose((1/sqrt(M))*[ 1 exp(j*ctet22(i)) exp(j*2*ctet22(i)) exp(j*3*ctet22(i)) ]);
f_t12_ula{i}=transpose((1/sqrt(M))*[ 1 exp(j*ctet12(i)) exp(j*2*ctet12(i)) exp(j*3*ctet12(i)) ]);
f_t21_ula{i}=transpose((1/sqrt(M))*[ 1 exp(j*ctet21(i)) exp(j*2*ctet21(i)) exp(j*3*ctet21(i)) ]);
cter11(i)= ((2*pi)/lambda)*d*sin(AoA11(i));
cter22(i)= ((2*pi)/lambda)*d*sin(AoA22(i));
cter12(i)= ((2*pi)/lambda)*d*sin(AoA12(i));
cter21(i)= ((2*pi)/lambda)*d*sin(AoA21(i));
f_r11_ula{i}=transpose((1/sqrt(O))*[ 1 exp(j*cter11(i)) exp(j*2*cter11(i)) exp(j*3*cter11(i)) ]);
f_r22_ula{i}=transpose((1/sqrt(O))*[ 1 exp(j*cter22(i)) exp(j*2*cter22(i)) exp(j*3*cter22(i))]);
f_r12_ula{i}=transpose((1/sqrt(O))*[ 1 exp(j*cter12(i)) exp(j*2*cter12(i)) exp(j*3*cter12(i)) ]);
f_r21_ula{i}=transpose((1/sqrt(O))*[ 1 exp(j*cter21(i)) exp(j*2*cter21(i)) exp(j*3*cter21(i))]);
channel11{i}= alpha11(i) * f_r11_ula{i}* conj(transpose(f_t11_ula{i})) ;
channel22{i}= alpha22(i) * f_r22_ula{i}* conj(transpose(f_t22_ula{i})) ;
channel12{i}= alpha12(i) * f_r12_ula{i}* conj(transpose(f_t12_ula{i})) ;
channel21{i}= alpha21(i) * f_r21_ula{i}* conj(transpose(f_t21_ula{i})) ;
end
I am writing this question here to ask how I can compress this code, as you can see its not very nicely written and I have basically many repetitions. I don't know how to write them in few commands. Every command is repeated four times and indexed by 11, 12, 21, 22..
P.S If someone wants to run the code the following variables are needed
a = 1;
b = 0;
M=4;
O = 4;
lambda=0.15;
d=lambda/2;
Looking forward for suggestions.

As #David mentioned, it can be done using 3D arrays. This removes much of the code repetition.
Here is an example of how it could be done:
sz=[2,2,3];
alpha=b+a.*randn(sz);
AoD = randi([-180/6 +180/6],sz);
AoA = randi([-180 +180],sz);
mask = logical(repmat(eye(2),1,1,3));
[AoA(mask), AoD(~mask)] = deal(AoD(~mask),AoA(mask));
ctet = 2*pi/lambda * d * sin(AoD);
f_t = reshape(arrayfun(#(x) exp(1j*(0:3)'*ctet(x))/sqrt(M),1:12,'UniformOutput',0),sz);
cter = (2*pi)/lambda*d*sin(AoA);
f_r = reshape(arrayfun(#(x) exp(1j*(0:3)'*cter(x))/sqrt(O),1:12,'UniformOutput',0),sz);
channel = reshape(arrayfun(#(x) alpha(x) * f_r{x} * conj(transpose(f_t{x})), 1:12, 'UniformOutput',0),sz);
Note that for each of the variables mentioned in the question, the same values can be accessed using the corresponding 3D index. For example, using the code above, the value that was previously in AoA11(1) is now in AoA(1,1,1). Similarly, the matrix that was stored in channel11{1} is now in channel{1,1,1}.
Hope this helps.

Related

Extract fields from Structure Array to put into another Structure Array

I have a structure array with a large number of fields that I don't care about, so I want to extract the limited number of fields I DO care about and put it into a separate structure array.
For a structure array of size one, I've done this by creating the new array from scratch, for example:
structOld.a = 1;
structOld.b = 2;
structOld.usefulA = 'useful information';
structOld.usefulB = 'more useful information';
structOld.c = 3;
structOld.d = 'words';
keepFields = {'usefulA','usefulB'};
structNew = struct;
for fn = keepFields
structNew.(fn{:}) = structOld.(fn{:});
end
which gives
structNew =
usefulA: 'useful information'
usefulB: 'more useful information'
Is there a more efficient way of doing this? How can I scale up to an structure array (vector) of size N?
N = 50;
structOld(1).a = 1;
structOld(1).b = 2;
structOld(1).usefulA = 500;
structOld(1).usefulB = 'us';
structOld(1).c = 3;
structOld(1).d = 'ef';
structOld(2).a = 4;
structOld(2).b = 5;
structOld(2).usefulA = 501;
structOld(2).usefulB = 'ul';
structOld(2).c = 6;
structOld(2).d = 'in';
structOld(3).a = 7;
structOld(3).b = '8';
structOld(3).usefulA = 504;
structOld(3).usefulB = 'fo';
structOld(3).c = 9;
structOld(3).d = 'rm';
structOld(N).a = 10;
structOld(N).b = 11;
structOld(N).usefulA = 506;
structOld(N).usefulB = 'at';
structOld(N).c = 12;
structOld(N).d = 'ion';
In this case, I'd like to end up with:
structNew =
1x50 struct array with fields:
usefulA
usefulB
Keeping elements with empty usefulA/usefulB fields is fine; I can get rid of them later if needed.
Using rmfield isn't great because the number of useless fields far outnumbers the useful fields.
You can create a new struct array using existing data as follows:
structNew = struct('usefulA',{structOld.usefulA},'usefulB',{structOld.usefulB});
If you have an arbitrary set of field names that you want to preserve, you could use a loop as follows. Here, I'm first extracting the data from strcutOld into a cell array data, which contains each of the arguments the the struct call in the previous line of code. data{:} is now a comma-separated list of these arguments, the last line of code below is identical to the line above.
keepFields = {'usefulA','usefulB'};
data = cell(2,numel(keepFields));
for ii=1:numel(keepFields)
data{1,ii} = keepFields{ii};
data{2,ii} = {structOld.(keepFields{ii})};
end
structNew = struct(data{:});

Extraction of data from DWT subband

I am attempting to extract data from a DWT subband. I am able to embed data correctly (I have followed it in the debugger),cal PSNR etc. PSNR rate seem very high 76.2?? however,I am having lot of trouble extracting data back!It is sometimes extracting the number 128?? Can anyone help or have any idea why this is? I would be very thankful.I have been working on this all day & having no luck!I am very curious to know??
Data Embedding:
coverImage = imread('lena.bmp');
message = importdata('minutiaTest.txt');
%message = 'Bifurcations:';
[LL,LH,HL,HH] = dwt2(coverImage,'haar');
if size(message) > size(coverImage,1) * size(coverImage,2)
error ('message too big to embed');
end
bit_count = 0;
steg_coeffs = [4, 4.75, 5.5, 6.25, 7];
for jj=1:size(message,2)+1
if jj > size(message,2)
charbits = [0,0,0,0,0,0,0,0];
else
charbits = dec2bin(message(jj),8)';
charbits = charbits(:)'-'0';
end
for ii=1:8
bit_count = bit_count + 1;
if charbits(ii) == 1
if HH(bit_count) <= 0
HH(bit_count) = steg_coeffs(randi(numel(steg_coeffs)));
end
else
if HH(bit_count) >= 0
HH(bit_count) = -1 * steg_coeffs(randi(numel(steg_coeffs)));
end
end
end
end
stego_image = idwt2(LL,LH,HL,HH,'haar');
imwrite(uint8(stego_image),'newStego.bmp');
Data Extraction:
new_Stego = imread('newStego.bmp');
[LL,LH,HL,HH] = dwt2(new_Stego,'haar');
message = '';
msgbits = '';
for ii = 1:size(HH,1)*size(HH,2)
if HH(ii) > 0
msgbits = strcat (msgbits, '1');
elseif HH(ii) < 0
msgbits = strcat (msgbits, '0');
else
return;
end
if mod(ii,8) == 0
msgChar = bin2dec(msgbits);
if msgChar == 0
break;
end
msgChar = char (msgChar);
message = [message msgChar];
msgbits = '';
end
end
The problem arises from reading your data with importdata.
This command will load the data to an array. Since you have 39 lines and 2 columns (skipping any empty lines), its size will be 39 2. However, the program assumes that your message will be a string. For example, 'i am a string' has a size 1 13. This expectation of the program compared to the data you actually give it creates all sorts of problems.
What you want is to read your data as a single string, where the number 230 is not one element, but 3 individual characters. Tabs and newlines will also be read in as well.
To read your file:
message = fileread('minutiaTest.txt');
After you extract your message, to save it to a file:
fid = fopen('myFilename.txt','w');
fprintf(fid,message);
fclose(fid);

MATLAB Execution Time Increasing

Here is my code. The intent is I have a Wireshark capture saved to a particularly formatted text file. The MATLAB code is supposed to go through the Packets, dissect them for different protocols, and then make tables based on those protocols. I currently have this programmed for ETHERNET/IP/UDP/MODBUS. In this case, it creates a column in MBTable each time it encounters a new register value, and each time it comes across a change to that register value, it updates the value in that line of the table. The first column of MBTable is time, the registers start with the second column.
MBTable is preallocated to over 100,000 Rows (nol is very large), 10 columns before this code is executed. The actual data from a file I'm pulling into the table gets to about 10,000 rows and 4 columns and the code execution is so slow I have to stop it. The tic/toc value is calculated every 1000 rows and continues to increase exponentially with every iteration. It is a large loop, but I can't see where anything is growing in such a way that it would cause it to run slower with each iteration.
All variables get initialized up top (left out to lessen amount of code.
The variables eth, eth.ip, eth.ip.udp, and eth.ip.udp.modbus are all of type struct as is eth.header and eth.ip.header. WSID is a file ID from a .txt file opened earlier.
MBTable = zeros(nol,10);
tval = tic;
while not(feof(WSID))
packline = packline + 1;
fl = fl + 1;
%Get the next line from the file
MBLine = fgetl(WSID);
%Make sure line is not blank or short
if length(MBLine) >= 3
%Split the line into 1. Line no, 2. Data, 3. ASCII
%MBAll = strsplit(MBLine,' ');
%First line of new packet, if headers included
if strcmp(MBLine(1:3),'No.')
newpack = true;
newtime = false;
newdata = false;
stoppack = false;
packline = 1;
end
%If packet has headers, 2nd line contains timestamp
if newpack
Ordered = false;
if packline == 2;
newtime = true;
%MBstrs = strsplit(MBAll{2},' ');
packno = int32(str2double(MBLine(1:8)));
t = str2double(MBLine(9:20));
et = t - lastt;
if lastt > 0 && et > 0
L = L + 1;
MBTable(L,1) = t;
end
%newpack = false;
end
if packline > 3
dataline = int16(str2double(MBLine(1:4)));
packdata = strcat(packdata,MBLine(7:53));
end
end
else
%if t >= st
if packline > 3
stoppack = true;
newpack = false;
end
if stoppack
invalid = false;
%eth = struct;
eth.pack = packdata(~isspace(packdata));
eth.length = length(eth.pack);
%Dissect the packet data
eth.stbyte = 1;
eth.ebyte = eth.length;
eth.header.stbyte = 1;
eth.header.ebyte = 28;
%Ethernet Packet Data
eth.header.pack = eth.pack(eth.stbyte:eth.stbyte+27);
eth.header.dest = eth.header.pack(eth.header.stbyte:eth.header.stbyte + 11);
eth.header.src = eth.header.pack(eth.header.stbyte + 12:eth.header.stbyte + 23);
eth.typecode = eth.header.pack(eth.header.stbyte + 24:eth.header.ebyte);
if strcmp(eth.typecode,'0800')
eth.type = 'IP';
%eth.ip = struct;
%IP Packet Data
eth.ip.stbyte = eth.header.ebyte + 1;
eth.ip.ver = eth.pack(eth.ip.stbyte);
%IP Header length
eth.ip.header.length = 4*int8(str2double(eth.pack(eth.ip.stbyte+1)));
eth.ip.header.ebyte = eth.ip.stbyte + eth.ip.header.length - 1;
%Differentiated Services Field
eth.ip.DSF = eth.pack(eth.ip.stbyte + 2:eth.ip.stbyte + 3);
%Total IP Packet Length
eth.ip.length = hex2dec(eth.pack(eth.ip.stbyte+4:eth.ip.stbyte+7));
eth.ip.ebyte = eth.ip.stbyte + max(eth.ip.length,46) - 1;
eth.ip.pack = eth.pack(eth.ip.stbyte:eth.ip.ebyte);
eth.ip.ID = eth.pack(eth.ip.stbyte+8:eth.ip.stbyte+11);
eth.ip.flags = eth.pack(eth.ip.stbyte+12:eth.ip.stbyte+13);
eth.ip.fragoff = eth.pack(eth.ip.stbyte+14:eth.ip.stbyte+15);
%Time to Live
eth.ip.ttl = hex2dec(eth.pack(eth.ip.stbyte+16:eth.ip.stbyte+17));
eth.ip.typecode = eth.pack(eth.ip.stbyte+18:eth.ip.stbyte+19);
eth.ip.checksum = eth.pack(eth.ip.stbyte+20:eth.ip.stbyte+23);
%eth.ip.src = eth.pack(eth.ip.stbyte+24:eth.ip.stbyte+31);
eth.ip.src = ...
[num2str(hex2dec(eth.pack(eth.ip.stbyte+24:eth.ip.stbyte+25))),'.', ...
num2str(hex2dec(eth.pack(eth.ip.stbyte+26:eth.ip.stbyte+27))),'.', ...
num2str(hex2dec(eth.pack(eth.ip.stbyte+28:eth.ip.stbyte+29))),'.', ...
num2str(hex2dec(eth.pack(eth.ip.stbyte+30:eth.ip.stbyte+31)))];
eth.ip.dest = ...
[num2str(hex2dec(eth.pack(eth.ip.stbyte+32:eth.ip.stbyte+33))),'.', ...
num2str(hex2dec(eth.pack(eth.ip.stbyte+34:eth.ip.stbyte+35))),'.', ...
num2str(hex2dec(eth.pack(eth.ip.stbyte+36:eth.ip.stbyte+37))),'.', ...
num2str(hex2dec(eth.pack(eth.ip.stbyte+38:eth.ip.stbyte+39)))];
if strcmp(eth.ip.typecode,'11')
eth.ip.type = 'UDP';
eth.ip.udp.stbyte = eth.ip.stbyte + 40;
eth.ip.udp.src = hex2dec(eth.pack(eth.ip.udp.stbyte:eth.ip.udp.stbyte + 3));
eth.ip.udp.dest = hex2dec(eth.pack(eth.ip.udp.stbyte+4:eth.ip.udp.stbyte+7));
eth.ip.udp.length = hex2dec(eth.pack(eth.ip.udp.stbyte+8:eth.ip.udp.stbyte+11));
eth.ip.udp.checksum = eth.pack(eth.ip.udp.stbyte+12:eth.ip.udp.stbyte+15);
eth.ip.udp.protoID = eth.pack(eth.ip.udp.stbyte+20:eth.ip.udp.stbyte+23);
if strcmp(eth.ip.udp.protoID,'0000')
eth.ip.udp.proto = 'MODBUS';
%eth.ip.udp.modbus = struct;
eth.ip.udp.modbus.stbyte = eth.ip.udp.stbyte+16;
eth.ip.udp.modbus.transID = eth.pack(eth.ip.udp.modbus.stbyte:eth.ip.udp.modbus.stbyte+3);
eth.ip.udp.modbus.protoID = eth.ip.udp.protoID;
eth.ip.udp.modbus.length = int16(str2double(eth.pack(eth.ip.udp.modbus.stbyte + 8:eth.ip.udp.modbus.stbyte + 11)));
eth.ip.udp.modbus.UID = eth.pack(eth.ip.udp.modbus.stbyte + 12:eth.ip.udp.modbus.stbyte + 13);
eth.ip.udp.modbus.func = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte + 14:eth.ip.udp.modbus.stbyte+15));
eth.ip.udp.modbus.register = eth.pack(eth.ip.udp.modbus.stbyte + 16: eth.ip.udp.modbus.stbyte+19);
%Number of words to a register, or the number of registers
eth.ip.udp.modbus.words = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte+20:eth.ip.udp.modbus.stbyte+23));
eth.ip.udp.modbus.bytes = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte+24:eth.ip.udp.modbus.stbyte+25));
eth.ip.udp.modbus.data = eth.pack(eth.ip.udp.modbus.stbyte + 26:eth.ip.udp.modbus.stbyte + 26 + 2*eth.ip.udp.modbus.bytes - 1);
%If func 16 or 23, loop through data/registers and add to table
if eth.ip.udp.modbus.func == 16 || eth.ip.udp.modbus.func == 23
stp = eth.ip.udp.modbus.bytes*2/eth.ip.udp.modbus.words;
for n = 1:stp:eth.ip.udp.modbus.bytes*2;
%Check for existence of register as a key?
if ~isKey(MBMap,eth.ip.udp.modbus.register)
MBCol = MBCol + 1;
MBMap(eth.ip.udp.modbus.register) = MBCol;
end
MBTable(L,MBCol) = hex2dec(eth.ip.udp.modbus.data(n:n+stp-1));
eth.ip.udp.modbus.register = dec2hex(hex2dec(eth.ip.udp.modbus.register)+1);
end
lastt = t;
end
%If func 4, make sure it is the response, then put
%data into table for register column
elseif false
%need code to handle serial to UDP conversion box
else
invalid = true;
end
else
invalid = true;
end
else
invalid = true;
end
if ~invalid
end
end
%end
end
%Display Progress
if int64(fl/1000)*1000 == fl
for x = 1:length(mess);
fprintf('\b');
end
%fprintf('Lines parsed: %i',fl);
mess = sprintf('Lines parsed: %i / %i',fl,nol);
fprintf('%s',mess);
%Check execution time - getting slower:
%%{
ext = toc(tval);
mess = sprintf('\nExecution Time: %f\n',ext);
fprintf('%s',mess);
%%}
end
end
ext = toc - exst;
Update: I updated my code above to remove the overloaded operators (disp and lt were replaced with mess and lastt)
Was asked to use the profiler, so I limited to 2000 lines in the table (added && L >=2000 to the while loop) to limit the execution time, and here are the top results from the profiler:
SGAS_Wireshark_Parser_v0p7_fulleth 1 57.110 s 9.714 s
Strcat 9187 29.271 s 13.598 s
Blanks 9187 15.673 s 15.673 s
Uigetfile 1 12.226 s 0.009 s
uitools\private\uigetputfile_helper 1 12.212 s 0.031 s
FileChooser.FileChooser>FileChooser.show 1 12.085 s 0.006s
...er>FileChooser.showPeerAndBlockMATLAB 1 12.056 s 0.001s
...nChooser>FileOpenChooser.doShowDialog 1 12.049 s 12.049 s
hex2dec 44924 2.944 s 2.702 s
num2str 16336 1.139 s 0.550 s
str2double 17356 1.025 s 1.025 s
int2str 16336 0.589 s 0.589 s
fgetl 17356 0.488 s 0.488 s
dec2hex 6126 0.304 s 0.304 s
fliplr 44924 0.242 s 0.242 s
It appears to be strcat calls that are doing it. I only explicitly call strcat on one line. Are some of the other string manipulations I'm doing calling strcat indirectly?
Each loop should be calling strcat the same number of times though, so I still don't understand why it takes longer and longer the more it runs...
also, hex2dec is called a lot, but is not really affecting the time.
But anyway, are there any other methods I can use the combine the strings?
Here is the issue:
The string (an char array in MATLAB) packdata was being resized and reallocated over and over again. That's what was slowing down this code. I did the following steps:
I eliminated the redundant variable packdata and now only use eth.pack.
I preallocated eth.pack and a couple "helper variables" of known lengths by running blanks ONCE for each before the loop ever starts
eth.pack = blanks(604);
thisline = blanks(47);
smline = blanks(32);
(Note: 604 is the maximum possible size of packdata based on headers + MODBUS protocol)
Then I created a pointer variable to point to the location of the last char written to packdata.
pptr = 1;
...
dataline = int16(str2double(MBLine(1:4)));
thisline = MBLine(7:53); %Always 47 characters
smline = [thisline(~isspace(thisline)),blanks(32-sum(~isspace(thisline)))]; %Always 32 Characters
eth.pack(pptr:pptr+31) = smline;
pptr = pptr + 32;
The above was inside the 'if packline > 3' block in place of the 'packdata =' statement, then at the end of the 'if stoppack' block was the reset statement:
pptr = 1; %Reset Pointer
FYI, not surprisingly this brought out other flaws in my code which I've mostly fixed but still need to finish. Not a big issue now as this loop executes lightning fast with these changes. Thanks to Yvon for helping point me in the right direction.
I kept thinking my huge table, MBTable was the issue... but it had nothing to do with it.

How to have infinite path segments using Sinatra

Lets say that I want to have unlimited path segements and have the get multiply them together such that:
get "/multiply/num1/num2/num3......" do
num1 = params[:num1].to_i
num2 = params[:num2].to_i
....
solution = num1 * num2 * ....
"the solution is = #{solution}"
end
I want the user to be able to type out as many path segments as they want and then get the solution for those numbers multiplied together.
I have found a way to do it:
get "/multiply/*" do
n = params[:splat][0].split('/')
for i in (0...n.length)
n[i] = n[i].to_f
end
n = n.inject{ |sum, n| sum * n }
"solution = #{n}"
end

How to programatically construct a large cell array

How could I construct automatically a dataset like the one below, assuming that the number of columns of matrix summary_whts is approx. 400???
lrwghts = dataset(...
{summary_whts(:,01),'w00'},...
{summary_whts(:,02),'w01'},...
{summary_whts(:,03),'w02'},...
{summary_whts(:,04),'w03'},...
{summary_whts(:,05),'w04'},...
{summary_whts(:,06),'w05'},...
{summary_whts(:,07),'w06'},...
{summary_whts(:,08),'w07'},...
{summary_whts(:,09),'w08'},...
{summary_whts(:,10),'w09'},...
{summary_whts(:,11),'w10'},...
{summary_whts(:,12),'w11'},...
'ObsNames',summary_mthd);
Why not use a simple loop to populate dataset?
nCols = size(summary_whts,1);
dataset = cell(nCols, 2);
for i = 1:nCols
dataset{i,1} = summary_whts(:,i);
dataset{i,2} = sprintf('w%04d', i);
end
dataset{end+1,1} = 'ObsNames';
dataset(end, 2} = summary_mthd;
At last, I found it! This is what I was looking for:
cat = [];
for i = 0:(size(X,2)),
cat = [cat;sprintf('w%03d',i)];
end
cat = cellstr(cat);
lrwghts = dataset({summary_whts,cat{:}},'ObsNames',cellstr(summary_mthd));