How can I modify a list of existing variables programmatically?

2 vues (au cours des 30 derniers jours)
Alvin Allen
Alvin Allen le 20 Sep 2023
Commenté : Alvin Allen le 20 Sep 2023
I've been given a set of recorded data for a bunch of signals, for example the list of column vectors "a", "b", "c", "d", "e" in a mat file. I know the names of the variables are a, b, c, d, e. In order for these recorded signals to be useful to me, I need to prepend them with a known vector of sample times, for example [1; 2; 3; 4; 5]. So as an example, I could manually do this operation like this:
load("recordedVars.mat"); % suppose this gives a = [2; 4; 6; 8; 10] as recorded data and something similar for b, c, d, e
times = [1; 2; 3; 4; 5]; % known vector of times to assign to each variable
a = [times, a];
b = [times, b];
c = [times, c];
d = [times, d];
e = [times, e];
Is there a programmatic way to do this job to scale up for more than 5 variables? In pseudocode what I'm imagining is:
Load Data
For each name in list of names
assign name = [times, name]
End
Is it possible to iterate on variable names in this way?
My actual application involes going on to use the modified a,b,c,d,e by loading them into simulink via "From Workspace" blocks with the given names, so I don't think assigining a bunch of new variables would save work.

Réponses (2)

Walter Roberson
Walter Roberson le 20 Sep 2023
Please read http://www.mathworks.com/matlabcentral/answers/304528-tutorial-why-variables-should-not-be-named-dynamically-eval for information about why we strongly recommend against creating variable names dynamically.
It is possible -- but it error prone and difficult to debug. I would say that you should not consider using it in your own code unless (at the very least) you can identify the problems with the code at https://www.mathworks.com/matlabcentral/answers/2020976-i-want-to-store-the-vector-from-each-for-loop-iteration-how-can-i-do-this#answer_1310391
  3 commentaires
Walter Roberson
Walter Roberson le 20 Sep 2023
load("recordedVars.mat"); % suppose this gives a = [2; 4; 6; 8; 10] as recorded data and something similar for b, c, d, e
That command "poofs" variables into the workspace. Instead use
varstruct = load("recordedVars.mat");
Then varstruct would be a struct with one field for each variable loaded. You can then use dynamic field names,
fn = fieldnames(varstruct);
times = varstruct.times;
fn = setdiff(fn, 'times');
for K = 1 : length(fn)
thisdata = varstruct.(fn{K});
thisdata = [times, thisdata];
assignin('base', 'DataToLoad', thisdata);
sim(....)
end
where the model uses From Workspace to load DataToLoad
Steven Lord
Steven Lord le 20 Sep 2023
If you must do this, call load with an output argument. Iterate over the fieldnames of the struct that load returns and use dynamic field names to access those fields. This allows you to avoid having an unknown number of variables with unknown names (which could potentially overwrite existing variables) in your workspace.
data = load('census.mat')
data = struct with fields:
cdate: [21×1 double] pop: [21×1 double]
f = fieldnames(data) % variables in the MAT-file
f = 2×1 cell array
{'cdate'} {'pop' }
for whichvar = 1:numel(f)
name = f{whichvar};
thevar = data.(name); % dynamic field names
sz = mat2str(size(thevar));
fprintf("Variable %s from census.mat has size %s.\n", name, sz)
end
Variable cdate from census.mat has size [21 1]. Variable pop from census.mat has size [21 1].
If I'd had a variable named pop in my workspace and tried to load this MAT-file, the variable would have been overwritten as you can with the example below.
pop = 42 % The Answer to Life, the Universe, and Everything
pop = 42
load('census.mat')
pop % No longer the Answer
pop = 21×1
3.9000 5.3000 7.2000 9.6000 12.9000 17.1000 23.1000 31.4000 38.6000 50.2000

Connectez-vous pour commenter.


the cyclist
the cyclist le 20 Sep 2023
You've seen @Walter Roberson's answer, and it is spot-on. That being said, what you want to do is possible, using the appropriately-reviled eval function. Here is a miniature version of what you want to do:
times = [1;2;3];
a = [2;3;5];
b = [7;11;13];
varList = ["a","b"];
for v = varList
eval(v+" = [times, "+v+"];");
end
You can see even in this small example how ugly and error-prone coding like this can be.
  2 commentaires
the cyclist
the cyclist le 20 Sep 2023
An arguably cleaner variant of this solution is to write out the string you want executed using the sprintf function:
times = [1;2;3];
a = [2;3;5];
b = [7;11;13];
varList = ["a","b"];
for v = varList
eval(sprintf("%s = [times, %s];",v,v));
end
But, from experience I know that folks sometimes have a difficult time grokking sprintf, so I didn't want to only use that as a solution.
Alvin Allen
Alvin Allen le 20 Sep 2023
Yep, that is ugly! Thanks though

Connectez-vous pour commenter.

Produits


Version

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by