Main Content

How to Use Square Jacobi SVD HDL Optimized Block

This example shows how to use the Square Jacobi SVD HDL Optimized block to compute the singular value decomposition (SVD) of square matrices.

Two-Sided Jacobi SVD

The Square Jacobi HDL Optimized block uses the two-sided Jacobi algorithm to perform singular value decomposition. Given an input square matrix A, the block first computes the two-by-two SVD for off-diagonal elements, then applies the rotation to the A, U, and V matrices. Because the Jacobi algorithm can perform such computations in parallel, it is suitable for FPGA and ASIC applications. For more information, see Square Jacobi SVD HDL Optimized.

Define Simulation Parameters

Specify the dimension of the sample matrices, the number of input sample matrices, and the number of iterations of the Jacobi algorithm.

n = 8;
numSamples = 3;
nIterations = 10;

Generate Input A Matrices

Use the specified simulation parameters to generate the input matrix A.

rng('default');
A = randn(n,n,numSamples);

The Square Jacobi SVD HDL Optimized block supports both real and complex inputs. Set the complexity of the input in the block mask accordingly.

% A = complex(randn(n,n,numSamples),randn(n,n,numSamples));

Select Fixed-Point Data Types

Define the desired word length.

wordLength = 32;

Use the upper bound on the singular values to define fixed-point types that will never overflow. First, use the fixed.singularValueUpperBound function to determine the upper bound on the singular values.

svdUpperBound = fixed.singularValueUpperBound(n,n,max(abs(A(:))));

Define the integer length based on the value of the upper bound, with one additional bit for the sign, another additional bit for intermediate CORDIC growth, and one more bit for intermediate growth to compute the Jacobi rotations.

additionalBitGrowth = 3;
integerLength = ceil(log2(svdUpperBound)) + additionalBitGrowth;

Compute the fraction length based on the integer length and the desired word length.

fractionLength = wordLength - integerLength;

Define the signed fixed-point data type to be 'Fixed' or 'ScaledDouble'. You can also define the type to be 'double' or 'single'.

dataType = 'Fixed';
T.A = fi([],1,wordLength,fractionLength,'DataType',dataType);
disp(T.A)
[]

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 24

Cast the matrix A to the signed fixed-point type.

A = cast(A,'like',T.A);

Configure Model Workspace and Run Simulation

model = 'SquareJacobiSVDModel';
open_system(model);
setModelWorkspace(model,'A',A,'n',n,...
    'nIterations',nIterations,'numSamples',numSamples);
out = sim(model);

Verify Output Solutions

Verify the output solutions. In these steps, "identical" means within roundoff error.

  1. Verify that U*diag(s)*V' is identical to A. relativeErrorUSV represents the relative error between U*diag(s)*V' and A.

  2. Verify that the singular values s are identical to the floating-point SVD solution. relativeErrorS represents the relative error between s and the singular values calculated by the MATLAB® svd function.

  3. Verify that U and V are unitary matrices. relativeErrorUU represents the relative error between U'*U and the identity matrix. relativeErrorVV represents the relative error between V'*V and the identity matrix.

for i = 1:numSamples
    disp(['Sample #',num2str(i),':']);
    a = A(:,:,i);
    U = out.U(:,:,i);
    V = out.V(:,:,i);
    s = out.s(:,:,i);

    % Verify U*diag(s)*V'
    if norm(double(a)) > 1
        relativeErrorUSV = norm(double(U*diag(s)*V')-double(a))/norm(double(a));
    else
        relativeErrorUSV = norm(double(U*diag(s)*V')-double(a));
    end
    relativeErrorUSV %#ok

    % Verify s
    s_expected = svd(double(a));
    normS = norm(s_expected);
    relativeErrorS = norm(double(s) - s_expected);
    if normS > 1
        relativeErrorS = relativeErrorS/normS;
    end
    relativeErrorS %#ok

    % Verify U'*U
    U = double(U);
    UU = U'*U;
    relativeErrorUU = norm(UU - eye(size(UU))) %#ok

    % Verify V'*V
    V = double(V);
    VV = V'*V;
    relativeErrorVV = norm(VV - eye(size(VV))) %#ok

    disp('---------------');
end
Sample #1:

relativeErrorUSV =

   4.9236e-06


relativeErrorS =

   2.4379e-06


relativeErrorUU =

   5.9432e-07


relativeErrorVV =

   6.9467e-07

---------------
Sample #2:

relativeErrorUSV =

   6.0158e-06


relativeErrorS =

   2.4712e-06


relativeErrorUU =

   6.0220e-07


relativeErrorVV =

   5.2963e-07

---------------
Sample #3:

relativeErrorUSV =

   5.7222e-06


relativeErrorS =

   2.9780e-06


relativeErrorUU =

   5.3064e-07


relativeErrorVV =

   5.2115e-07

---------------

See Also

Blocks

Functions