Example #1
0
        // ----------------------------------------------------------------------------------
        // -------- ОСНОВНАЯ ФУНКЦИЯ РАСЧЕТА ------------------------------------------------
        // весовых коэффициентов калибровки датчика с помощью МНК
        // ----------------------------------------------------------------------------------
        public Matrix <double> CalcCalibrCoef(Matrix <double> Rmtx, Matrix <double> Umtx, Matrix <double> Pmtx, Matrix <double> Tmtx, double Pmax, Matrix <double> gammaP, Matrix <double> gammaT)
        {
            Matrix <double> resultBmtx;           // Возвращаемое значение - Матрица калибровочных коэффициентов
            //// -1 если не верные данные о погрешностях из текстового файла
            //// -2 если не верные входные данные (не согласованые матрицы)
            //// -3 если маскимальный ВПИ! равен 0
            //// -4 если рассчитанная матрица допустимых отклонений Fdop имеет нулевые значения



            Matrix <double> Kp;        // Матрица коэффициентов пернастройки(стартовая)

            Matrix <double> Fdop;      // Матрица допустимых отклонений Fdop (стартовая)
            Matrix <double> Fr;        // Матрица допустимых отклонений Fdop (расчетная)

            Matrix <double> Fkn1;      // Матрица фактических отклонений Fkn1 (стартовая с единичными весами)
            Matrix <double> Fkn;       //Рассчитываем фактические отклонения Fkn (расчетная)

            Matrix <double> M1;        // Матрица весов (стартовая, единичная)
            Matrix <double> M;         // Матрица весов (расчетная)
            Matrix <double> M_opt;     // Матрица весов (оптимальная)
            double          maxValueM; // максимальное значение веса матрицы M

            Matrix <double> B1;        // Матрица весовых коэффициентов (стартовая, для единичных весов)
            Matrix <double> B;         // Матрица весовых коэффициентов (расчетная, промежуточная)

            int Ndop;                  // Количество точек в допуске
            int Nmax;                  // Общее количество точек (число элементов в матрице)

            int    Kf_opt;             // Оптимальный Kf
            double Kmult_opt;          // Оптимальный Kmult

            int  Tdw_out_res;          // Промежуточный счетчик циклов подряд без решения
            int  Tdw_out_res_max;      // Предельное значение промежуточного счетчика циклов подряд без решения
            bool Exit_dw;              // Критерий выхода из цикла do -while



            // ---------- ЭТАП-1 ------------------------------------------------------------
            // ПОДГОТОВКА ДАННЫХ ДЛЯ РАСЧЕТА
            // ------------------------------------------------------------------------------

            // Определяем количество строк и столбцов входных матриц
            int rowP = Pmtx.RowCount;           // Количество строк матрицы Pmtx
            int colP = Pmtx.ColumnCount;        // Количество столбцов матрицы Pmtx

            int rowU = Umtx.RowCount;           // Количество строк матрицы Umtx
            int colU = Umtx.ColumnCount;        // Количество столбцов матрицы Umtx

            int rowR = Rmtx.RowCount;           // Количество строк матрицы Rmtx
            int colR = Rmtx.ColumnCount;        // Количество столбцов матрицы Rmtx

            int colT = Tmtx.ColumnCount;        // Количество столбцов матрицы Rmtx


            // Проверяем на соответствие размерности матриц
            if ((rowP != rowU) || (rowU != rowR) || (colP != colU) || (colU != colR) || (colR != colT))
            {
                resultBmtx = DenseMatrix.Create(1, 1, -2);  // возвращаем: -2 не верные входные данные
                return(resultBmtx);
            }

            // Проверка данныхпогрешностей Pa, Pb, Ta, Tb, из текстового файла
            if ((gammaP.ColumnCount < 2) || (gammaP.RowCount != 3) || (gammaT.ColumnCount != 2) || (gammaT.RowCount != 1))
            {
                resultBmtx = DenseMatrix.Create(1, 1, -1);  // возвращаем: -1 не верные данные о погрешностях из текстового файла
                return(resultBmtx);
            }

            // Проверка Pmax на ноль
            if (Pmax == 0)
            {
                resultBmtx = DenseMatrix.Create(1, 1, -3);  // возвращаем: -3 маскимальный ВПИ! равен 0 - это ошибка
                return(resultBmtx);
            }


            // Если размерности входных данных согласованы
            // Определяем общее количество точек (число элементов в матрице)
            Nmax = rowP * colP;

            // Нормируем матрицу P
            //Это можно перенести пораньше, сразу после формирования матрицы P и определения Pmax
            Matrix <double> Pn = DenseMatrix.Create(rowP, colP, 0);

            for (int i = 0; i < rowP; i++)
            {
                for (int j = 0; j < colP; j++)
                {
                    Pn[i, j] = Pmtx.At(i, j) / Pmax;
                }
            }

            // Формируем единичную матрицу весов M
            M1    = DenseMatrix.Create(rowP, colP, 1);
            M_opt = M1;

            // Рассчитываем матрицу коэффициентов B1(при единичной матрице весов М)
            B1 = CalcB(rowP, colP, M1, Pn, Umtx, Rmtx);
            if ((B1.RowCount == 1) && (B1.At(0, 0) == -1))
            {
                resultBmtx = DenseMatrix.Create(1, 1, 0);  // возвращаем: -1 решения нет
                return(resultBmtx);
            }

            // ФОРМИРОВАНИЕ СТАРТОВОЙ РАСЧЕТНОЙ ГРАНИЦЫ
            // Составляем матрицу коэффициентов пернастройки, где все Kp = 0
            Kp = DenseMatrix.Create(rowP, colP, 0);
            double Kpmax = -1;

            // Составляем матрицу коэффициентов пернастройки Kp, кроме точек, где P(i, j) == 0
            for (int i = 0; i < rowP; i++)
            {
                for (int j = 0; j < colP; j++)
                {
                    if (Pmtx.At(i, j) != 0)
                    {
                        Kp[i, j] = Pmax / Math.Abs(Pmtx.At(i, j));        //abs(P(i, j)), чтобы обеспечить универсальность формулы относителньо вида давления(ДД, ДИВ, ДА и пр)
                        {
                            if (Kp[i, j] > Kpmax)
                            {
                                Kpmax = Kp.At(i, j);
                            }
                        }
                    }
                }
            }

            // Ограничение на Kpmax
            if (Kpmax > Kpmax_dop)
            {
                Kpmax = Kpmax_dop;
            }

            // Окончательное формирование матрицы коэффициентов пернастройки Kp
            for (int i = 0; i < rowP; i++)
            {
                for (int j = 0; j < colP; j++)
                {
                    if ((Kp.At(i, j) == 0) || (Kp.At(i, j) > Kpmax))
                    {
                        Kp[i, j] = Kpmax;
                    }
                }
            }

            // Рассчитываем матрицу допустимых отклонений Fdop(размерностью N, K)
            // Внутри функции должно быть определение какой тип датчика (ЭнИ - 100 или ЭнИ - 12, или может быть другой новый тип)
            Fdop = CalcFdop(rowP, colP, Kf, Kp, Tmtx, Tnku, gammaP, gammaT);

            // Проверка рассчитанной матрицы допустимых отклонений Fdop на отсутствие нулевых элементов
            // Если нулевые элементы есть, следовательно нет решения, выходим из функции (возвращаем -1)
            int  ind  = 0;
            bool flag = true;

            while ((ind < rowP) && (flag))
            {
                for (int j = 0; j < colP; j++)
                {
                    if (Fdop.At(ind, j) == 0)
                    {
                        flag = false;
                        break;
                    }
                }
                ind = ind + 1;
            }

            if (flag == false)
            {
                resultBmtx = DenseMatrix.Create(1, 1, -4);  // возвращаем: -4
                return(resultBmtx);
            }

            //Рассчитываем фактические отклонения Fkn(формула 5, стр. 10)
            Fkn1 = CalcFkn(rowP, colP, B1, Rmtx, Umtx, Pn, Kp);



            // ---------- ЭТАП - 2 --------------------------------------------------------
            // ОСНОВНОЙ АЛГОРИТМ РАСЧЕТА
            // ПОИСК Kf
            // ----------------------------------------------------------------------------

            // Флаг решение false - не найдено, true - найдено
            bool   flagFindR    = false;
            bool   flagExitCalc = false;
            double dM           = 0;

            maxValueM = 0;
            Kf_opt    = 6;

            for (int Kf = 1; Kf < Kpmax_dop; Kf++)  // Изменил предельное значение "10" на "Kpmax_dop"
            {
                // Рассчитываем матрицу допустимых отклонений Fdop для заданного Kf
                Fdop = CalcFdop(rowP, colP, Kf, Kp, Tmtx, Tnku, gammaP, gammaT);

                // Формируем расчетную матрицу Fr(на старте она равна допускаемой Fdop)
                Fr = Fdop;

                // Формируем матрицу единичных весовов М (на старте она равна единичной матрице)
                M = M1;
                M = DenseMatrix.Create(rowP, colP, 1);

                // Вычисляем матрицу фактических отклонений Fkn(на старте она равна фактическим отклонениям при единичных весовых коэффициентах)
                Fkn = Fkn1;

                // Определяем кол - во точек в допуске
                Ndop = CalcNdop(rowP, colP, Fkn1, Fr);

                // Если не все точки в допуске
                if (Ndop < Nmax)
                {
                    //maxValueM = 0;
                    // Организуем цикл по а до Amax
                    for (int a = 0; a < Amax; a++)
                    {
                        flagExitCalc = false;

                        // Перерассчитываем веса матрицы М
                        for (int N = 0; N < rowP; N++)
                        {
                            for (int K = 0; K < colP; K++)
                            {
                                // нужна проверка для Fr(N, K) не равно нулю, если равно, то выходим из расчета
                                if (Fr.At(N, K) != 0)
                                {
                                    dM      = KdM * (Fkn.At(N, K) - Fr.At(N, K)) * M.At(N, K) / Fr.At(N, K);
                                    M[N, K] = Math.Round(M.At(N, K) + dM, 4);
                                    //M[N, K] = M.At(N, K) + dM;
                                }
                                else
                                {
                                    flagExitCalc = true;
                                    break;
                                }
                            }
                            if (flagExitCalc)
                            {
                                break;
                            }
                        }

                        // Перерассчитываем коэф.полинома В для новой матрицы весом М
                        B = CalcB(rowP, colP, M, Pn, Umtx, Rmtx);

                        // Перерассчитываем фактические отклонения Fkn для новых коэф В
                        Fkn = CalcFkn(rowP, colP, B, Rmtx, Umtx, Pn, Kp);

                        // Определяем кол - во точек в допуске
                        Ndop = CalcNdop(rowP, colP, Fkn, Fr);

                        // Если все точки в допуске решение найдено
                        if (Ndop == Nmax)
                        {
                            flagFindR = true;
                            break;
                        }
                        // если нет
                        else
                        {
                            // Находим максимальное значение эл.матрицы М
                            maxValueM = maxValMatrix(M);

                            // Проверяем превышают ли веса М максимально допустимое Mmax
                            if (maxValueM > Mmax)
                            {
                                // если да, то выходим из цикла по Amax
                                break;
                            }
                        } // для  if (Ndop == Nmax)
                    }     //  for (int a = 0; a < Amax; a++)
                }
                else
                {
                    // Решение найдено, устанавливаем флаг
                    flagFindR = true;
                } // для if (Ndop ~= Nmax)



                //  Если решение найдено(флаг = 1) выходим из цикла
                if (flagFindR)
                {
                    Kf_opt = Kf;
                    break;
                }
            } // для for Kf = 1 : 1 : 10

            if ((Kf == Kpmax_dop) && (flagFindR == false))
            {
                // Изменил в условие "Kf == 10" на условие "Kf == Kpmax_dop" ПЕРЕИМЕНОВАТЬ Kf в Kf_opt до конца кода
                Kf_opt = 6;
            }

            // Рассчитываем матрицу допустимых отклонений Fdop для заданного Kf
            Fdop = CalcFdop(rowP, colP, Kf_opt, Kp, Tmtx, Tnku, gammaP, gammaT);



            // ---------- ЭТАП - 3 -----------------------------------------------------
            //  ОСНОВНОЙ АЛГОРИТМ РАСЧЕТА
            // ПОИСК ОПТИМАЛЬНОГО РЕШЕНИЯ
            // -------------------------------------------------------------------------

            //  Рассчет r_opt
            double r = 0;
            double r_opt;

            maxValueM = 0;

            for (int N = 0; N < rowP; N++)
            {
                for (int K = 0; K < colP; K++)
                {
                    r = r + Math.Abs(Fkn1.At(N, K) / Fdop.At(N, K));
                }
            }
            r_opt = r / Nmax;


            double Kmult = 1;

            while (Kmult >= 0.1)
            {
                // Задаем, обновляем переменные
                //Tdw = 0;                    // счетчик всех циклов do -while
                //Tdw_opt = 0;                 // количество найденных не оптимальных решений подряд
                //Tdw_opt_max = 50;           // макс.кол - во решений в допуске но НЕ оптимальных
                Tdw_out_res     = 0;        // промежуточный счетчик циклов подряд без решения
                Tdw_out_res_max = 50;       // предельное значение промежуточного счетчика циклов подряд без решения
                //Tdw_out_res_sum = 0;        // общий счетчик циклов в сумме без решения
                //Tdw_out_res_sum_max = 100;  // предельное количество циклов в сумме без решения
                //Res_count = 0;              // счетчик найденных решений
                //Res_count_max = 100;        // максимальное количество найденных решений
                Exit_dw = false;            // критерий выхода из цикла do -while

                // Формируем матрицу единичных весовов М
                M = M1;
                //M = DenseMatrix.Create(rowP, colP, 1);

                // Вычисляем матрицу фактических отклонеий Fkn
                Fkn = Fkn1;

                // Формируем стартовую рассчетную границу(для заданного Kmult)
                Fr = Fdop.Multiply(Kmult);

                while (Exit_dw == false)
                {
                    flagExitCalc = false;
                    //Tdw = Tdw + 1;   // Считаем количество всех циклов do -while
                    //Tdw_out_res_sum = Tdw_out_res_sum + 1;     // Считаем количество всех циклов do -while в сумме без решения, независимо от того было ли найдено решение или нет

                    // Расчет коэффициентов B
                    B = CalcB(rowP, colP, M, Pn, Umtx, Rmtx);

                    // Рассчитываем фактические отклонения Fkn(формула 5, стр. 10)
                    Fkn = CalcFkn(rowP, colP, B, Rmtx, Umtx, Pn, Kp);


                    // Определяем кол - во точек в допуске
                    Ndop = CalcNdop(rowP, colP, Fkn, Fr);

                    // Если все точки в допуске решение найдено
                    if (Ndop == Nmax)
                    {
                        //Tdw_opt = Tdw_opt + 1;    // Считаем количество найденных решений подряд, как только решение отсутствует, параметр обнуляется
                        // Расчет среднего значения относительного отклонения по модулю
                        r = 0;

                        for (int N = 0; N < rowP; N++)
                        {
                            for (int K = 0; K < colP; K++)
                            {
                                r = Math.Round(r + Math.Abs(Fkn.At(N, K) / Fdop.At(N, K)), 4);
                            }
                        }
                        r = r / Nmax;

                        // Сравниваем текущую r с r_opt, если r меньше, то перезаписываем r_opt
                        if (r < r_opt)
                        {
                            // Оптимальное решение найдено
                            r_opt     = r;
                            M_opt     = M;
                            Kmult_opt = Kmult;
                            //Tdw_opt = 0;
                        }

                        // Считаем общее количество найденных решений, независимо от того, было ли отсутствие решения
                        //Res_count = Res_count + 1;
                        Tdw_out_res = 0;   // обнуляем промежуточный счетчик циклов без решения, в связи с найденным решением
                        // Понижение расчетной границы Fr
                        Fr = CalcFr_cur(rowP, colP, Fr, Fkn, deltaFdop_min, Fr_min, deltaFkn_min);

                        //если не все точки в допуске(решение не найдено)
                    }
                    else
                    {
                        // увеличиваем промежуточный счетчик циклов без решения
                        Tdw_out_res = Tdw_out_res + 1;
                    }


                    // Перерассчитываем веса матрицы М
                    for (int N = 0; N < rowP; N++)
                    {
                        for (int K = 0; K < colP; K++)
                        {
                            // нужна проверка для Fr(N, K) не равно нулю, если равно, то выходим из расчета
                            if (Fr.At(N, K) != 0)
                            {
                                dM      = KdM * (Fkn.At(N, K) - Fr.At(N, K)) * M.At(N, K) / Fr.At(N, K);
                                M[N, K] = M.At(N, K) + dM;
                                nm++;
                            }
                            else
                            {
                                flagExitCalc = true;
                                break;
                            }
                        }
                        if (flagExitCalc)
                        {
                            break;
                        }
                    }


                    // Находим максимальное значение элементов матрицы М
                    maxValueM = maxValMatrix(M);

                    // Проверка условий выхода их цикла do -while
                    // 1.Если общее количество найденных решений Res_count, независимо от того, было ли отсутствие решения, больше, чем максимальное
                    // значение этого параметра Res_count_max, то выход из do -while
                    // 2.Если максимальное значение элементов матрицы М maxVal больше, чем Mmax, то выходим
                    // 3.Если общий счетчик циклов в сумме без решения
                    // Tdw_out_res_sum больше, чем допускаемое количество Tdw_out_res_sum_max, то выходим
                    // 4.Если количество найденных не оптимальных решений подряд Tdw_opt больше, чем допускаемое количество Tdw_opt_max, то выходим.

                    if ((maxValueM > Mmax) || (Tdw_out_res > Tdw_out_res_max))
                    {
                        Exit_dw = true;  // критерий выхода из цикла do -while
                    }
                } // для while(Exit_dw == 0)

                Kmult = Kmult - 0.3;
            } // для for Kmult = 1 : -0.1 : 0.1



            // ----------ЭТАП - 4--------------------
            // ОБРАБОТКА РЕЗУЛЬТАТОВ
            // --------------------------------------
            nm = nm + 0;
            // Расчет коэффициентов B
            Matrix <double> BmtxRes = DenseMatrix.Create(24, 1, 0);

            // Расчет коэффициентов B
            BmtxRes = CalcB(rowP, colP, M_opt, Pn, Umtx, Rmtx);

            // Рассчитываем фактические отклонения Fkn(формула 5, стр. 10)
            Fkn = CalcFkn(rowP, colP, BmtxRes, Rmtx, Umtx, Pn, Kp);

            resultBmtx = DenseMatrix.Create(24, 1, 0);
            resultBmtx = BmtxRes;
            return(resultBmtx);

            // КОНЕЦ РАСЧЕТА //



            /*
             *
             *
             *
             * // ФУНКЦИЯ ОБНУЛЕНИЯ ДАТЧИКА
             * //-------------------------------------------------------------------------
             * // В этой функции серьезные проблемы с универсальностью. Буду думать уже в
             * // отпуске. Не успел подумать. Точка по давлению 0 может отсутствовать! И
             * // как быть в этом случае. Обнулить ближайшую к нулю точку по давлению? Буду
             * // думать.А можно точку ноль аппроксимировать и потом обнулять ?
             * // Пока это работает для ДД, ДИ, ДВ.
             * //-------------------------------------------------------------------------
             *
             * // Ищем координаты точки с нулевым давлением и на НКУ.
             * int col = -1;
             * for (int i = 0; i < Tmtx.ColumnCount; i++)
             * {
             *  if (Tmtx.At(0, i) == 23)
             *  {
             *      col = i+1;
             *      break;
             *  }
             * }
             * if (col == -1)
             * {
             *  resultBmtx = DenseMatrix.Create(1, 1, -4);
             *  return resultBmtx;
             * }
             *
             *
             * int row = -1;
             * for (int i = 0; i < rowP; i++)
             * {
             *  if (Pmtx.At(i, col) == 0)
             *  {
             *      row = i+1;
             *      break;
             *  }
             * }
             * if (row == -1)
             * {
             *  resultBmtx = DenseMatrix.Create(1, 1, -5);
             *  return resultBmtx;
             * }
             *
             * // Ищем фактические отклонения, но с учетом знака(не по модулю как в CalcFkn)
             * Matrix<double> Fkn_sign = DenseMatrix.Create(rowP, colP, 0);
             *
             * // цикл по N(строкам матриц M, P, R, U)
             * for (int N = 0; N < rowP; N++)
             * {
             *  // цикл по K(столбцам матриц M, P, R, U)
             *  for (int K = 0; K < colP; K++)
             *  {
             *      double Fi = 0;
             *      int m = 0;
             *      // цикл по j
             *      for (int j = 0; j < 6; j++)
             *      {
             *          // цикл по i
             *          for (int i = 0; i < 4; i++)
             *          {
             *              Fi = Fi + BmtxRes.At(m,0) * Math.Pow(Rmtx.At(N, K), i) * Math.Pow(Umtx.At(N, K), j);
             *              m = m + 1;
             *          }
             *      }
             *      Fkn_sign[N, K] = (Fi - Pn.At(N, K)) * 100 * Kp.At(N, K);
             *  }
             * }
             *
             *
             * // Обнуляем фактические отклонения по значению на НКУ и в 0 точке
             * for (int N = 0; N < rowP; N++)
             *  {
             *  for (int K = 0; K < colP; K++)
             *  {
             *      Fkn[N, K] = Math.Abs(Fkn_sign.At(N, K) / Kp.At(N, K) - Fkn_sign.At(row, col) / Kp.At(row, col)) * Kp.At(N, K);
             *  }
             * }
             *
             * // Тип датчика
             *
             * Vector<double> code_acc = DenseVector.Create(gammaTa.RowCount, 0);
             * code_acc = gammaTa.Column(0, 0, gammaTa.RowCount);
             *
             * int code_opt = -1;
             *
             * // окончательная допускаемая граница по которой определяем код точности с учетом коэф. запаса
             * Matrix<double> Fdop_res = DenseMatrix.Create(rowP, colP, 0);
             * Matrix<double> gamma_P = DenseMatrix.Create(1, 2, 0);
             * Matrix<double> gamma_T = DenseMatrix.Create(1, 2, 0);
             *
             * for (int cc = 1; cc < code_acc.Count; cc++)
             * {
             *  curCode = Convert.ToInt32(gammaPa.At(cc, 0));
             *  for (int i = 0; i < rowP; i++)
             *  {
             *      for (int j = 0; j < colP; j++)
             *      {
             *          if (Kp.At(i, j) < Kf)
             *          {
             *              // Получаем коэффициенты а и b осн.приведенной погрешности
             *              gamma_P = CalcGammaP(Kp.At(i, j), curCode, gammaPa, gammaPb);
             *              // Получаем коэффициенты а и b доп.температурной погрешности
             *              gamma_T = CalcGammaT(curCode, sens, gammaTa, gammaTb);
             *              // Расчет Fdop
             *              Fdop_res[i, j] = ((gamma_P.At(0, 0) + gamma_P.At(0, 1) * Kp.At(i, j)) + (gamma_T.At(0, 0) + gamma_T.At(0, 1) * Kp.At(i, j)) * (Math.Abs(Tmtx.At(0, j) - Tnku) / 10))*(0.5 + 0.05 * (Math.Abs(Tmtx.At(0, j) - Tnku) / 10)) * 0.9;
             *          }
             *
             *          else
             *          {
             *              // Получаем коэффициенты а и b осн.приведенной погрешности
             *              gamma_P = CalcGammaP(Kf, curCode, gammaPa, gammaPb);
             *              // Получаем коэффициенты а и b доп.температурной погрешности
             *              gamma_T = CalcGammaT(curCode, sens, gammaTa, gammaTb);
             *              // Расчет Fdop
             *              Fdop_res[i, j] = ((gamma_P.At(0, 0) + gamma_P.At(0, 1) * Kf) + (gamma_T.At(0, 0) + gamma_T.At(0, 1) * Kf) * (Math.Abs(Tmtx.At(0, j) - Tnku) / 10)) *(0.5 + 0.05 * (Math.Abs(Tmtx.At(0, j) - Tnku) / 10)) * 0.9;
             *          }
             *      }
             *  }
             *
             *  Ndop = CalcNdop(rowP, colP, Fkn, Fdop_res);
             *
             *
             *  if (Ndop == Nmax)
             *  {
             *      code_opt = curCode;
             *      break;
             *  }
             * }
             *
             * if (code_opt == -1)
             * {
             *  resultBmtx = DenseMatrix.Create(1, 1, -1);  // возвращаем: -6 не попали ни в какой код точности
             *  return resultBmtx;
             * }
             *
             * resultBmtx = DenseMatrix.Create(24, 1, 0);
             * resultBmtx = BmtxRes;
             * return resultBmtx;*/
        }