What's wrong with my implementation of filter function on matlab - matlab

I am implementing a function named filter_fir on matlab, referencing the built-in function filter in matlab.
function y = filter_fir(b, a, x)
y = conv(b, x);
y = y(1:length(x));
as = [0 a(2:end)];
a1 = a(1);
if a1 == 0
error('a(1) cannot be zero');
end
ya = y
for n = 1:(length(x))
ya = conv(ya, as);
ya = ya(1:length(x));
y = y - ya;
end
y = y ./ a1;
end
Here are the results:
Yt = filter([1 1 1], 1, [1 2 3 4 5])
Ys = filter_fir([1 1 1], 1, [1 2 3 4 5])
Yt =
1 3 6 9 12
Ys =
1 3 6 9 12
Yt = filter([1 1 1], [2 2], [1 2 3 4 5])
Ys = filter_fir([1 1 1], [2 2], [1 2 3 4 5])
Yt =
0.5000 1.0000 2.0000 2.5000 3.5000
Ys =
0.5000 0.5000 -2.0000 -11.5000 -35.0000
When a=1,two results from the built-in filter function and filter_fir are the same.
But when a = [2 2], they are not the same.
Could anybody tell me what the problem is ?

Related

How to subset a matrix by index

A = [1 2 3; 4 5 6]
r_idx = [1 2]
c_idx = [1 2]
A(r_idx,c_idx) = [1 nan nan; nan 5 nan]
In other words, it should return the (1,1) and (2,2) elements of A and setting all other entries to be nan.
Is this possible to do?
A = [1 2 3; 4 5 6];
r_idx = [1 2];
c_idx = [1 2];
B = nan(size(A));
B(sub2ind(size(A),r_idx,c_idx)) = A(sub2ind(size(A),r_idx,c_idx));
then, desired result is in B
One approach with sparse -
A(full(sparse(r_idx,c_idx,1,size(A,1),size(A,2)))==0) = nan
Or with setdiff -
A(setdiff(1:numel(A),sub2ind(size(A),r_idx,c_idx))) = nan

cross product of multidimensional arrays

I have two vectors and , each of them has three coordinates which have sizes 80x80x2000.
I want to calculate the cross product in MATLAB of these two vectors for each time moment. I know that I can extract individually coordinates in nested loops but is it possible to make it avoiding any loops?
here is the sample code with loops
m1x = cat(3, [1 2; 3 4], [5 6; 7 8]);
m1y = cat(3, [9 10; 11 12], [13 14; 15 16]);
m1z = cat(3, [17 18; 19 20], [21 22; 23 24]);
m2x = cat(3, [5 6; 2 6], [1 3; 7 9]);
m2y = cat(3, [6 7; 3 5], [2 11; 2 6]);
m2z = cat(3, [3 9; 0 1], [4 2; 3 15]);
result_x(2,2,2)=0; result_y(2,2,2)=0; result_z(2,2,2)=0;
for t=1:2
for i=1:2
for j=1:2
a = [m1x(i,j,t); m1y(i,j,t); m1z(i,j,t);];
b = [m2x(i,j,t); m2y(i,j,t); m2z(i,j,t);];
c = cross(a,b);
result_x(i,j,t) = c(1);
result_y(i,j,t) = c(2);
result_z(i,j,t) = c(3);
end;
end;
end;
so finally I have three components x,y and z of resulting vector for each moment of time
For example, if you have matrices A and B, such that each one has t (time) rows and 3 columns (x, y, z) or if you can reshape them to arrive at this configuration, you can use:
C=cross(A,B);
and each row t in C will be the cross-product of the corresponding rows in A and B. Example:
>> A=[rand(2000,1),rand(2000,1),rand(2000,1)];
>> B=[rand(2000,1),rand(2000,1),rand(2000,1)];
>> C=cross(A,B);
>> C(1,:)
ans =
0.0090 -0.0435 0.0756
>> cross(A(1,:),B(1,:))
ans =
0.0090 -0.0435 0.0756

