changeset 160:e3035d45d014 danieleb

Added support classes
author Daniele Barchiesi <daniele.barchiesi@eecs.qmul.ac.uk>
date Wed, 31 Aug 2011 10:53:10 +0100
parents 23763c5fbda5
children 88578ec2f94a
files util/classes/@audio/audio.m util/classes/@audio/plot.m util/classes/@dictionary/cumcoherence.m util/classes/@dictionary/dictionary.m util/classes/@dictionary/mtimes.m util/classes/@dictionary/plotcumcoherence.m util/classes/@dictionary/spark.m util/classes/dictionaryMatrices/dctmatrix.m util/classes/dictionaryMatrices/grassmannian.m util/classes/util/regularisedictionary.m
diffstat 10 files changed, 410 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@audio/audio.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,54 @@
+classdef audio
+    %% Audio object
+    properties
+        s  %vector containing the audio signal
+        fs %sampling frequency 
+        nBits % number of bits per sample
+        name % string containing the name of the audio file
+        format % string containing the format of the audio file
+    end
+    
+    methods
+        %% Constructor
+        function obj = audio(varargin)
+            error(nargchk(1,5,nargin));
+            if ischar(varargin{1})
+                [~, obj.name obj.format] = fileparts(varargin{1});
+                switch obj.format
+                    case '.wav'
+                        [obj.s obj.fs obj.nBits] = wavread(varargin{1});
+                    otherwise
+                        error('Unsupported audio format')
+                end
+            else
+                obj.s = varargin{1};
+                if nargin>1, obj.fs = varargin{2}; else obj.fs = []; end
+                if nargin>2, obj.nBits = varargin{3}; else obj.nBits = []; end
+                if nargin>3, obj.name = varargin{4}; else obj.name = []; end
+                if nargin>4, obj.format = varargin{5}; else obj.format = []; end
+            end
+        end
+        
+        %% Playback functions
+        function player = play(obj, player)
+            if ~exist('player','var') || isempty(player)
+                player = audioplayer(obj.s,obj.fs);
+            end
+            play(player);
+        end
+        
+        function player = stop(obj, player)
+            if ~exist('player','var') || isempty(player)
+                player = audioplayer(obj.s,obj.fs);
+            end
+            stop(player)
+        end
+        
+        function player = pause(obj, player)
+            if ~exist('player','var') || isempty(player)
+                player = audioplayer(obj.s,obj.fs);
+            end
+            pause(player)
+        end
+    end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@audio/plot.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,58 @@
+function plot(obj)
+
+%% Plot the time domain signal
+s = obj.s;
+fs = obj.fs;
+figure, plot((1:length(s))/fs,s);
+title('Audio signal')
+xlabel('time (s)');
+axis tight
+
+player = audioplayer(s,fs);
+set(player,'StartFcn',@plotTransportBar);
+set(player,'TimerFcn',@updateTransportBar);
+set(player,'StopFcn',@deleteTransportBar);
+
+%% Add playbaack controls
+playButtonH = uicontrol(gcf,'Style','pushbutton','String','play','Units',...
+    'Normalized','Position',[0.02 + 0.39 0 0.1 0.05]);
+stopButtonH = uicontrol(gcf,'Style','pushbutton','String','stop','Units',...
+    'Normalized','Position',[0.12 + 0.39 0 0.1 0.05]);
+
+set(playButtonH,'Callback',@play_callback);
+set(stopButtonH,'Callback',@stop_callback);
+
+    function play_callback(~,~)
+        if strcmpi(get(playButtonH,'String'),'play')
+            play(player,player.CurrentSample);
+            set(playButtonH,'String','pause');
+        else
+            pause(player)
+            set(playButtonH,'String','play');
+        end
+    end
+
+    function stop_callback(~,~)
+        stop(player);
+    end
+
+%% Transport Bar functions
+    function plotTransportBar(~,~)
+        global tbH
+        xLim = get(gca,'Xlim');
+        yLim = get(gca,'YLim');
+        tbH = line([xLim(1) xLim(1)],yLim,'Color','k');
+    end
+        
+    function updateTransportBar(hObject,~)
+        global tbH
+        currentSample = hObject.CurrentSample;
+        pos = currentSample/fs;
+        set(tbH,'XData',[pos pos]);
+    end
+
+    function deleteTransportBar(~,~)
+        global tbH
+        delete(tbH);
+    end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@dictionary/cumcoherence.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,19 @@
+function mu = cumcoherence(obj)
+obj = normalize(obj);
+[M N] = size(obj.phi);
+mu = zeros(M,1);
+for m=1:M
+    c = zeros(N);
+    for i=1:N
+        c(:,i) = abs(obj.phi'*obj.phi(:,i));
+        c(i,i) = 0;
+    end
+    c = sort(c,'descend');
+    c = c(1:m,:);
+    if m==1
+        mu(m) = max(c);
+    else
+        mu(m) = max(sum(c));
+    end
+end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@dictionary/dictionary.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,114 @@
+classdef dictionary
+    %% Dictionary for sparse representation
+    properties
+        phi         %Matrix containing the dictionary
+        len         %Length of basis functions
+        nAtoms      %Number of basis function
+        name        %String containing the matrix ensemble from which the dictionary is drawn
+    end
+    properties (Dependent = true)
+        redundancy      %Redundancy of the dictionary: nAtoms/len
+        coherence       %Maximum inner product of different basis
+        isNormalised    %True if the atoms have unit norm
+        rank            %rank of the dictionary
+    end
+    
+    methods
+        %% Constructor
+        function obj = dictionary(phi,len,nAtoms)
+            % obj = dictionary(phi,len,nAtoms)
+            % INPUTS:
+            % - phi: either a string specifying a matrix ensamble or a
+            % matrix defining an explicit dictionary
+            % - len: length of the atoms (only for implicit dictionaries)
+            % - nAtoms: number of atoms (only for implicit dictionaries)
+            if nargin
+                if ~ischar(phi)
+                    [obj.len obj.nAtoms] = size(phi);
+                    obj.phi              = phi;
+                    obj.name             = 'explicit';
+                else
+                    switch lower(phi)
+                        case 'dct'
+                            obj.phi = dctmatrix(len,nAtoms);
+                        case 'grassmanian'
+                            obj.phi = grassmanian(len,nAtoms);
+                        otherwise
+                            obj.phi = MatrixEnsemble(len,nAtoms,phi);
+                    end
+                    obj.len    = len;
+                    obj.nAtoms = nAtoms;
+                    obj.name   = lower(phi);
+                end
+            end
+        end
+        
+        %% Dependent properties
+        function redundancy = get.redundancy(obj)
+            redundancy = obj.nAtoms/obj.len;
+        end
+        function coherence = get.coherence(obj)
+            obj.phi = normcol(obj.phi);
+            G = obj.phi'*obj.phi;
+            G = G - eye(size(G));
+            coherence = max(abs(G(:)));
+        end
+        function isNormalised = get.isNormalised(obj)
+            isNormalised = norm(sum(conj(obj.phi).*obj.phi) - ...
+                ones(1,obj.nAtoms))<1e-9;
+        end
+        function r = get.rank(obj)
+            r = rank(obj.phi);
+        end
+        %% Operations
+        function obj = normalize(obj)
+            obj.phi = normcol(obj.phi);
+        end
+        
+        %% Visualization
+        function image(obj)
+            %Image of the dictionary
+            if isreal(obj.phi)
+                imagesc(obj.phi);
+                title('Dictionary');
+                xlabel('Atom number');
+            else
+                subplot(2,1,1)
+                imagesc(real(obj.phi));
+                title('Real');
+                xlabel('Atom number');
+                subplot(2,1,2)
+                imagesc(imag(obj.phi));
+                title('Imaginary');
+                xlabel('Atom number');
+            end
+        end
+        function imagegram(obj)
+            G = obj.phi'*obj.phi;
+            imagesc(G);
+            title('Gram Matrix')
+        end
+        function plot(obj,n)
+            %Plot of the n-th basis
+            if isreal(obj.phi)
+                plot(obj.phi(:,n));
+                title(['Atom number ' num2str(n) '/' num2str(size(obj.phi,2))]);
+            else
+                subplot(2,1,1)
+                plot(real(obj.phi(:,n)));
+                title(['Atom number ' num2str(n) '/' num2str(size(obj.phi,2)) ' - Real']);
+                subplot(2,1,2)
+                plot(imag(obj.phi(:,n)));
+                title(['Atom number ' num2str(n) '/' num2str(size(obj.phi,2)) ' - Imaginary']);
+            end
+        end
+        
+        function movie(obj)
+            %Movie of the basis
+            for i=1:size(obj.phi,2)
+                obj.plot(i);
+                pause(1/25);
+            end
+        end
+    end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@dictionary/mtimes.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,11 @@
+function C = mtimes(A,B)
+isAdic = strcmp(class(A),'dictionary');
+isBdic = strcmp(class(B),'dictionary');
+if isAdic && ~isBdic
+    C = A.phi*B;
+elseif isBdic && ~isAdic
+    C = A*B.phi;
+elseif isAdic && isBdic
+    C = A.phi*B.phi;
+end
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@dictionary/plotcumcoherence.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,10 @@
+function plotcumcoherence(obj)
+mu = cumcoherence(obj);
+v = conv(mu,[1 1]);
+ind = find(v<1, 1, 'last');
+plot(1:obj.len,mu);
+hold on
+line([ind ind], [min(mu) max(mu)],'Color','red');
+title(['Minimum allowed sparsity (Tanner):' num2str(ind/obj.len)]);
+grid on
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@dictionary/spark.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,35 @@
+function varargout = Spark(obj)
+% Calculates the minimum number of linearly dependent atoms in the matrix A
+% WARNING: this function computes a combinatorial function, use only if the
+% size of the problem is small (i.e. <20)
+if nargout <= 1
+    A = obj.phi;
+    k = size(A,2);
+    if k>20
+        warning('This function computes a combinatorial function, use only if thesize of the problem is small (i.e. <20).');
+        choice = input('The calculation of spark will take a long time... do you wish to continue anyway (y/n)','s');
+        if strcmpi( choice,'n')
+            return
+        end
+    end
+    sigma = 2;
+    while true
+        P = nchoosek(1:k,sigma);
+        for i=1:size(P,1)
+            r = rank(A(:,P(i,:)));
+            if r<sigma
+                varargout{1} = sigma;
+                return
+            end
+        end
+        sigma = sigma + 1;
+        if sigma==k
+            varargout{1} = inf;
+            return
+        end
+    end
+else
+    %% TODO: calculate lower and upper bounds on the spark
+    varargout{1} = 2;
+    varargout{2} = inf;
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/dictionaryMatrices/dctmatrix.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,24 @@
+function D = dctmatrix(N,K,type)
+
+error(nargchk(1,3,nargin,'struct'));
+if ~exist('type','var') || isempty(type), type='II'; end
+if ~exist('K','var') || isempty(K), K=N; end
+
+[c r] = meshgrid(0:K-1,0:N-1);
+switch type
+    case 'I'
+        D = cos(pi*c.*r/(K-1));
+        D(1,:) = D(1,:)/sqrt(2);
+        D(end,:) = D(end,:)/sqrt(2);
+    case 'II'
+        D = cos(pi*(2*c+1).*r/(2*K));
+        D(1,:) = D(1,:)/sqrt(2);
+    case 'III'
+        D = cos(pi*(2*r+1).*c/(2*K));
+        D(:,1) = D(:,1)/sqrt(2);
+    case 'IV'
+        D = cos(pi*(2*r+1+2*c+4*c.*r)/(4*K));
+    otherwise
+        error('unsupported dct type');
+end
+D = normcol(D);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/dictionaryMatrices/grassmannian.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,44 @@
+function [A G res muMin] = grassmannian(n,m,nIter,dd1,dd2,initA,verb)
+% grassmanian attempts to create an n by m matrix with minimal mutual
+% coherence using an iterative projection method.
+%
+% [A G res] = grassmanian(n,m,nIter,dd1,dd2,initA)
+%
+%
+%% Parameters and Defaults
+error(nargchk(2,7,nargin));
+
+if ~exist('verb','var')  || isempty(verb),  verb = false; end %verbose output
+if ~exist('initA','var') || isempty(initA), initA = randn(n,m); end %initial matrix
+if ~exist('dd2','var')   || isempty(dd2),   dd2 = 0.95; end %shrinking factor
+if ~exist('dd1','var')   || isempty(dd1),   dd1 = 0.9; end %percentage of coherences to be shrinked
+if ~exist('nIter','var') || isempty(nIter), nIter = 5; end %number of iterations
+
+%% Compute svd and gramian
+A = normc(initA); %normalise columns
+[Uinit Sigma] = svd(A); %calculate svd of the matrix
+G = A'*A; %gramian matrix
+
+muMin = sqrt((m-n)/(n*(m-1)));              %Lower bound on mutual coherence
+res = zeros(nIter,1);
+for iIter = 1:nIter
+   gg  = sort(abs(G(:))); %sort inner products from less to ost correlated
+   pos = find(abs(G(:))>gg(round(dd1*(m^2-m))) & abs(G(:)-1)>1e-6); 
+   G(pos) = G(pos)*dd2;
+   [U S V] = svd(G);
+   S(n+1:end,1+n:end) = 0;
+   G = U*S*V';
+   G = diag(1./abs(sqrt(diag(G))))*G*diag(1./abs(sqrt(diag(G))));
+   gg = sort(abs(G(:)));
+   pos = find(abs(G(:))>gg(round(dd1*(m^2-m))) & abs(G(:)-1)>1e-6);
+   res(iIter) = max(abs(G(pos)));
+   if verb
+    fprintf(1,'%6i  %12.8f   %12.8f  %12.8f \n',...
+            [iIter,muMin,mean(abs(G(pos))),max(abs(G(pos)))]);
+   end
+end
+
+[~, Sigma_gram V_gram] = svd(G); %calculate svd decomposition of gramian
+Sigma_new = sqrt(Sigma_gram(1:n,:)).*sign(Sigma);
+A = Uinit*Sigma_new*V_gram';
+A = normc(A);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/util/regularisedictionary.m	Wed Aug 31 10:53:10 2011 +0100
@@ -0,0 +1,41 @@
+function Dreg = regularisedictionary(D)
+% REGULARISEDICTIONARY regularise dictionary for sparse representation
+%
+% Example
+% Dreg = regularisedictionary(D)
+%
+% Input
+% - D: initial dictionary matrix.
+%
+% Output
+% - Dreg: regularised dictionary
+%
+% References:
+%
+% See also
+
+% Author(s): Daniele Barchiesi
+% Copyright 2011-2011
+
+[n m] = size(D);	%dimension and number of atoms
+[U S V] = svd(D);	%SVD decomposition of the dictionary
+G = V*(S'*S)*V';	%gram matrix (equivalent to D'*D)
+I = eye(m);			%identity matrix
+lambda = 1;		    %regularisation coefficient
+
+% Optimise the gram matrix
+cvx_begin							%start cvx optimisation problem
+	variable Greg(m,m) symmetric;	%declare optimisation variable to be an mxm symmetric matrix
+	expression residual(m,m)		%declare residual as an intermediate calculation step
+	residual = G-Greg;				%define residual
+	minimise (max(max(abs(Greg-I))));	%define objective function
+	subject to						%declare constraints
+		Greg == semidefinite(m);	%positive semidefinite cone membership
+		diag(Greg) == ones(m,1);	%unit diagonal
+		norm(residual,'fro') <= lambda;	%
+cvx_end
+
+[~, Sgram Vgram] = svd(Greg);		%SVD decomposition of gramian
+Snew = sqrt(Sgram(1:n,:)).*sign(S); %calculate singular values of the regularised dictionary
+Dreg = U*Snew*Vgram';				%calculate regularised dictionary
+Dreg = normc(Dreg);					%normalise columns of regularised dictionary