I have a very large dataset arranged into multiple structure arrays in MATLAB. The structures look something like this:
Flight1=
.testpoint = 1
.Mach = 0.8
.Speed = 300
.Cieling = 35000
.Data = [A] % A is an MxN matrix
Similarly there are multiple test points for multiple flights. Is there a way to retrieve the Data of only specified test points? For example I want to look at the Data of ALL the test points whose .Mach = 0.8 or where .testpoint = 2?
I hope I have made it clear enough.
Assuming you have a struct array Flight where Flight( k ) is a struct with the fields you described, then:
sel = [ Flight(:).Mach ] == 0.8; % select all flights with Mach == 0.8
poitEightMach = Flight( sel ); % selecting them into a separate struct array
sel = [Flight(:).testpoint] == 2;
testPoint2 = Flight( sel ); % select all flights with testpoint == 2
Related
I have an array of structures. Lets say
s(1).value, ... , s(5).value.
I have a vector of values, lets say vals = [1 2 3 4 5], that i want to assign to the array of structures. So written in pseudocode i want: s(:).value = vals.
As shown below there is a know solution. But is it really not possible to do this assignment in 1 line as in the pseudocode?
% Vector of values
vals = [1 2 3 4 5];
n = length(vals);
% Initialize struct
s(n).values = 0;
% Put vals into my struct.values
[s(1:n).values] = ???
% Known solution that i am not satisfied with:
vals_c = num2cell(vals);
[s(1:n).values] = vals_c{:};
Best regards, Jonas
It's possible to do this in one line using cell2struct in conjuction with num2cell.
% Vector of values
vals = [1 2 3 4 5];
n = length(vals);
% Put vals into my struct.values
s = cell2struct(num2cell(vals), 'values', 1)
% transpose if orientation is important
s = s.';
it's not pretty, but it does do it in one line. cell2struct supports multiple entries so you may be able to populate many fields.
The big downside is that it creates the struct from scratch, so you'd have to do a struct merge if you need to add this data to an existing struct.
Having recently gone through the same phase I thought I'd answer this one.
To create a new structure with one field:
field = 'f';
value = {'some text';
[10, 20, 30];
magic(5)};
s = struct(field,value)
Create a nonscalar structure with several fields:
field1 = 'f1'; value1 = zeros(1,10);
field2 = 'f2'; value2 = {'a', 'b'};
field3 = 'f3'; value3 = {pi, pi.^2};
field4 = 'f4'; value4 = {'fourth'};
s = struct(field1,value1,field2,value2,field3,value3,field4,value4)
Also, as I'd always suggest, going over the documentation a few times is quite necessary and useful, so there you go. https://in.mathworks.com/help/matlab/ref/struct.html
Alrighty, so I have a pretty 'simple' problem on my hands. I am given two inputs for my function: a string that gives the formula of the equation and a structure that contains the information I need and looks like this:
Name
Symbol
AtomicNumber
AtomicWeight
To find the molecular weight, I have to take all of the elements in the formula, find their total mass and add them all together. For example, let's say that I have to find the molecular weight of oxygen. The formula would look like:
H2,O
The molecular weight will thus be
2*(Hydrogen's weight) + (Oxygen's weight), which evaluates to 18.015.
There will always be a comma separating the different elements in a formula. What I am having trouble with right now, is taking the number out of the string(the formula). I feel like I'm over-complicating how I am going about extracting it. If there's a number, I know it can be in positions 2 or 3 (depending on the element name). I tried to use isnumeric, I tried to do some really weird, coding stuff (which you'll see below), but I am having difficulties.
test case:
mass5 = molarMass('C,H2,Br,C,H2,Br', table)
mass5 => 187.862
table:
Name Symbol AtomicNumber AtomicWeight
'Carbon' 'C' 6 12.0110000000000
'Hydrogen' 'H' 1 1.00800000000000
'Nitrogen' 'N' 7 14.0070000000000
'Oxygen' 'O' 8 15.9990000000000
'Phosphorus''P' 15 30.9737619980000
'Sulfur' 'S' 16 32.0600000000000
'Chlorine' 'Cl' 17 35.4500000000000
'Bromine' 'Br' 35 79.9040000000000
'Sodium' 'Na' 11 22.9897692800000
'Magnesium' 'Mg' 12 24.3050000000000
My code so far is:
function[molar_mass] = molarMass(formula, information)
Names = []; %// Creates a Name array
[~,c] = size(information); %Finds the rows and columns of the table
for i = 1:c %Reads through the columns
Molecules = getfield(information(:,i), 'Name'); %Finds the numbers in the 'Name' area
Names = [Names {Molecules}];
end
Symbols = [];
[~, c2] = size(information);
for i = 1:c2 %Reads through the columns
Symbs = getfield(information(:,i), 'Symbol'); %Finds the numbers in the 'Symbol'
Symbols = [Symbols {Symbs}];
end
AN = [];
[~, c3] = size(information);
for i = 1:c3 %Reads through the columns
Atom = getfield(information(:,i), 'AtomicNumber'); %Finds the numbers in the 'AtomicWeight' area
AN = [AN {Atom}];
end
Wt = [information(:).AtomicWeight];
formula_parts = strsplit(formula, ','); % cell array of strings
total_mass = 0;
multi = [];
atoms = [];
Indices = [];
for ipart = 1:length(formula_parts)
part = formula_parts{ipart}; % Takes in the string
isdigit = (part >= '0') & (part <= '9'); % A boolean array
atom = part(~isdigit); % Select all chars that are not digits
Indixes = find(strcmp(Symbols, atom));
Indices = [Indices {Indixes}];
mole = atom;
atoms = [atoms {mole}];
natoms = part(isdigit); % Select all chars that are digits
% Convert natoms string to numbers, default to 1 if missing
if length(natoms) == 0
natoms = '1';
multi = [multi {natoms}];
else
natoms = num2str(natoms);
multi = [multi {natoms}];
end
end
multi = char(multi);
multi = str2num(multi); %Creates a number array with my multipliers
f=56;
Molecule_Wt = Wt{Indices};
duck = 62;
total_mass = total_mass + atom_weight * multi;
end
Thanks to Bas Swinckels I can now extract the numbers from the formulas, but what I'm struggling with now is how to pull out the weights associated with the symbols. I created my own weight_chart, but strcmp won't work there. Neither will strfind or strmatch. What I want to do is find the formulas in my input, in the chart. Then index it from that index, to the column (so add 1 I believe). How do I find the indices though? I'd prefer to find them in the order the strings appear in my input, since I can then apply my 'multi' array to it.
Any help/suggestions would be appreciated :)
Given the string, you can pull out the part that is a digit character with the isstrprop function. Then use that to address your string to get just those characters, then cast that as a double with str2double.
PartialString = 'H12';
Subscript = str2double (PartialString (isstrprop (PartialString, 'digit')));
This should get you started, there is still some parts that need to be filled in:
formula_parts = strsplit(formula, ','); % cell array of strings
total_mass = 0;
for ipart = 1:length(formula_parts)
part = formula_parts{ipart}; % string like 'H2'
isdigit = isstrprop(part, 'digit'); % boolean array
atom = part(~isdigit); % select all chars that are not digits
natoms = part(isdigit); % select all chars that are digits
% convert natoms string to int, default to 1 if missing
if length(natoms) == 0
natoms = 1;
else
natoms = num2str(natoms);
end
% calculate weight
atom_weight = lookup_weight(atom); % somehow look up value in table
total_mass = total_mass + atom_weight * natoms;
end
See this old question about how to extract letters or digits from a string.
I want to find cells, which are at the same position in two different cell arrays and which have specific values.
The two cell arrays have the following structure:
cell array C1= cell(20,1). In each cell there is another cell cell(8129,8) holding double values in the range of [0,1].
Cell array C2= cell(20,1). In each cell there is another cell cell(8192,8) also holding double values in the range of [0,1].
I know want to find those cells, which (1) have a specific value that I determine (e.g. C1_value = 0.8 and C2_value = 0.85) and (2) are at the same position in the respective sub cell (!) array (e.g. C1{2}(736) == 0.8 and C2(19)(736) == 0.85). NOTE: The same position only refers to the subcell arrays (cell(8192,8)) not the "main" cell arrays C1(:) and C2(:)
Thanks in advance!
See if this approach works for you -
sz = cell2mat(cellfun(#size,C1(1),'uni',0))
row1 = sz(1);
col1 = sz(2);
t1 = reshape(horzcat(C1{:}),row1,col1,[])
t2 = reshape(horzcat(C2{:}),row1,col1,[])
b1 = t1==C1_value
b2 = t2==C2_value
tt1 = reshape(b1,row1*col1,[])' %//'
tt2 = reshape(b2,row1*col1,[])' %//'
tt22 = permute(tt2,[3 2 1])
tt3 = bsxfun(#and,tt1,tt22)
[C1_cellnum,subcellnum,C2_cellnum] = ind2sub(size(tt3),find(tt3)) %// outputs
Thus, with your sample data, you must have -
C1_cellnum as 2, C2_cellnum as 19 and subcellnum as 736.
I have two array, the first one is data_array(50,210), the second one is dest_array(210,210). The goal, using data from data_array to calculate the values of dest_array at specific indicies, without using for-loop.
I do it in such way:
function [ out ] = grid_point( row,col,cg_row,cg_col,data,kernel )
ker_len2 = floor(length(kernel)/2);
op1_vals = data((row - ker_len2:row + ker_len2),(col - ker_len2:col + ker_len2));
out(cg_row,cg_col) = sum(sum(op1_vals.*kernel)); %incorre
end
function [ out ] = sm(dg_X, dg_Y)
%dg_X, dg_Y - arrays of size 210x210, the values - coordinates of data in data_array,
%index of each element - position this data at 210x210 grid
data_array = randi(100,50,210); %data array
kernel = kernel_sinc2d(17,'hamming'); %sinc kernel for calculations
ker_len2 = floor(length(kernel)/2);
%adding the padding for array, to avoid
%the errors related to boundaries of data_array
data_array = vertcat(data_array(linspace(ker_len2+1,2,ker_len2),:),...
data_array,...
data_array(linspace(size(data_array,1)-1,size(data_array,1) - ker_len2,ker_len2),:));
data_array = horzcat(data_array(:,linspace(ker_len2+1,2,ker_len2)),...
data_array,...
data_array(:,linspace(size(data_array,2)-1,(size(data_array,2) - ker_len2,ker_len2)));
%cg_X, cg_Y - arrays of indicies for X and Y directions
[cg_X,cg_Y] = meshgrid(linspace(1,210,210),linspace(1,210,210));
%for each point at grid(210x210) formed by cg_X and cg_Y,
%we should calculate the value, using the data from data_array(210,210).
%after padding, data_array will have size (50 + ker_len2*2, 210 + ker_len2*2)
dest_array = arrayfun(#(y,x,cy,cx) grid_point(y, x, cy, cx, data_array, kernel),...
dg_Y, dg_X, cg_Y, cg_X);
end
But, it seems that arrayfun cannot resolve my problem, because I use arrays with different sizes. Have somebody the ideas of this?
I am not completely sure, but judging from the title, this may be what you want:
%Your data
data_array_small = rand(50,210)
data_array_large = zeros(210,210)
%Indicating the points of interest
idx = randperm(size(data_array_large,1));
idx = idx(1:size(data_array_small,1))
%Now actually use the information:
data_array_large(idx,:) = data_array_small
Say for n=5, the following code gives me a plot for n randomly generated nodes. These nodes are not structures (just plotted points), but I want to assign every node a message just as I did for sink and source and keep track of the nodes identity and location.
For example, if node 4 has (x,y) coordinates (.3452 , .5463), I want to assign node 4 a msg and temp_value as well. How can I do this?
Code:
n = input('No. of Nodes:');
sink = [0 0];
source = [1 1];
node = rand(n,2)
x = node(:,1);
y = node(:,2);
x1 = sink(:,1);
y1 = sink(:,1);
x2 = source(:,1);
y2 = source(:,1);
plot(x,y,'o')
hold on
plot(x1,y1,'r*')
hold on
plot(x2,y2,'r*')
hold on
sink = struct;
sink.msg = 'temp';
sink.temp_value = '30'
source = struct;
source.msg = 'temp';
source.temp_value = '30'
I would suggest creating an array of structures that stores all of the data associated with each "node". You can create all of the data for your nodes with one call to STRUCT in the following way:
N = 5; %# Number of nodes
coords = num2cell(rand(N,2)); %# Cell array of random x and y coordinates
nodes = struct('x',coords(:,1),... %# Assign x coordinates
'y',coords(:,2),... %# Assign y coordinates
'message','temp',... %# Assign default message
'value',30); %# Assign default value
The variable nodes is an N-by-1 structure array with fields x, y, message, and value. You can access and modify the data using the usual array and field indexing:
>> nodes(1) %# Contents of node 1
ans =
x: 0.4387
y: 0.4898
message: 'temp'
value: 30
>> nodes(1).message %# Message for node 1
ans =
temp
>> nodes(1).message = 'hello world!'; %# Change message for node 1
You can then plot the nodes in the following way:
plot([nodes.x],[nodes.y],'r*'); %# Plot all the nodes in red
index = randi(N,[1 2]); %# Pick two nodes at random
hold on;
plot([nodes(index).x],[nodes(index).y],'b*'); %# Plot 2 random nodes in blue