/// <summary>
        /// Обратное дискретное вейвлет преобразование
        /// </summary>
        /// <param name="Decomp">Разложение сигнала</param>
        /// <returns>Исходный сигнал</returns>
        public List <double> Reconstruct(CDecomposition Decomp)
        {
            var Y = new List <double>();

            InitFilter(Decomp.WawletOrder);
            int l, m, u, i, k;
            int J = Decomp.J;
            var B = new double[J + 1][];
            var A = new double[J][];
            int L = Decomp.SignalLength;

            B[J] = new double[Decomp.SignalLength];

            for (int j = J; j > 0; j--)
            {
                B[j - 1] = new double[(int)Math.Pow(2, j - 1)];
                A[j - 1] = new double[(int)Math.Pow(2, j - 1)];
            }

            B[0][0] = Decomp.Approx[0];
            A[0][0] = Decomp.Details[0][0];

            for (int j = 1; j < J + 1; j++)
            {
                l = -2;
                m = -1;
                for (int t = 0; t < Math.Pow(2, j - 1); t++)
                {
                    l       = l + 2;
                    m       = m + 2;
                    u       = t;
                    i       = 1;
                    k       = 0;
                    B[j][l] = Gn[i] * Decomp.Details[j - 1][u] + Hn[i] * B[j - 1][u];
                    B[j][m] = Gn[k] * Decomp.Details[j - 1][u] + Hn[k] * B[j - 1][u];
                    if (M > 2)
                    {
                        for (int n = 1; n < M / 2; n++)
                        {
                            u = u + 1;
                            if (u >= Math.Pow(2, j - 1))
                            {
                                u = 0;
                            }
                            i        = i + 2;
                            k        = k + 2;
                            B[j][l] += Gn[i] * Decomp.Details[j - 1][u] + Hn[i] * B[j - 1][u];
                            B[j][m] += Gn[k] * Decomp.Details[j - 1][u] + Hn[k] * B[j - 1][u];
                        }
                    }
                }
            }
            for (int n = 0; n < B[J].Length; n++)
            {
                Y.Add(Math.Pow(L, 0.5) * B[J][n]);
            }
            return(Y);
        }
        /// <summary>
        /// Прямое дискретное вейвлет преобразование
        /// </summary>
        /// <param name="Yn">Сигнал</param>
        /// <param name="J">Степень двойки длины сигнала</param>
        /// <param name="N">Порядок вейвлета</param>
        /// <returns>Разложение сигнала</returns>
        public CDecomposition Decompose(List <double> Yn, int J, int N)
        {
            InitFilter(N);
            var L      = (int)Math.Pow(2, J);
            var Decomp = new CDecomposition(J);

            Decomp.SignalLength = Yn.Count;
            Decomp.WawletOrder  = N;
            Decomp.J            = J;

            int u;
            var B = new double[J + 1][];
            var A = new double[J][];

            B[J] = new double[L];
            for (int n = 0; n < L; n++)
            {
                B[J][n] = Math.Pow(L, -0.5) * Yn[n];
            }

            for (int j = J; j > 0; j--)
            {
                B[j - 1] = new double[(int)Math.Pow(2, j - 1)];
                A[j - 1] = new double[(int)Math.Pow(2, j - 1)];

                for (int t = 0; t < Math.Pow(2, j - 1); t++)
                {
                    u           = 2 * t + 1;
                    A[j - 1][t] = Gn[0] * B[j][u];
                    B[j - 1][t] = Hn[0] * B[j][u];
                    for (int n = 1; n < M; n++)
                    {
                        u = u - 1;
                        if (u < 0)
                        {
                            u = (int)Math.Pow(2, j) - 1;
                        }
                        A[j - 1][t] += Gn[n] * B[j][u];
                        B[j - 1][t] += Hn[n] * B[j][u];
                    }
                    Decomp.Details[j - 1].Add(A[j - 1][t]);
                }
            }
            Decomp.Approx.Add(B[0][0]);


            return(Decomp);
        }
        /// <summary>
        /// Обратное дискретное вейвлет преобразование
        /// </summary>
        /// <param name="Decomp">Разложение сигнала</param>
        /// <returns>Исходный сигнал</returns>
        public List<double> Reconstruct(CDecomposition Decomp)
        {
            var Y = new List<double>();
            InitFilter(Decomp.WawletOrder);
            int l, m, u, i, k;
            int J = Decomp.J;
            var B = new double[J + 1][];
            var A = new double[J][];
            int L = Decomp.SignalLength;

            B[J] = new double[Decomp.SignalLength];

            for (int j = J; j > 0; j--)
            {
                B[j - 1] = new double[(int) Math.Pow(2, j - 1)];
                A[j - 1] = new double[(int) Math.Pow(2, j - 1)];
            }

            B[0][0] = Decomp.Approx[0];
            A[0][0] = Decomp.Details[0][0];

            for (int j = 1; j < J + 1; j++)
            {
                l = -2;
                m = -1;
                for (int t = 0; t < Math.Pow(2, j - 1); t++)
                {
                    l = l + 2;
                    m = m + 2;
                    u = t;
                    i = 1;
                    k = 0;
                    B[j][l] = Gn[i]*Decomp.Details[j - 1][u] + Hn[i]*B[j - 1][u];
                    B[j][m] = Gn[k]*Decomp.Details[j - 1][u] + Hn[k]*B[j - 1][u];
                    if (M > 2)
                    {
                        for (int n = 1; n < M/2; n++)
                        {
                            u = u + 1;
                            if (u >= Math.Pow(2, j - 1))
                                u = 0;
                            i = i + 2;
                            k = k + 2;
                            B[j][l] += Gn[i]*Decomp.Details[j - 1][u] + Hn[i]*B[j - 1][u];
                            B[j][m] += Gn[k]*Decomp.Details[j - 1][u] + Hn[k]*B[j - 1][u];
                        }
                    }
                }
            }
            for (int n = 0; n < B[J].Length; n++)
                Y.Add(Math.Pow(L, 0.5)*B[J][n]);
            return Y;
        }
        /// <summary>
        /// Разделение сигнала
        /// </summary>
        /// <param name="Decomp">Разложение сигнала</param>
        /// <param name="j1">Пик №1</param>
        /// <param name="j2">Пик №2</param>
        /// <returns>Список разложений сигналов</returns>
        public List<CDecomposition> Divide(CDecomposition Decomp, int j1, int j2)
        {
            var LDecomp = new List<CDecomposition>();
            if (j2 == j1 + 2)
            {
                CDecomposition d1, d2;

                d1 = new CDecomposition(Decomp.J);
                d2 = new CDecomposition(Decomp.J);

                d1.J = Decomp.J;
                d1.WawletOrder = Decomp.WawletOrder;
                d1.SignalLength = Decomp.SignalLength;

                d2.J = Decomp.J;
                d2.WawletOrder = Decomp.WawletOrder;
                d2.SignalLength = Decomp.SignalLength;

                int z = j1 + 1; // level between j1 and j2
                var a = new double[(int) Math.Pow(2, z)];
                var b = new double[(int) Math.Pow(2, z)];

                for (int n = 0; n < a.Length; n++)
                {
                    a[n] = Decomp.Details[z - 1][n/2]*Decomp.Details[z - 1][n/2];
                    b[n] = (Decomp.Details[z + 1][2*n] + Decomp.Details[z + 1][2*n + 1])/2;
                }

                d1.Approx.Add(Decomp.Approx[0]);
                d2.Approx.Add(0);

                for (int j = 0; j < Decomp.J; j++)
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                        if (j < j1 + 1)
                            d1.Details[j].Add(Decomp.Details[j][i]);
                        else
                        {
                            if (j == z)
                            {
                                d1.Details[j].Add((a[i]/(a[i] + b[i]))*Decomp.Details[j][i]);
                            }
                            else
                                d1.Details[j].Add(0);
                        }

                for (int j = 0; j < Decomp.J; j++)
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                        if (j < j2 - 1)
                            d2.Details[j].Add(0);
                        else
                        {
                            if (j == z)
                            {
                                d2.Details[j].Add((b[i]/(a[i] + b[i]))*Decomp.Details[j][i]);
                            }
                            else
                                d2.Details[j].Add(Decomp.Details[j][i]);
                        }

                LDecomp.Add(d1);
                LDecomp.Add(d2);
            }
            else
            {
                CDecomposition d1, d2;

                d1 = new CDecomposition(Decomp.J);
                d2 = new CDecomposition(Decomp.J);

                d1.J = Decomp.J;
                d1.WawletOrder = Decomp.WawletOrder;
                d1.SignalLength = Decomp.SignalLength;

                d2.J = Decomp.J;
                d2.WawletOrder = Decomp.WawletOrder;
                d2.SignalLength = Decomp.SignalLength;

                d1.Approx.Add(Decomp.Approx[0]);
                d2.Approx.Add(0);

                for (int j = 0; j < Decomp.J; j++)
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                        if (j <= j1 + 1)
                            d1.Details[j].Add(Decomp.Details[j][i]);
                        else
                            d1.Details[j].Add(0);

                for (int j = 0; j < Decomp.J; j++)
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                        if (j <= j2 - 1)
                            d2.Details[j].Add(0);
                        else
                            d2.Details[j].Add(Decomp.Details[j][i]);

                LDecomp.Add(d1);
                LDecomp.Add(d2);
            }
            return LDecomp;
        }
        /// <summary>
        /// Прямое дискретное вейвлет преобразование
        /// </summary>
        /// <param name="Yn">Сигнал</param>
        /// <param name="J">Степень двойки длины сигнала</param>
        /// <param name="N">Порядок вейвлета</param>
        /// <returns>Разложение сигнала</returns>
        public CDecomposition Decompose(List<double> Yn, int J, int N)
        {
            InitFilter(N);
            var L = (int) Math.Pow(2, J);
            var Decomp = new CDecomposition(J);
            Decomp.SignalLength = Yn.Count;
            Decomp.WawletOrder = N;
            Decomp.J = J;

            int u;
            var B = new double[J + 1][];
            var A = new double[J][];

            B[J] = new double[L];
            for (int n = 0; n < L; n++)
                B[J][n] = Math.Pow(L, -0.5)*Yn[n];

            for (int j = J; j > 0; j--)
            {
                B[j - 1] = new double[(int) Math.Pow(2, j - 1)];
                A[j - 1] = new double[(int) Math.Pow(2, j - 1)];

                for (int t = 0; t < Math.Pow(2, j - 1); t++)
                {
                    u = 2*t + 1;
                    A[j - 1][t] = Gn[0]*B[j][u];
                    B[j - 1][t] = Hn[0]*B[j][u];
                    for (int n = 1; n < M; n++)
                    {
                        u = u - 1;
                        if (u < 0)
                            u = (int) Math.Pow(2, j) - 1;
                        A[j - 1][t] += Gn[n]*B[j][u];
                        B[j - 1][t] += Hn[n]*B[j][u];
                    }
                    Decomp.Details[j - 1].Add(A[j - 1][t]);
                }
            }
            Decomp.Approx.Add(B[0][0]);

            return Decomp;
        }
        /// <summary>
        /// Разделение сигнала
        /// </summary>
        /// <param name="Decomp">Разложение сигнала</param>
        /// <param name="j1">Пик №1</param>
        /// <param name="j2">Пик №2</param>
        /// <returns>Список разложений сигналов</returns>
        public List <CDecomposition> Divide(CDecomposition Decomp, int j1, int j2)
        {
            var LDecomp = new List <CDecomposition>();

            if (j2 == j1 + 2)
            {
                CDecomposition d1, d2;

                d1 = new CDecomposition(Decomp.J);
                d2 = new CDecomposition(Decomp.J);

                d1.J            = Decomp.J;
                d1.WawletOrder  = Decomp.WawletOrder;
                d1.SignalLength = Decomp.SignalLength;

                d2.J            = Decomp.J;
                d2.WawletOrder  = Decomp.WawletOrder;
                d2.SignalLength = Decomp.SignalLength;

                int z = j1 + 1; // level between j1 and j2
                var a = new double[(int)Math.Pow(2, z)];
                var b = new double[(int)Math.Pow(2, z)];

                for (int n = 0; n < a.Length; n++)
                {
                    a[n] = Decomp.Details[z - 1][n / 2] * Decomp.Details[z - 1][n / 2];
                    b[n] = (Decomp.Details[z + 1][2 * n] + Decomp.Details[z + 1][2 * n + 1]) / 2;
                }

                d1.Approx.Add(Decomp.Approx[0]);
                d2.Approx.Add(0);

                for (int j = 0; j < Decomp.J; j++)
                {
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                    {
                        if (j < j1 + 1)
                        {
                            d1.Details[j].Add(Decomp.Details[j][i]);
                        }
                        else
                        {
                            if (j == z)
                            {
                                d1.Details[j].Add((a[i] / (a[i] + b[i])) * Decomp.Details[j][i]);
                            }
                            else
                            {
                                d1.Details[j].Add(0);
                            }
                        }
                    }
                }

                for (int j = 0; j < Decomp.J; j++)
                {
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                    {
                        if (j < j2 - 1)
                        {
                            d2.Details[j].Add(0);
                        }
                        else
                        {
                            if (j == z)
                            {
                                d2.Details[j].Add((b[i] / (a[i] + b[i])) * Decomp.Details[j][i]);
                            }
                            else
                            {
                                d2.Details[j].Add(Decomp.Details[j][i]);
                            }
                        }
                    }
                }

                LDecomp.Add(d1);
                LDecomp.Add(d2);
            }
            else
            {
                CDecomposition d1, d2;

                d1 = new CDecomposition(Decomp.J);
                d2 = new CDecomposition(Decomp.J);

                d1.J            = Decomp.J;
                d1.WawletOrder  = Decomp.WawletOrder;
                d1.SignalLength = Decomp.SignalLength;

                d2.J            = Decomp.J;
                d2.WawletOrder  = Decomp.WawletOrder;
                d2.SignalLength = Decomp.SignalLength;


                d1.Approx.Add(Decomp.Approx[0]);
                d2.Approx.Add(0);

                for (int j = 0; j < Decomp.J; j++)
                {
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                    {
                        if (j <= j1 + 1)
                        {
                            d1.Details[j].Add(Decomp.Details[j][i]);
                        }
                        else
                        {
                            d1.Details[j].Add(0);
                        }
                    }
                }

                for (int j = 0; j < Decomp.J; j++)
                {
                    for (int i = 0; i < Decomp.Details[j].Count; i++)
                    {
                        if (j <= j2 - 1)
                        {
                            d2.Details[j].Add(0);
                        }
                        else
                        {
                            d2.Details[j].Add(Decomp.Details[j][i]);
                        }
                    }
                }

                LDecomp.Add(d1);
                LDecomp.Add(d2);
            }
            return(LDecomp);
        }