Compute mean on matrix by groups of indices matlab

I have the following data:
A = [1 2 ; 3 2; 4 7; 10 2; 6 7; 10 9]
B = [1 2 3; 4 4 9; 1 8 0; 3 7 9; 3 6 8]
C = [4; 10; 6; 3; 1]
A =
1 2
3 2
4 7
10 2
6 7
10 9
B =
1 2 3
4 4 9
1 8 0
3 7 9
3 6 8
C.' =
4 10 6 3 1
For each unique value in A(:,2) I need to take the corresponding values in A(:,1),
look for their value in C, then take the relevant rows in B and compute their mean.
The result should be length(unique(A(:,2)) x size(B,2);
The expected result for this example:
Value "2": mean of rows 2, 4 and 5 from B
Explanation: Indices 1, 3 and 10 that correspond to value "2" in A are
at indices 2, 4, 5 in C.
Correspondingly:
Value "7": mean of rows 1 and 3 from B.
Value "9": mean of row 2 from B.
I compute it now by applying unique on A and iterating each value, searching the right indices. My data set is quite large, so it takes quite a time. How can I avoid the loops?
Let's do what you say in the question step by step:
For each unique value in A(:, 2):
[U, ia, iu] = unique(A(:, 2));
Take the corresponding values in A(:, 1) and look for their value in C:
[tf, loc] = ismember(A(:, 1), C);
It's also recommended to make sure, just in case, that all values are actually found in C:
assert(all(tf))
Then take the relevant rows in B and compute their mean:
[X, Y] = meshgrid(1:size(B, 2), iu);
result = accumarray([Y(:), X(:)], reshape(B(loc, :), 1, []), [], #mean);
Hope this helps! :)
Example
%// Sample input
A = [1 2 ; 3 2; 4 7; 10 2; 6 7; 10 9];
B = [1 2 3; 4 4 9; 1 8 0; 3 7 9; 3 6 8];
C = [4; 10; 6; 3; 1];
%// Compute means
[U, ia, iu] = unique(A(:, 2));
[tf, loc] = ismember(A(:, 1), C);
[X, Y] = meshgrid(1:size(B, 2), iu);
result = accumarray([Y(:), X(:)], reshape(B(loc, :), [], 1), [], #mean);
The result is:
result =
3.3333 5.6667 8.6667
1.0000 5.0000 1.5000
4.0000 4.0000 9.0000
Here is another solution without arrayfun and accumarray using good old-fashion matrix multiplication:
r = bsxfun(#eq, A(:,1), C')*(1:numel(C))';
[~,m,n] = unique(A(:,2));
f=histc(n, 1:numel(m));
result = diag(1./f)*bsxfun(#eq, 1:numel(m), n).'*B(r,:);
I ran a benchmark against other two solutions and it appears to be faster than both. For 1000 repetitions:
This method takes 0.205650 seconds.
Eitan T's solution takes 0.546976 seconds.
matlabit's solution takes 1.619039 seconds.
Here is the benchmark code:
N = 1e3;
tic
for k=1:N,
r = bsxfun(#eq, A(:,1), C')*(1:numel(C))'; % faster than [~,r] = ismember(A(:,1), C)
[~,m,n] = unique(A(:,2));
f=histc(n, 1:numel(m));
result2 = diag(1./f)*bsxfun(#eq, 1:numel(m), n).'*B(r,:);
end
toc
tic
for k=1:N,
[U, ia, iu] = unique(A(:, 2));
[tf, loc] = ismember(A(:, 1), C);
[X, Y] = meshgrid(1:size(B, 2), iu);
result1 = accumarray([Y(:), X(:)], reshape(B(loc, :), [], 1), [], #mean);
end
toc
tic
for k=1:N,
D = [arrayfun(#(x) find(C == x,1,'first'), A(:,1) ), A(:,2)];
data = [B(D(:,1),:), D(:,2)];
st = grpstats(data(:,1:3),data(:,4:4),{'mean'});
end
toc
Thanks,
I also thought of:
D = [arrayfun(#(x) find(C == x,1,'first'), A(:,1) ), A(:,2)];
data = [B(D(:,1),:), D(:,2)];
st = grpstats(data(:,1:3),data(:,4:4),{'mean'});

How to choose between two values using 'or' in matlab?

I have the following code :
a = cell(4,1);
a{1} = [5 3 0 0];
a{2} = [0 3 5 0];
a{3} = [1 3 0 0];
a{4} = [0 3 2 0];
arrayind = 2;
b = a(cellfun(#(x)x(arrayind) == 1,a));
b{:}
How can I achieve this when an IF statement is used :
if r>2
b = a(cellfun(#(x)x(arrayind) == (1 | 2 | 3),a));
end
Basically saying, find 1, if not there then 2, if not there then 3...
ismember could perhaps be what you are looking for.
Replacing the equality operator with ismember as follows:
a = cell(4,1);
a{1} = [5 3 0 0];
a{2} = [0 3 5 0];
a{3} = [1 3 0 0];
a{4} = [0 3 2 0];
arrayind = 1;
b = a(cellfun(#(x) ismember(x(arrayind), [1 5]), a));
would yield b = a([1, 3])

Cartesian product in MATLAB

Here is the simplified version of the problem I have. Suppose I have a vector
p=[1 5 10]
and another one
q=[.75 .85 .95]
And I want to come up with the following matrix:
res=[1, .75;
1, .85;
1, .95;
5, .75;
5, .85;
5, .95;
10, .75;
10, .85;
10, .95]
This is also known as the Cartesian Product.
How can I do that?
Here's one way:
[X,Y] = meshgrid(p,q);
result = [X(:) Y(:)];
The output is:
result =
1.0000 0.7500
1.0000 0.8500
1.0000 0.9500
5.0000 0.7500
5.0000 0.8500
5.0000 0.9500
10.0000 0.7500
10.0000 0.8500
10.0000 0.9500
A similar approach as the one described by #nibot can be found in matlab central file-exchange.
It generalizes the solution to any number of input sets. This would be a simplified version of the code:
function C = cartesian(varargin)
args = varargin;
n = nargin;
[F{1:n}] = ndgrid(args{:});
for i=n:-1:1
G(:,i) = F{i}(:);
end
C = unique(G , 'rows');
end
For instance:
cartesian(['c','d','e'],[1,2],[50,70])
ans =
99 1 50
99 1 70
99 2 50
99 2 70
100 1 50
100 1 70
100 2 50
100 2 70
101 1 50
101 1 70
101 2 50
101 2 70
Here's a function, cartesian_product, that can handle any type of input, including string arrays, and returns a table with column names that match the names of the input variables. Inputs that are not variables are given names like var1, var2, etc.
function tbl = cartesian_product(varargin)
names = arrayfun(#inputname, 1:nargin, 'UniformOutput', false);
for i = 1:nargin
if isempty(names{i})
names{i} = ['var' num2str(i)];
end
end
rev_args = flip(varargin);
[A{1:nargin}] = ndgrid(rev_args{:});
B = cellfun(#(x) x(:), A, 'UniformOutput', false);
C = flip(B);
tbl = table(C{:}, 'VariableNames', names);
end
>> x = ["a" "b"];
>> y = 1:3;
>> z = 4:5;
>> cartesian_product(x, y, z)
ans =
12×3 table
x y z
___ _ _
"a" 1 4
"a" 1 5
"a" 2 4
"a" 2 5
"a" 3 4
"a" 3 5
"b" 1 4
"b" 1 5
"b" 2 4
"b" 2 5
"b" 3 4
"b" 3 5
>> cartesian_product(1:2, 3:4)
ans =
4×2 table
var1 var2
____ ____
1 3
1 4
2 3
2 4