function C = conv(A, B) % CONV Convolution and polynomial multiplication. % (Quaternion overloading of standard Matlab function.) % Copyright © 2006 Stephen J. Sangwine and Nicolas Le Bihan. % See the file : Copyright.m for further details. % This function operates in the same way as the standard Matlab function % apart from supporting both left and right coefficients. (Since quaternion % multiplication is not commutative, the general case requires both left % and right multiplication in the convolution product/summation.) To supply % left and right coefficients, use the calling profile conv({L,R},v) where % L and R are vectors of the same length and orientation. If the first % parameter is not a cell array, it is taken to be a left coefficient and % the right coefficient array is implicitly ones. error(nargchk(2, 2, nargin)), error(nargoutchk(0, 1, nargout)) if iscell(A) % The first parameter must be a cell array of two elements, and the % elements must have the same size (therefore orientation). if length(A) ~= 2 error('If a cell array, the first parameter must have two elements.') end L = A{1}; R = A{2}; % Separate the cell array into two vectors. if ~all(size(L) == size(R)) error('The elements of the cell array must have the same size.') end else L = A; R = ones(size(L)); % Supply the implicit right coefficients. end if ~isvector(L) || ~isvector(B) error('Parameters must be vectors.') end m = length(L); n = length(B); % Construct a result vector C matching the orientation of the longer of % L or B in order to return a result compatible with the standard Matlab % conv function. if m > n % w must have the same orientation as u. if size(L, 1) == 1 C = quaternion(zeros(1, m + n - 1)); else C = quaternion(zeros(m + n - 1, 1)); end end if m < n % w must have the same orientation as q. if size(B, 1) == 1 C = quaternion(zeros(1, m + n - 1)); else C = quaternion(zeros(m + n - 1, 1)); end end if m == n % The two parameters are of equal length. In this case Matlab's conv % function seems to return a column vector unless both parameters are % row vectors. if size(L, 1) == 1 && size(B, 1) == 1 C = quaternion(zeros(1, m + n - 1)); else C = quaternion(zeros(m + n - 1, 1)); end end % To ensure that we can multiply L .* B .* R we need them to have the same % orientation (row, column). If B doesn't match the orientation of L, % transpose it. if (size(L, 1) == 1 && size(B, 1) ~= 1) || (size(L, 2) == 1 && size(B, 2) ~= 1) B = B.'; end for k = 1:length(C) % For each element of the output array. % This code is vectorized: the two arrays are sliced to extract the % parts that must be multiplied element by element and summed to give % the current element of the output array. This is complicated by the % cases where one array overlaps the end of the other. j1 = max(1, k + 1 - n); % These two indices select a region of the L j2 = min(k, m); % and R arrays (the whole of, in the general % case). % We need to use indexing here, but since this is a class method, % normal array indexing doesn't work. See the comment in the file % svd.m where the same problem and solution occurs. The commented % statement below is what we would write if array indexing worked % here as per normal. % C(k) = sum(L(j1 : j2) .* B(k + 1 - j1 : k + 1 - j2) .* R(j1 : j2)); s = substruct('()',{k}); t = substruct('()',{j1:j2}); C = subsasgn(C, s, ... sum(subsref(L, t) .* ... flipud(fliplr(subsref(B, substruct('()', {k + 1 - j2 : k + 1 - j1})))) .* ... subsref(R, t))); end % Implementation note: the use of ones(size(u)) for v in the case where v % is omitted is a crude hack and it would be better not to multiply by the % right coefficients at all. Also if only two parameters are given it would % be better to assign the longer of the two to q, and the shorter to u or v % according as to whether it should be multiplied on the left or right. % The code also needs to be sorted out to tidy up the mess caused by trying % to return a result with the same orientation as Matlab's built-in in % conv.