Пример #1
0
        /// <summary>
        /// Create a Vandermonde matrix of size row x column over GF16
        /// </summary>
        /// <remarks>
        /// The Vandermonde matrix is typically used to create the encoding matrix where:
        /// - The number of Columns of the matrix correspond to number of checksum
        /// packets.
        /// - The number of Rows of the matrix correspond to number of data packets.
        /// </remarks>
        /// <param name="columns">The number of columns of the Vandermonde matrix</param>
        /// <param name="rows">The number of rows of the Vandermode matrix</param>
        /// <returns></returns>
        public static UInt16[,] CreateVandermondeMatrix(int columns, int rows)
        {
            // TODO: Add input validation

            // maxChecksumPackets will be the max number of Columns of the encoding static matrix
            // maxDataPackets will be the max number of Rows of the encoding static matrix

            UInt16[,] vandermondeMtx = new UInt16[columns, rows];

            // Creation of the Vandermonde Matrix over GF16 with the following
            // (2^column)^row

            // As an example, a 5 x 3 Vandermonde Matrix over GF16 (5 data packets, 3 checksum packets)
            // would give the following:
            //
            // 1^0 2^0 4^0
            // 1^1 2^1 4^1
            // 1^2 2^2 4^2
            // 1^3 2^3 4^3
            // 1^4 2^4 4^4
            //
            // Which gives:
            //
            // 1   1   1
            // 1   2   4
            // 1   4   16
            // 1   8   64
            // 1   16  256

            for (int col = 0; col < columns; col++)
            {
                // multFactor is the number to multiply to get the value in the next row
                // for a given column of the Vandermonde matrix
                UInt16 multFactor = GF16.Power(2, (uint)col);
                for (int row = 0; row < rows; row++)
                {
                    if (row == 0)
                    {
                        // Special case the first row (power of zero)
                        vandermondeMtx[col, row] = 1;
                    }
                    else
                    {
                        // Each element of the Vandermonde matrix is calculated as (2^column)^row over GF16

                        // This algorithm uses the previous row to compute the next one to improve
                        // the performances (instead of recalculating (2^column)^row)
                        vandermondeMtx[col, row] = GF16.Multiply(vandermondeMtx[col, row - 1], multFactor);
                    }
                }
            }
            return(vandermondeMtx);
        }
        /// <summary>
        /// Create the decoding matrix
        /// </summary>
        /// <param name="nbDataPackets">Number of data packet</param>
        /// <param name="nbChecksumPackets">Number of checksum packet</param>
        /// <param name="rtpPackets">Array of rtpPackets</param>
        /// <returns>The decoding matrix</returns>
        /// <example>
        /// For example, if you have 3 data packets and 2 checksum
        /// packets and get the last data packet, you will get
        /// the following matrix
        /// 0   1   1
        /// 0   1   2
        /// 1   1   4
        /// </example>
        // TODO: To be more generic, we should use System.Array instead of array of BufferChunks
        public static GF16[,] DecodingMatrixGeneration(BufferChunk[] dataReceived, int nbChecksumPackets)
        {
            // nbTotalPackets is the total # rtpPackets to create (data packets and checksum packets)
            int nbTotalPackets = dataReceived.Length;
            int nbDataPackets  = nbTotalPackets - nbChecksumPackets;

            // Let's suppose that we lost the 2 first packets
            // So [E'] that should have been
            //  1   0   0   1   1
            //  0   1   0   1   2
            //  0   0   1   1   4
            // is actually
            //  0   1   1
            //  0   1   2
            //  1   1   4

            // The reverted decoding matrix will be multiplied by data received to get all the datas
            // for instance [D0..D2] = [D2 C0 C1] x 1/[E']
            // => So the number of columns should correspond to the number of data recieved + checksum received
            // and the number of rows should correspond of the number of data packet K

            // count the number of packets received
            int nbPacketsReceived = ReceivedPacketsCount(nbTotalPackets, dataReceived);

            // nbPacketsReceived columns, K rows
            // Note that the # columns is smaller than the number of packet received
            // in case the number of packet lost was smaller than the number than
            // the number of checksum packets (we short the matrix: It's like if we lost the last
            // checksum(s) packet(s)
            GF16[,] mtxEprime_GF16 = new GF16[nbPacketsReceived, nbDataPackets];

            // Construct the matrix mtxEprime_GF16 from the rtpPackets received
            // Note see also Jay's Decode method

            // Loop trough the data rtpPackets and put a 1 on the row of the packet
            // received

            int foundIndex = 0;

            for (int index = 0; index < nbDataPackets; index++)
            {
                if (dataReceived[index] != null) // not a packet lost
                {
                    // Generate a row in the mtxEprime_GF16 (decode matrix)
                    if (index < nbDataPackets)
                    {
                        // TODO: To be clean, we should have initialized all the other items
                        // on the row explicitely to zero or make sure their are set them to zero
                        // when creating the new matrix
                        mtxEprime_GF16[foundIndex, index] = (UInt16)1;
                    }
                    foundIndex++;
                    //                  if (foundIndex >= nbPacketsReceived-nbAdditionalPacketsReceived)
                    //                      return mtxEprime_GF16;
                }
            }

            // Generate a Vandermonde Mtx for the other items
            // TODO: Change that to use the Vandermonde static mtx
            for (UInt32 m = 0; m < nbChecksumPackets; m++)
            {
                // Note: If a checksum packet has been lost, the column is skiped
                if (dataReceived[m + nbDataPackets] != null) // not a packet lost
                {
                    for (UInt32 k = 0; k < nbDataPackets; k++)
                    {
                        // Each element of the Vandermonde matrix is calculated as (m+1)^k over GF16
                        // mtx[column, row] = (column+1)^row

                        // With Vandermonde: 1^x, 2^x, 3^x, ... the code was:
                        // mtxEprime_GF16[foundIndex, k] = GF16.Power((UInt16)(m+1), (UInt32)k);
                        // I experimented problems (no pivot found during invertion of Eprime)
                        // when losing 3 packets (worked fine when losing 2 packets)

                        // So I changed, to use Vandermonde matrix were mtx[column, row] = (2^column)^row
                        mtxEprime_GF16[foundIndex, k] = GF16.Power((UInt16)GF16.Power(2, (m)), (UInt32)k);

                        // TODO: Check if Jay's approach is more efficient: mtxE_GF16[m, k] = GF16.gf_exp[GF16.Modnn(k*m)];
                    }
                    foundIndex++;
                    //                  if (foundIndex >= nbPacketsReceived-nbAdditionalPacketsReceived)
                    //                      return mtxEprime_GF16;
                }
            } // for
            return(mtxEprime_GF16);
        }