Slicing Power Spectral Density over frequency bands - matlab

I am using pwelch to get the Power Spectral Density of multiple signal vectors and then finding the average signal to noise ratios over 5 frequency bands.
I converted the power spectral densities to dB and am currently obtaining each band one by one:
P_signal1(band1)
P_signal1(band2)
P_signal1(band3)
...
P_signal2(band1)
P_signal2(band2)
and so on.
Is there any way to obtain this easily, maybe using arrays of the signals and the bands
signals = [P_signal1, P_signal2, P_signal3, P_signal4, P_signal5]
bands = [band1, band2, band3, band4, band5]
and obtain a matrix of each combination?

A = 1:100;
bands = [1:20;21:40;41:60;61:80;81:100];
A(bands)
Full documentation can be seen here.
The idea is indexing in Matlab is a lot different than in other languages, since Matlab uses matrices. When you index an array like A(1), it will pick one element out, just like any other language. When you index it as A([2,1;3,1]), magic happens. Matlab will take out elements of A 4 times, each corresponding to one element in [2,1;3,1]. And then it arranges the 4 results in the same form of [2,1;3,1]. The output will be also a matrix.
EDIT: Using cell array
A = 1:100;
bands = {1:20;21:40;41:60;61:80;81:100};
cell2mat( cellfun(#(x) A(x), bands, 'UniformOutput', false) )
This works differently than above, but shares similar idea. Now bands is a cell array, each element containing an index range.
cellfun takes each of this range as x, and evaluate expression A(x) (which means access that part of A), and put the result into a new cell array, of which the size is same with bands, and the element position accords to the definition in bands.
cell2mat converts this output cell array into a plain numeric array.

Related

Difference in Matlab results when using PCA() and PCACOV()

Closest match I can get is to run:
data=rand(100,10); % data set
[W,pc] = pca(cov(data));
then don't demean
data2=data
[W2, EvalueMatrix2] = eig(cov(data2));
[W3, EvalueMatrix3] = svd(cov(data2));
In this case W2 and W3 agree and W is the transpose of them?
Still not clear why W should be the transpose of the other two?
As an extra check I use pcacov:
[W4, EvalueMatrix4] = pcacov(cov(data2));
Again it agrees with WE and W3 but is the transpose of W?
The results are different because you're subtracting the mean of each row of the data matrix. Based on the way you're computing things, rows of the data matrix correspond to data points and columns correspond to dimensions (this is how the pca() function works too). With this setup, you should subtract the mean from each column, not row. This corresponds to 'centering' the data; the mean along each dimension is set to zero. Once you do this, results should be equivalent to pca(), up to sign flips.
Edit to address edited question:
Centering issue looks ok now. When you run the eigenvalue decomposition on the covariance matrix, remember to sort the eigenvectors in order of descending eigenvalues. This should match the output of pcacov(). When calling pca(), you have to pass it the data matrix, not the covariance matrix.

How to calculate per-page STD in matlab?

Suppose I have matrix A of 100x200x300. Third dimension is called "page" in Matlab and this matrix has 300 pages then.
Now I want to calculate standard deviation within each page and get a result matrix of 1x1x300.
I can't just do
std(std(A,0,1),0,2)
because normalization will be wrong as I think.
You need to collapse the first two dimensions into one (i.e. into columns) using reshape; and then compute std along each column:
Ar = reshape(A, size(A,1)*size(A,2), size(A,3));
result = std(Ar);
This will give you a 1x300 vector as result. If you really need it to be 1x1x300, use
result = shiftdim(result, -1);

Matlab code to compare two histograms

I want to compare two image histograms. They are as follows:
h1 --> double valued 1 dimension vector .4096 in length.
h2 --> double valued 1 dimension vector .4096 in length.
I am using this matlab function here:
http://clickdamage.com/sourcecode/code/compareHists.m
It is as follows:
% s = compareHists(h1,h2)
% returns a histogram similarity in the range 0..1
%
% Compares 2 normalised histograms using the Bhattacharyya coefficient.
% Assumes that sum(h1) == sum(h2) == 1
%
function s = compareHists(h1,h2)
s = sum(sum(sum(sqrt(h1).*sqrt(h2))));
My question is :
Is there a need for multiple sums?
Even if there is only one sum in the above equation, it would suffice..right?
like this: sum(sqrt(h1).*sqrt(h2)) --> ?
Can some one please explain the code above? Also, tell me if I use a single sum will it be all right?
I tried both ways and got the same answer for two image histograms. I did this with only two histograms not more and hence want to be sure.
Thanks!
In general, sum does the sum along one dimension only. If you want to sum along multiple dimensions you either
use sum several times; or
use linear indexing to reduce to a single dimension and then use sum once: sum(sqrt(h1(:)).*sqrt(h2(:))).
In your case, if there's only one dimension, yes, a single sum would suffice.
You are right. Only one sum is needed. However, if either h1 or h2 is a multidimensional matrix, then you may want to sum as many as the dimensions. For example:
A=magic(4); % a 4 by 4 matrix of magic numbers.
sum(A) % returns [34,34,34,34], i.e. the sum of elements in each column.
sum(sum(A)) % returns 136, i.e. the sum of all elements in A.
I believe the code you downloaded originaly was written to handle multiple histograms stacked as columns of a matrix. This is (IMHO) the reason for the multiple sums.
In your case you can leave it with only one sum.
You can do even better - without any sum
Hover here to see the answer
s = sqrt(h1(:)')*sqrt(h2(:));
The trick is to use vector multiplication!
I don't see any points in 3 sums too, but if you have not a vector with histogram but a matrix you will need 2 sums like this sum(sum(sqrt(h1).*sqrt(h2))) to compare them. First one will calculate the sum of the rows, the second - the sum of the columns.

Matlab 3d-matrix

I have to create a very big 3D matrix (such as: 500000x60x60). Is there any way to do this in matlab?
When I try
omega = zeros(500000,60,60,'single');
I get an out-of-memory error.
The sparse function is no option since it is only meant for 2D matrices. So is there any alternative to that for higher dimensional matrices?
Matlab only has support for sparse matrices (2D). For 3D tensors/arrays, you'll have to use a workaround. I can think of two:
linear indexing
cell arrays
Linear indexing
You can create a sparse vector like so:
A = spalloc(500000*60*60, 1, 100);
where the last entry (100) refers to the amount of non-zeros eventually to be assigned to A. If you know this amount beforehand it makes memory usage for A more efficient. If you don't know it beforehand just use some number close to it, it'll still work, but A can consume more memory in the end than it strictly needs to.
Then you can refer to elements as if it is a 3D array like so:
A(sub2ind(size(A), i,j,k))
where i, j and k are the indices to the 1st, 2nd and 3rd dimension, respectively.
Cell arrays
Create each 2D page in the 3D tensor/array as a cell array:
a = cellfun(#(x) spalloc(500000, 60, 100), cell(60,1), 'UniformOutput', false);
The same story goes for this last entry into spalloc. Then concatenate in 3D like so:
A = cat(3, a{:});
then you can refer to individual elements like so:
A{i,j,k}
where i, j and k are the indices to the 1st, 2nd and 3rd dimension, respectively.
Since your matrix is sparse, try to use ndsparse (N-dimensional sparse arrays FEX)

ROC curve vertical average in MATLAB

Is there a way to compute the vertical average (http://vicos.fri.uni-lj.si/data/vprsistemi/ROCintro.pdf) of several ROC curves in MATLAB? I've found in the MATLAB guide that perfcurve could do it, but I have no idea how to use it.
You can just concatenate the probability of detection arrays into a matrix and then take their mean. Assuming your probability of false alarms are held in the row vector PFA and your probability of detection values are held in the row vectors PD1, PD2, ...:
PDMatrix = [PD1; PD2; ...];
PDMean = mean(PDMatrix, 1);
This assumes your ROC curves all share the same PFA values. If this isn't the case, then you can create a common PFA array and use interp1 to resample your PD arrays before averaging. For example, if you're interested in logarithmically spaced PFA values from 10^-6 to "near 1," and your PFA/PD pairs have the data to interpolate in this range, you can do something like
PFAResampled = logspace(-6, -.1, 1000);
PD1Resampled = interp1(PFA1, PD1, PFAResampled);
PD2Resampled = interp1(PFA2, PD2, PFAResampled);
After that, you can just concatenate and take the mean as shown above.