How to output and name variables generated in 'for' loop into workspace.

Wrote a little function to generate random frequency sine tones. I would like each tone generated to be output into the workspace as a variable with name determined by output and input arguments and randomly generated variables (namely, tone freqency). I figured how to put the generated tones into a cell, but that's not what I want; I just want the simple, discrete audio vectors (1 x Nsamples), etc.
Comment lines in the code below explain what I'm trying to achieve a bit further. I KNOW this is a very simple thing, but the solution escapes me, and I'm not sure where to look in the documentation.
Thanks in advance!
function [Signal] = SineWave(Flower, Fupper, Amp, Fs, Time, NumTones)
% Random frequency sine tone generator ...
% Generates a specified number of sine tones at specified length and
% amplitude with random frequency values within specified upper and lower limits.
for i = 1 : NumTones
Frequency = randi([Flower Fupper]);
t = 0:1/Fs:Time;
Signal = Amp * sin(2*pi*Frequency*t);
sound(Signal, Fs)
pause(Time)
% ADD LINES TO OUTPUT EACH TONE GENERATED AS 'Signal(Frequency)_i'
% Output variables named according to the [Signal] output argument followed by the randomly generated
% frequency value and number (i). For example, for five random sine tones (NumTones), five variables should be outputted named thusly:
% 'Signal250_1' 'Signal440_2' 'Signal1000_3' 'Signal330_4' 'Signal2500_5'
end

1 commentaire

"I KNOW this is a very simple thing..."
Not really.
"...but the solution escapes me, and I'm not sure where to look in the documentation"
Start by reading this documentation:
in particular the section that states "A frequent use of the eval function is to create sets of variables such as A1, A2, ..., An, but this approach does not use the array processing power of MATLAB and is not recommended. The preferred method is to store related data in a single array."

Connectez-vous pour commenter.

 Réponse acceptée

Can you define variables with numbered names like Tone200_1, Tone400_2, etc, ... ? Yes.

6 commentaires

I had actually come across that page, but couldn't see exactly how it could solve my issue (admittedly, I did hurry over it). So would a better solution be to have the variables outputted to a cell, then extract the individual tones/audio vectors with indexing? Could that process be incorporated into the 'for' loop to output named variables extracted from the cell (but that seems terribly inefficient to me)? Or is my only option to extract each tone from the cell with indexing (but that doesn't give me its frequency). So like ...
OutputTone1 = ToneCell{1,1};
OutputTone2 = ToneCell{1,2};
% ... and so on.
A different way of describing what I want to achieve is to have each resultant tone labelled with its randomly generated frequency. Is that possible to achieve inside a cell? Can each tone's position in the cell be "labelled" with its frequency?
So, I guess I'm asking two things. But I can more than happily leave dynamic variable naming behind if there's another way to have the frequency attached to/labelling each tone (within a cell or not). Could row 2 of the cell have the frequency under each tone, for example, so I know which randomly generated frequency corresponds to which tone.
Many thanks in advance.
Mohammad Sami
Mohammad Sami le 10 Oct 2020
Modifié(e) : Mohammad Sami le 10 Oct 2020
Yes as Steven explained, it's not a good idea to dynamically name variables. two of the ways you can "label" the signals. You can put the signal in column one and the corresponding frequency value in column two. Or you can have a separate frequency variable which is the same size as signal cell array with corresponding frequency of each signal.
If you have a collection of signals, consider storing them as fields in a struct array. The fields can be named whatever you want (dynamic variable names are discouraged, dynamic field names not discouraged or less discouraged.)
S = struct;
x = 0:360;
for multiplier = 1:5
name = "sind_of_x" + multiplier;
S.(name) = sind(multiplier*x);
end
plot(x, S.('sind_of_x3'))
Or you could have a non-scalar struct array.
S2 = struct;
x = 0:360;
for multiplier = 1:5
S2(multiplier).x = x;
S2(multiplier).y = sind(multiplier*x);
end
plot(S2(3).x, S2(3).y)
Fantastic! Thank you so much for your great answers!
Both of those solutions work really well. The last thing (perhaps it's in your solution and just not clear to me) is how to include the frequency/random number in the variable names; and how to then call those for plotting in the same way as you showed above - but as I won't know the frequency, I can't call the variable by its name.
This was supposed to be a just little function to generate test signals for a much bigger plotting function, but I've almost spent as much time on it. Hehe. I've learned some new stuff about indexing which will certainly help me elsewhere, which is really cool. Been "away" from MATLAB for about six years (insofar as writing new code for things), it's changed so much in that time and probably doubled in power.
Thanks again!
"is how to include the frequency/random number in the variable names"
Everyone on this thread has already recommended that you do NOT do that.
Meta-data (such as frequencies) is data, and data belongs in variables, not in variable names.
"but as I won't know the frequency, I can't call the variable by its name."
That is one of the reasons why your approach should be avoided, and is why everyone is recommending that you use better data design (i.e. storing the data in one or two variables).
Thanks for clarifying that. I've had no issue getting it to work where it generates a cell with each signal's frequency in the row below.
So, taking the generous recommendations by you and others, I've since adjusted the code for which the test tones are intended to call the data - signals and their frequency labels - from the cell using indexing.
Its inefficiency and instability actually makes more sense to me now when considering it from the point of view of it being an attempt to view a datum in the name of a variable.
Thanks again for all your help!

Connectez-vous pour commenter.

Plus de réponses (1)

Mohammad Sami
Mohammad Sami le 9 Oct 2020
Modifié(e) : Mohammad Sami le 9 Oct 2020
You can store the values in a cell array. Edited portion of your code
if true
Signal{i} = Amp * sin(2*pi*Frequency*t);
sound(Signal{i}, Fs)
end

3 commentaires

Similarly you can store the corresponding frequency for each signal in another array.
Hi, thanks for answering. In my post I mentioned that I'd already figured out how to get the outputs into a cell array (using lines identical to your suggestion, in fact), but I actually want individual, discrete vectors outputted to the workspace. So instead of a signle cell array variable that contains all the tones generated, I would like a different variable in the workspace for each tone (i.e. 'Tone200_1' 'Tone400_2', and so on.
if true
Frequency = randi([Flower Fupper]);
Signal{i,1} = Frequency;
Signal{i,2} = Amp * sin(2*pi*Frequency*t);
sound(Signal{i,2}, Fs);
end
Updated to include frequency in column 1 and signal in column 2

Connectez-vous pour commenter.

Catégories

En savoir plus sur Audio I/O and Waveform Generation dans Centre d'aide et File Exchange

Produits

Version

R2019b

Community Treasure Hunt

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

Start Hunting!

Translated by