Build Matrix from X and Y Coords and Corresponding Values

Hello,
I have three vectors and I want to construct a matrix from them.
  • 'a' is a vector of length n, containing magnitude data.
  • 't' is a vector (also length n) of time indices at which the samples in 'a' occur.
  • 'f' is a vector (length m) of frequency indices at which the samples in 'a' occur.
t = 1:1:2500; % Vector of sample indices
f = 1:1:100; % Vector of frequency indices
a = rescale(square(t)); % Vector of magnitude values
How can I construct matrix 'M' with each value in 'a' occurring at the corresponding coordinate in (t, f), and all other indices in 'M' = 0?
  • Using diag(a) does not work, because 't' and 'f' are of different lengths. I can resample or interpolate 'M' to change the resulting square matrix into a rectangular one, but this corrupts the data. I do not want to reduce the number of rows of M by decimation, but rather by allowing 'r' values of m to occupy each row.
% diag and resamp method - does not work.
M = diag(a);
% ratio of 't' to 'f'
r = length(t) / length(f);
% resample 'M' to dimensions of [length(f) x length(t)]
M_rect = resample(M, 1, r, 'Dimension', 2);
  • I have tried simply writing element-by-element into 'M' in a for-loop, however for obvious reasons, this leaves me with a square matrix of either nxn. Essentially this is identical to diag(a).
% Single index Loop method - does not work
for i = 1:length(t)
M(i, i) = a(i);
end
  • I have tried writing element-by-element into 'M' in two nested for-loops with row and column indices, however this results in 'M' having correct dimensions, but the values of 'a' fill every column. Essentially this is identical to diag(a).
% Dual index Loop method - does not work
for i = 1:length(t)
for j = 1:length(f)
M(j, i) = a(i);
end
end
This seems like it should be quite simple, but it's been wrecking my head. Any help would be most appreciated.
Thanks in advance,
Ben

1 Comment

What are the intended dimensions of M? How is it that "f is a vector (length m) of frequency indices at which the samples in 'a' occur" but length(f)~=length(a)?.

Sign in to comment.

 Accepted Answer

Generally speaking, if you have a list of (t,f) coordinates with corresponding values a, you can use accumarray, e.g.,
t=[1,2,3]';
f=[2,2,5]';
a=rand(1,3)'
a = 3×1
0.0438 0.2643 0.2258
M=accumarray([t,f],a,[5,6])
M = 5×6
0 0.0438 0 0 0 0 0 0.2643 0 0 0 0 0 0 0 0 0.2258 0 0 0 0 0 0 0 0 0 0 0 0 0
Or, you can use sparse,
M=sparse(t,f,a,5,6);
full(M)
ans = 5×6
0 0.0438 0 0 0 0 0 0.2643 0 0 0 0 0 0 0 0 0.2258 0 0 0 0 0 0 0 0 0 0 0 0 0

3 Comments

Hi Matt,
Thanks very much for your answer, and sorry for my slow reply.
The intended dimensions of M are = [length(f), length(t)].
Unfortunately, sparse() and accumarray() do not work for my values of 'f', as these are not coordinates but frequencies in Hz, so they are not necessarily integers, and do not necessarily start at 1 or go to length(f). Sorry, I should have been more careful in defining this variable in my example code.
A clearer example would have been:
t = 1:1:2500; % Vector of sample indices
f = linspace(50, 30, 100); % Vector of frequencies (Hz)
a = rescale(square(t)); % Vector of magnitude values
I've written something that uses accumarray, but it is a little hacky.
f1 = 50; % Starting frequency
f2 = 30; % Ending Frequency
nf = 100; % Number of frequency points between f1 and f2
nsamps = 2500; % Signal duration (samples)
t = 1:1:nsamps; % Vector of sample indices
f = linspace(f1, f2, nf); % Vector of frequencies (Hz)
a = rescale(square(t)); % Vector of magnitude values
f_delta = f1-f2; % Frequency
% Vector of intiger frequency indices.
f_indices = linspace(f1, f2+1, f_delta);
% ratio of 't' to 'f'
r = nsamps / f_delta;
% 'r' time samples for each frequency
f_reshaped = repelem(f_indices, r);
% Accumulate a into M
M = accumarray([f_reshaped', t'], 1, [nf, nsamps]);
This works, but breaks for certain values of f1, f2, nf and nsamps, so I have had to add some "if" statements to pad extra zeros or trim end samples in cases where f_indices ends up being the wrong length (ie. not 2500).
This will work, but I would love any advice on a cleaner way to achieve this.
Thanks again,
Ben
These variables are never used
f = linspace(f1, f2, nf); % Vector of frequencies (Hz)
a = rescale(square(t)); % Vector of magnitude values
so I have had to add some "if" statements to pad extra zeros or trim end samples in cases where f_indices ends up being the wrong length
What should happen if it is the wrong length? Should f_indices grow/shrink to 2500 or should t change length to accomodate f_indices?
Thanks Matt, I've cleaned up my code and I'm happy with it now.
I appreciate your help.
Chers,
Ben

Sign in to comment.

More Answers (0)

Categories

Find more on MATLAB in Help Center and File Exchange

Products

Release

R2022b

Asked:

Ben
on 9 Nov 2022

Commented:

Ben
on 16 Nov 2022

Community Treasure Hunt

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

Start Hunting!