function Ft=frametight(F);
%FRAMETIGHT Construct the canonical tight frame
% Usage: Ft=frametight(F);
%
% Ft=FRAMETIGHT(F) returns the canonical tight frame of F.
%
% The canonical tight frame can be used to get perfect reconstruction if
% it is used for both analysis and synthesis. This is demonstrated in the
% following example:
%
% % Create a frame and its canonical tight
% F=frame('dgt','hamming',32,64);
% Ft=frametight(F);
%
% % Compute the frame coefficients and test for perfect
% % reconstruction
% f=gspi;
% c=frana(Ft,f);
% r=frsyn(Ft,c);
% norm(r(1:length(f))-f)
%
% See also: frame, framepair, framedual
%
% Url: http://ltfat.github.io/doc/frames/frametight.html
% Copyright (C) 2005-2023 Peter L. Soendergaard <peter@sonderport.dk> and others.
% This file is part of LTFAT version 2.6.0
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
complainif_notenoughargs(nargin,1,'FRAMETIGHT');
complainif_notvalidframeobj(F,'FRAMETIGHT');
% Default operation, works for a lot of frames
Ft=F;
% Handle the windowed transforms
switch(F.type)
case {'dgt','dgtreal','dwilt','wmdct','filterbank','ufilterbank',...
'nsdgt','unsdgt','nsdgtreal','unsdgtreal'}
Ft=frame(F.type,{'tight',F.g},F.origargs{2:end});
case {'filterbankreal','ufilterbankreal'}
Ft=frame(F.type,{'realtight',F.g},F.origargs{2:end});
case 'gen'
[U,sv,V] = svd(F.g,'econ');
Ft=frame('gen',U*V');
case 'tensor'
for ii=1:F.Nframes
tight_frames{ii}=frametight(F.frames{ii});
end;
F=frame('tensor',tight_frames{:});
case 'fusion'
tight_w=1./F.w;
for ii=1:F.Nframes
tight_frames{ii}=frametight(F.frames{ii});
end;
Ft=frame('fusion',tight_w,tight_frames{:});
case 'ufwt'
% The canonical tight made from ufwt might not keep the iterated
% filterbank structure
[g,a] = wfbt2filterbank({F.g,F.J,'dwt'});
g = comp_filterbankscale(g,a,F.flags.scaling);
Ft = frametight(frame('filterbank',g,ones(numel(g),1),numel(g)));
case 'uwfbt'
% The canonical tight made from uwfbt might not keep the iterated
% filterbank structure
[g,a] = wfbt2filterbank(F.g,F.J);
g = comp_filterbankscale(g,a,F.flags.scaling);
Ft = frametight(frame('filterbank',g,ones(numel(g),1),numel(g)));
case 'uwpfbt'
% The canonical tight made from uwpfbt might not keep the iterated
% filterbank structure
[g, a] = wpfbt2filterbank(F.g,F.flags.interscaling);
g = comp_filterbankscale(g,a,F.flags.scaling);
Ft = frametight(frame('filterbank',g,ones(numel(g),1),numel(g)));
case 'fwt'
is_basis = abs(sum(1./F.g.a)-1)<1e-6;
is_tight = F.info.istight;
if is_basis && is_tight
Ft = F;
else
error(['%s: Cannot create the canonical tight frame with the ',...
'same structure. Consider casting the system to an ',...
'uniform filterbank.'],...
upper(mfilename));
end
case 'wfbt'
is_basis = all(cellfun(@(nEl) abs(sum(1./nEl.a)-1)<1e-6,F.g.nodes));
is_tight = F.info.istight;
if is_basis && is_tight
Ft = F;
else
error(['%s: Cannot create the canonical tight frame with the ',...
'same structure. Consider casting the system to an ',...
'uniform filterbank.'],...
upper(mfilename));
end
case 'wpfbt'
% WPFBT is too wierd.
error(['%s: Canonical tight frame of wpfbt might not keep the ',...
'same structure. '],upper(mfilename))
end;
switch(F.type)
case {'ufwt','uwfbt','uwpfbt'}
warning(sprintf(['%s: The canonical tight system does not preserve ',...
'the iterated filterbank structure.'],...
upper(mfilename)));
end
% Treat the fixed length frames
if isfield(F,'fixedlength') && F.fixedlength && isfield(F,'L')
Ft = frameaccel(Ft,F.L);
Ft.fixedlength = 1;
end