Doxygen — различия между версиями
Korogodin (обсуждение | вклад) |
Korogodin (обсуждение | вклад) |
||
(не показаны 15 промежуточных версий 1 участника) | |||
Строка 7: | Строка 7: | ||
Для html-представления документации, размещаемого на web-серверах, существует удобный способ организации поиска (при помощи создаваемого Doxygen'ом PHP-модуля) и ссылок на внешнюю документацию. | Для html-представления документации, размещаемого на web-серверах, существует удобный способ организации поиска (при помощи создаваемого Doxygen'ом PHP-модуля) и ссылок на внешнюю документацию. | ||
− | Doxygen - консольная программа в духе классической Unix. Она работает подобно компилятору, анализируя исходные тексты и создавая документацию. | + | Doxygen - консольная программа в духе классической Unix. Она работает подобно компилятору, анализируя исходные тексты и создавая документацию. |
+ | |||
== Что требуется установить для полноценной работы == | == Что требуется установить для полноценной работы == | ||
+ | |||
=== Doxygen === | === Doxygen === | ||
Основная программа | Основная программа | ||
+ | |||
=== Graphiz === | === Graphiz === | ||
− | Graphviz – это свободно распространяемый пакет утилит для визуализации данных. Нам он нужен для того, чтобы Doxygen мог показать в документации отношения наследования, графы вызовов и прочую информацию в виде наглядных изображений. | + | [http://ru.wikipedia.org/wiki/Graphviz Graphviz] – это свободно распространяемый пакет утилит для визуализации данных. Нам он нужен для того, чтобы Doxygen мог показать в документации отношения наследования, графы вызовов и прочую информацию в виде наглядных изображений. |
+ | |||
=== LaTeX === | === LaTeX === | ||
При установленном пакете того или иного LaTeX-дистрибутива, Doxygen конвертирует TeX-разметку в комментариях в изображения, а затем вставляет их в итоговый отчет. Также генерирует TeX-файлы, а затем PDF. | При установленном пакете того или иного LaTeX-дистрибутива, Doxygen конвертирует TeX-разметку в комментариях в изображения, а затем вставляет их в итоговый отчет. Также генерирует TeX-файлы, а затем PDF. | ||
+ | |||
=== Doxywizard === | === Doxywizard === | ||
Строка 1309: | Строка 1314: | ||
</div> | </div> | ||
− | == | + | |
+ | ==Комментирование исходного текста== | ||
+ | Практически любой элемент программы (класс, функция, переменная) может быть задокументирован в системе Doxygen.<br> | ||
+ | Документирование выполняется на основе двух видов комментариев:<br> | ||
+ | * краткий (brief) | ||
+ | * и полный (detailed). | ||
+ | |||
+ | Краткие комментарии обычно описывают предназначение комментируемого элемента, а полные содержат информацию по его использованию и функционированию и чаще всего являются многострочными.<br> | ||
+ | К каждому элементу программы не может быть привязано более одного краткого и полного комментария.<br> | ||
+ | Для документирования какого-либо элемента программы, соответствующий комментарий располагают перед этим элементом в тексте программы. Например: | ||
+ | |||
+ | //! Оценка вектора состояния СС за дисперсией квадратурных компонент | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | Существует множество вариантов оформления комментариев:<br> | ||
+ | |||
+ | * Возможно использовать комментарии в стиле системы JavaDoc, применяемой при документировании исходных текстов на языке Java: | ||
+ | |||
+ | /** | ||
+ | * Оценка вектора состояния СС за дисперсией квадратурных компонент | ||
+ | */ | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | или так | ||
+ | |||
+ | /*! | ||
+ | * Оценка вектора состояния СС за дисперсией квадратурных компонент | ||
+ | */ | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | как и для предыдущего случая, знаки "*" не обязательны для промежуточных строк: | ||
+ | |||
+ | /*! | ||
+ | Оценка вектора состояния СС за дисперсией квадратурных компонент | ||
+ | */ | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | * Еще один вариант - использование дополнительных знаков "/" или "!" в каждой строке (QT-Style): | ||
+ | |||
+ | /// | ||
+ | /// Оценка вектора состояния СС за дисперсией квадратурных компонент | ||
+ | /// | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | или | ||
+ | |||
+ | //! | ||
+ | //! Оценка вектора состояния СС за дисперсией квадратурных компонент | ||
+ | //! | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | |||
+ | По умолчанию любой многострочный комментарий является подробным. Для объявления кратких комментариев можно так же использовать несколько методов:<br> | ||
+ | |||
+ | * Использование команды \brief в блоке комментария: | ||
+ | |||
+ | /*! \brief краткий комментарий. | ||
+ | * краткий комментарий. | ||
+ | * | ||
+ | * после пустой строки начинается подробный комментарий. | ||
+ | */ | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | 2.Для однострочных комментариев: | ||
+ | |||
+ | /// краткое описание. | ||
+ | /** Полное описание. */ | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | или | ||
+ | |||
+ | //! краткое описание. | ||
+ | //! многострочное | ||
+ | //! подробное описание. | ||
+ | int x_stdn2_est; | ||
+ | |||
+ | Иногда желательно расположить комментарий после, либо на одной строке с описываемым элементом. Для такого случая так же существуют несколько возможных способов:<br> | ||
+ | |||
+ | 1. int x_stdn2_est;; /*!< Подробный комментарий */ | ||
+ | 2. int x_stdn2_est;; /**< Подробный комментарий */ | ||
+ | 3. int x_stdn2_est;; //!< Подробный комментарий | ||
+ | 4. //!< | ||
+ | 5. int x_stdn2_est;; ///< Подробный комментарий | ||
+ | ///< | ||
+ | 6. int x_stdn2_est;; //!< Краткий комментарий | ||
+ | 7. int x_stdn2_est;; ///< Краткий комментарий | ||
+ | |||
+ | |||
+ | Обычно предполагается, что документирующие комментарии находятся рядом с документируемым элементом. Однако, Doxygen позволяет поместить комментарий практически в любой части файла, связав его с каким-либо элементом. В этом случае необходимо указывать в блоке комментария ряд специальных команд.<br> | ||
+ | Например так будет выглядеть описание класса Test, размещенное в любом месте файла:<br> | ||
+ | |||
+ | /*! \class Test | ||
+ | \brief Тестовый класс. | ||
+ | |||
+ | Полное описание класса. | ||
+ | */ | ||
+ | |||
+ | Кроме команды \class, можно использовать множество других:<br> | ||
+ | \struct - документирует структуру | ||
+ | \union - документирует объединение | ||
+ | \enum - документирует перечисление | ||
+ | \fn - документирует функцию | ||
+ | \var - документирует переменную | ||
+ | \def - документирует макрос подстановки #define | ||
+ | \file - документирует файл | ||
+ | \namespace - документирует пространство имен. | ||
+ | \typedef - документирование объявления типа | ||
+ | \interface - документирование IDL интерфейса | ||
+ | \package - документирование пакета на языке Java | ||
+ | |||
+ | |||
+ | == Востребованные команды == | ||
+ | |||
+ | |||
+ | === Комментирование структур, переменных и т.д. === | ||
+ | |||
+ | Переменные часто удобно объединять в группы: | ||
+ | <source lang="c"> | ||
+ | /** @name Аккумуляторы и их триггеры */ | ||
+ | quint32 R2; ///< Первичный акк. \f$ I^2 + Q^2 \f$ | ||
+ | quint64 R4; ///< Первичный акк. \f$ (I^2 + Q^2)^2 \f$ | ||
+ | |||
+ | quint32 R2_acum; ///< Вторичный аккумулятор R2 | ||
+ | quint64 R4_acum; ///< Вторичный аккумулятор R4 | ||
+ | |||
+ | quint32 R2_acum_copy; ///< Триггер R2_acum | ||
+ | quint64 R4_acum_copy; ///< Триггер R4_acum | ||
+ | //@} | ||
+ | </source> | ||
+ | |||
+ | |||
+ | === Комментирование функции === | ||
+ | |||
+ | <source lang="c"> | ||
+ | /** | ||
+ | Позволяет установить оценку дисперсии (мощности шумовой составляющей) корреляционных сумм и | ||
+ | зафиксировать её. | ||
+ | @param PoMe - указатель на структуру данных блока оценки с/ш | ||
+ | @param stdn2_IQ - устанавливаемое значение оценки дисперсии квадратур | ||
+ | @return 0, если прошло успешно, 1, если предлагаемое число после сдвига не влазиет в 32 разряда | ||
+ | */ | ||
+ | int SetVariancePowerMeasure(PowerMeasure_struct *PoMe, quint32 stdn2_IQ ){ | ||
+ | if (__CLZ(stdn2_IQ) >= x_stdn2_shift){ // Если предлагаемое число можно сдвинуть, не переполнив 32 разряда | ||
+ | PoMe->x_stdn2_est = stdn2_IQ; | ||
+ | // В случае увеличения порядка фильтра добавить сюда PoMe->x_stdn2_extr = stdn2_IQ; | ||
+ | PoMe->x_stdn2_est_shifted = stdn2_IQ<<x_stdn2_shift; | ||
+ | return 0; | ||
+ | }else return 1; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | === Вставка TeX-формул === | ||
+ | |||
+ | Для вставки TeX-формулы используются команды <code>\f$ ... \f$</code> и <code>\f[ ... \f] </code>, которые обрамляют TeX-разметку: | ||
+ | |||
+ | Выражение в тексте: | ||
+ | <source lang="c"> | ||
+ | /** Всё гениальное просто: \f$ E = mc^2 \f$ */ | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Выражение по центру, с новой строки: | ||
+ | <source lang="c"> | ||
+ | /** Воспользуемся дискриминатором | ||
+ | \f[ | ||
+ | u_{d,k} = - atan{frac{Q_k}{I_k}}, | ||
+ | \f] | ||
+ | его характеристики хорошо изучены, работа наглядна. | ||
+ | */ | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Для расширенного синтаксиса нужно дополнить опцию в Doxyfile'e: | ||
+ | <source lang="bash"> | ||
+ | EXTRA_PACKAGES = amssymb,amsfonts,amsmath,mathtext | ||
+ | </source> | ||
+ | |||
+ | |||
+ | === Bug, ToDo, Warning, Note === | ||
+ | |||
+ | Одноименные команды вставляют одноименные заметки. Далее doxygen формирует отдельные списки, по которым можно быстро найти интересующее место в коде. | ||
+ | |||
+ | <source lang="c"> | ||
+ | /** | ||
+ | @warning Не трогать значение этой переменной | ||
+ | @todo Переписать функцию под новую структуру данных | ||
+ | @bug Ошибочно работает при x<0 | ||
+ | @note Подробнее изложено в рабочем журнале | ||
+ | */ | ||
+ | </source> | ||
+ | |||
+ | == Пример из жизни == | ||
+ | |||
+ | Пример документирования файлов PowerMeasure.c и PowerMeasure.h. Результат можно подглядеть [http://server.srns.ru/doxygen/examples/PowerMeasure_DoxyDoc/index.html тут]. | ||
+ | |||
+ | <div class="NavFrame collapsed"> | ||
+ | <div class="NavHead">PowerMeasure.c</div> | ||
+ | <div class="NavContent"> | ||
+ | <source lang="c"> | ||
+ | #include "PowerMeasure.h" | ||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | #include <math.h> | ||
+ | #include "FPGA.h" | ||
+ | #else if (RECEIVER_TYPE == RECEIVER_NIIKP_ARM) | ||
+ | #include "std.h" | ||
+ | #include <intrinsics.h> | ||
+ | #endif | ||
+ | |||
+ | quint32 sqrt_PoMe(quint32 x); | ||
+ | quint32 NearestPower2(quint32 x); // Ближайщее большее 2^n, возвращаем n | ||
+ | |||
+ | |||
+ | /** | ||
+ | Инициализация структуры данных блока оценки с/ш, сброс счетчиков. | ||
+ | @param PoMe - указатель на структуру данных блока оценки с/ш | ||
+ | @param Init_qcno - инициализационное значение отношения с/ш, в НИИ КП не используется | ||
+ | */ | ||
+ | void InitPowerMeasure(PowerMeasure_struct * PoMe, quint32 Init_qcno) | ||
+ | { | ||
+ | PoMe->x_A2_est[0] = (1<<PoMe_NoiseU2Bit_shifted<<5); | ||
+ | |||
+ | PoMe->x_stdn2_est = (1<<PoMe_NoiseU2Bit_shifted); // Для первого порядка совпадает с экстраполяцией | ||
+ | PoMe->x_stdn2_est_shifted = PoMe->x_stdn2_est << x_stdn2_shift; | ||
+ | PoMe->allow_stnd2_est = 1; // Разрешить оценивать и фильтровать дисперсию квадратур | ||
+ | |||
+ | PoMe->R2 = 0; | ||
+ | PoMe->R4 = 0; | ||
+ | |||
+ | PoMe->acum_counter = 0; // Счетчик второго уровня накопителя корреляционных сумм | ||
+ | PoMe->sum_counter = 0; // Счетчик первого уровня накопителя корреляционных сумм | ||
+ | |||
+ | PoMe->fail_counter = 0; // Счетчик подряд идущих фейлов измерений | ||
+ | |||
+ | PoMe->start_counter = 0; // Счетчик тиков фильтра СКО от разрешения, доходит до (obr_Kf_stdn_0+задержка) и застывает | ||
+ | |||
+ | PoMe->acum_threshold_lock = 0; | ||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | if (Init_qcno > 0) | ||
+ | PoMe->qcno = Init_qcno; | ||
+ | else | ||
+ | PoMe->qcno = (quint32)( PoMe->x_A2_est[0] / (2.0 * PoMe->x_stdn2_est * PoMe_Tcorr) ); | ||
+ | PoMe->qcno_dBHz = 10.0*log10(PoMe->qcno); | ||
+ | PoMe->qcno_dBHz_extr = PoMe->qcno_dBHz; | ||
+ | #endif | ||
+ | } | ||
+ | |||
+ | |||
+ | /** | ||
+ | По накопленным \f$\sum I_k^2+Q_k^2\f$ и \f$\sum (I_k^2+Q_k^2)^2\f$ производим | ||
+ | оценки дисперсии, амплитуды и квадрата амплитуды квадратур. | ||
+ | Основная нить вычислений: | ||
+ | \f[ M = \frac{R2}{K} \f] | ||
+ | \f[ Diskrimi = 2M^2 - \frac{R4}{K} \f] | ||
+ | \f[ A^2_{izm} = M - 2 \sigma^2_{filt} \f] | ||
+ | \f[ \sigma^2_{izm} = \frac{M - \sqrt{Diskrimi}}{2} \f] | ||
+ | Измерения \f$ \sigma^2_{izm} \f$ хорошенько фильтруем, чтобы не испортить \f$ A^2_{izm} \f$ | ||
+ | @param PoMe - указатель на структуру данных блока оценки с/ш | ||
+ | */ | ||
+ | void DoPowerMeasure(PowerMeasure_struct *PoMe) | ||
+ | { | ||
+ | quint32 M; | ||
+ | quint32 Diskrimi; | ||
+ | quint32 SQ_stdn_izm; | ||
+ | quint32 SQ_A_izm; | ||
+ | //qint32 Ud_A; | ||
+ | qint32 Ud_stdn; | ||
+ | qint64 tmp64_1, tmp64_2, tmp64_3; | ||
+ | quint32 tmpu32_2, Diskrimi_shift; | ||
+ | |||
+ | /* Division by acum_counter */ | ||
+ | int clz=31-__CLZ(PoMe->Accumulators_are_ready); | ||
+ | if((1<<clz)==PoMe->Accumulators_are_ready) | ||
+ | { | ||
+ | tmp64_1 = PoMe->R2_acum_copy >> clz; // M | ||
+ | tmp64_3 = PoMe->R4_acum_copy >> clz; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | tmp64_1 = PoMe->R2_acum_copy / PoMe->Accumulators_are_ready; // M | ||
+ | tmp64_3 = PoMe->R4_acum_copy / PoMe->Accumulators_are_ready; | ||
+ | } | ||
+ | /***/ | ||
+ | |||
+ | PoMe->acum_threshold_lock = 0; | ||
+ | |||
+ | tmp64_2 = 2*tmp64_1*tmp64_1; | ||
+ | tmp64_2 = tmp64_2 - tmp64_3; // Diskrimi | ||
+ | if (tmp64_2 < 0)tmp64_2 = 0; | ||
+ | |||
+ | tmpu32_2 = ((tmp64_2 >> 32)&0xFFFFFFFF); | ||
+ | Diskrimi_shift = 32 - __CLZ(tmpu32_2); | ||
+ | if (Diskrimi_shift & 0x1) Diskrimi_shift++; // Чётное must be | ||
+ | M = (tmp64_1&0xFFFFFFFF); | ||
+ | Diskrimi = ((tmp64_2 >> Diskrimi_shift)&0xFFFFFFFF); | ||
+ | PoMe->Accumulators_are_ready = 0; | ||
+ | PoMe->IQ_Power = M; | ||
+ | |||
+ | /* Измерение квадрата амплитуды */ | ||
+ | if (M > 2*PoMe->x_stdn2_est){ | ||
+ | SQ_A_izm = M - 2*PoMe->x_stdn2_est; | ||
+ | PoMe->fail_counter = 0; | ||
+ | } | ||
+ | else { | ||
+ | PoMe->fail_counter++; | ||
+ | if (PoMe->x_A2_est[0] > (1<<PoMe_NoiseU2Bit_shifted) ) SQ_A_izm = (1<<PoMe_NoiseU2Bit_shifted); | ||
+ | else SQ_A_izm = PoMe->x_A2_est[0] - PoMe->x_A2_est[0]/2; //0.05*(0 - PoMe->x_A2_est[0]); | ||
+ | } | ||
+ | /***/ | ||
+ | |||
+ | |||
+ | /* Фильтр амплитуды и её квадрата */ | ||
+ | PoMe->x_A2_est[0] = SQ_A_izm; | ||
+ | PoMe->x_A_est = sqrt_PoMe( PoMe->x_A2_est[0] ); | ||
+ | /***/ | ||
+ | |||
+ | |||
+ | //#ifdef __Model | ||
+ | // static FILE* fid_ampout=0; | ||
+ | // if (!fid_ampout) | ||
+ | // { | ||
+ | // fid_ampout = fopen("amp.csv", "wt"); | ||
+ | // fprintf(fid_ampout,"tmp64_1;tmp64_2;tmp64_3;SQ_stdn;tmp;Diskrimi;M;SQ_A_izm\n"); | ||
+ | // } | ||
+ | // fprintf(fid_ampout,"%I64u;%I64u;%I64u;%d;%d;%u;%u;%u\n", | ||
+ | // tmp64_1,tmp64_2,tmp64_3, | ||
+ | // SQ_stdn_izm, | ||
+ | // tmp, | ||
+ | // Diskrimi, | ||
+ | // M, | ||
+ | // SQ_A_izm); | ||
+ | // fflush(fid_ampout); | ||
+ | //#endif | ||
+ | |||
+ | if (PoMe->allow_stnd2_est == 1){ | ||
+ | quint32 tmp; | ||
+ | /* Измерение квадрата СКО квадратур */ | ||
+ | if ( Diskrimi > 0 ) { | ||
+ | tmp = sqrt_PoMe(Diskrimi); | ||
+ | if (tmp != 0){ // Одна итерация по Герону для увеличения точности до требуемой | ||
+ | tmp += (int(Diskrimi) -int(tmp*tmp))/2 / int(tmp); // Обратное смещение с учетом смещения в корне | ||
+ | } | ||
+ | tmp <<= (Diskrimi_shift/2); | ||
+ | if (M > tmp) | ||
+ | SQ_stdn_izm = (M - tmp) / 2 ; // | ||
+ | else | ||
+ | SQ_stdn_izm = 0; | ||
+ | } else | ||
+ | SQ_stdn_izm = M / 2; | ||
+ | /***/ | ||
+ | |||
+ | if (SQ_stdn_izm > 2*PoMe->x_stdn2_est) // При резком изменении амплитуды на интервале оценивания | ||
+ | SQ_stdn_izm = 2*PoMe->x_stdn2_est; // происходит аномальный выброс, т.к. процесс не соответствует модели постоянства параметра | ||
+ | |||
+ | |||
+ | /* Фильтр диспресии квадратурных компонент */ | ||
+ | Ud_stdn = (SQ_stdn_izm<<x_stdn2_shift) - PoMe->x_stdn2_est_shifted; // Дискриминатор дисперсии квадратур | ||
+ | quint32 start_delay = 10; // First PoMe_obr_Kf_stdn_0 steps Kalman is used | ||
+ | if (PoMe->start_counter >= (PoMe_obr_Kf_stdn_0 + start_delay)) // После подстройки опять затягиваем фильтр | ||
+ | PoMe->x_stdn2_est_shifted += Ud_stdn / PoMe_obr_Kf_stdn_0; | ||
+ | else if (PoMe->start_counter < start_delay) { // На начальном этапе фильтр затянут | ||
+ | PoMe->start_counter++; | ||
+ | PoMe->x_stdn2_est_shifted += Ud_stdn / PoMe_obr_Kf_stdn_0; | ||
+ | } | ||
+ | else { // После выжидания start_delay расширяем фильтр и быстро подстраиваемся | ||
+ | PoMe->start_counter++; | ||
+ | PoMe->x_stdn2_est_shifted += Ud_stdn >> NearestPower2(PoMe->start_counter - start_delay); | ||
+ | } | ||
+ | PoMe->x_stdn2_est = PoMe->x_stdn2_est_shifted>>x_stdn2_shift; | ||
+ | /***/ | ||
+ | |||
+ | } // if (PoMe->allow_stnd2_est == 1) | ||
+ | |||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | PoMe->SQ_A_izm = SQ_A_izm; | ||
+ | PoMe->SQ_stdn_izm = SQ_stdn_izm; | ||
+ | PoMe->qcno = (quint32)( PoMe->x_A2_est[0] / (2.0 * PoMe->x_stdn2_est * PoMe_Tcorr) ); | ||
+ | PoMe->qcno_dBHz = 10.0*log10(PoMe->qcno); | ||
+ | PoMe->qcno_dBHz_extr = PoMe->qcno_dBHz; | ||
+ | #endif | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | Сопоставляет выбранному номеру порога число требуемых накоплений второго уровня. | ||
+ | @param PoMe - указатель на структуру данных блока оценки с/ш | ||
+ | |||
+ | @todo Что-то слишком громозко и сложно, нужно переделать систему порогов | ||
+ | */ | ||
+ | void SetAccumThreshold(PowerMeasure_struct *PoMe){ | ||
+ | |||
+ | switch (PoMe->acum_threshold_level){ | ||
+ | case 5: | ||
+ | PoMe->acum_threshold = PoMe_Threshold_5; | ||
+ | break; | ||
+ | case 4: | ||
+ | PoMe->acum_threshold = PoMe_Threshold_4; | ||
+ | break; | ||
+ | case 3: | ||
+ | PoMe->acum_threshold = PoMe_Threshold_3; | ||
+ | break; | ||
+ | case 2: | ||
+ | PoMe->acum_threshold = PoMe_Threshold_2; | ||
+ | break; | ||
+ | case 1: | ||
+ | PoMe->acum_threshold = PoMe_Threshold_1; | ||
+ | break; | ||
+ | default: | ||
+ | PoMe->acum_threshold = PoMe_Threshold_def; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | Производит необходимые накопления суммы квадратов корреляционных сумм, | ||
+ | устанавливает пороги накопления по детектируемой мощности на входе, | ||
+ | при достижении порога вызывает функцию обработки накоплений DoPowerMeasure. | ||
+ | Различаются накопления двух уровней. | ||
+ | - первый: накопление PoMe_sum_counter_max величин U2, результат - детектор мощности | ||
+ | - второй: накопление acum_threshold сумм первого уровня, затем вызов DoPowerMeasure | ||
+ | @param PoMe - указатель на структуру данных блока оценки с/ш | ||
+ | @param U2 - сумма квадратов корреляционных сумм \f$U2 = I_k^2 + Q_k^2\f$ | ||
+ | */ | ||
+ | void AccumPowerMeasure(PowerMeasure_struct *PoMe, quint32 U2){ | ||
+ | |||
+ | quint64 tmpu64; | ||
+ | quint32 tmpu32; | ||
+ | int overflow_F_ = 0; | ||
+ | PoMe->sum_counter++; if (PoMe->sum_counter == PoMe_sum_counter_max) PoMe->sum_counter = 0; | ||
+ | |||
+ | tmpu32 = PoMe->R2 + U2; | ||
+ | if (PoMe->R2 <= tmpu32) // overflow defence | ||
+ | PoMe->R2 = tmpu32; // sum I^2 + Q^2 | ||
+ | else{ // impossible, if PoMe_sum_counter_max and U2_SHIFT are correct | ||
+ | PoMe->R2 = U2; | ||
+ | overflow_F_ = 1; | ||
+ | } | ||
+ | |||
+ | tmpu64 = PoMe->R4 + (quint64)(U2) * (quint64)(U2); | ||
+ | if ( (PoMe->R4 <= tmpu64) & (overflow_F_ == 0) ) // overflow defence | ||
+ | PoMe->R4 = tmpu64; // sum (I^2 + Q^2)^2 | ||
+ | else{ // impossible, if PoMe_sum_counter_max and U2_SHIFT are correct | ||
+ | PoMe->R4 = (quint64)(U2) * (quint64)(U2); | ||
+ | } | ||
+ | |||
+ | if (PoMe->sum_counter == (PoMe_sum_counter_max - 1) ) | ||
+ | { | ||
+ | quint64 tmpu64_1, tmpu64_2; | ||
+ | quint32 tmpu32_1, tmpu32_2; | ||
+ | if (overflow_F_ == 0){ | ||
+ | tmpu64_1 = PoMe->R4 / PoMe_sum_counter_max; | ||
+ | tmpu32_1 = PoMe->R2 / PoMe_sum_counter_max; | ||
+ | } else { | ||
+ | tmpu64_1 = PoMe->R4; | ||
+ | tmpu32_1 = PoMe->R2; | ||
+ | } | ||
+ | PoMe->R2 = 0; | ||
+ | PoMe->R4 = 0; | ||
+ | |||
+ | tmpu64_2 = PoMe->R4_acum + tmpu64_1; | ||
+ | tmpu32_2 = PoMe->R2_acum + tmpu32_1; | ||
+ | |||
+ | if ( (PoMe->R4_acum <= tmpu64_2)&(PoMe->R2_acum <= tmpu32_2)&(overflow_F_ == 0) ){ // Переполнения нет | ||
+ | PoMe->R4_acum = tmpu64_2; | ||
+ | PoMe->R2_acum = tmpu32_2; | ||
+ | PoMe->acum_counter++; | ||
+ | }else if ( (tmpu64_1 > PoMe->R4_acum)||(tmpu32_1 > PoMe->R2_acum)||(overflow_F_ == 0) ){ | ||
+ | // impossible, if PoMe_sum_counter_max, U2_SHIFT and max[threshold] are correct | ||
+ | overflow_F_ = 1; | ||
+ | PoMe->R4_acum = tmpu64_1; // А раз оно такое большое, то будем по нему и работать | ||
+ | PoMe->R2_acum = tmpu32_1; | ||
+ | PoMe->acum_counter = 1; | ||
+ | }else { // Штатное переполнение по капле: где-то что-то мы проворонили | ||
+ | overflow_F_ = 1; // Надеяться и ждать, что сейчас всё пучком пройдет) | ||
+ | } | ||
+ | |||
+ | // *********** Threshold setting ********************** | ||
+ | tmpu32_2 = 32 - __CLZ(tmpu32_1); // Num of ones in E[U2] | ||
+ | if ( tmpu32_2 > (PoMe_NoiseU2Bit_shifted + 8) ){ // Power >> Noise Power | ||
+ | PoMe->acum_threshold_level = 5; | ||
+ | }else if ( tmpu32_2 > (PoMe_NoiseU2Bit_shifted + 4) ){ | ||
+ | PoMe->acum_threshold_level = 4; | ||
+ | }else if ( tmpu32_2 > (PoMe_NoiseU2Bit_shifted+2) ){ | ||
+ | PoMe->acum_threshold_level = 3; | ||
+ | }else | ||
+ | if ( (PoMe->x_A2_est[0])>>(PoMe_NoiseU2Bit_shifted-1)){ | ||
+ | PoMe->acum_threshold_level = 2; | ||
+ | }else{ | ||
+ | PoMe->acum_threshold_level = 1; | ||
+ | } | ||
+ | if (PoMe->acum_counter == 1) PoMe->acum_threshold_level_first = PoMe->acum_threshold_level; | ||
+ | |||
+ | |||
+ | if ((PoMe->acum_threshold_level - PoMe->acum_threshold_level_first) > 1){ // Up | ||
+ | PoMe->acum_threshold_lock = 1; | ||
+ | SetAccumThreshold(PoMe); | ||
+ | PoMe->R4_acum = tmpu64_1; // Old data so old | ||
+ | PoMe->R2_acum = tmpu32_1; | ||
+ | PoMe->acum_counter = 1; | ||
+ | PoMe->acum_threshold_level_first = PoMe->acum_threshold_level; // One second or more | ||
+ | if (PoMe->acum_threshold_level_first > 3) | ||
+ | PoMe->acum_threshold = 1; | ||
+ | else if (PoMe->acum_threshold_level_first == 3) | ||
+ | PoMe->acum_threshold = 2; | ||
+ | else | ||
+ | PoMe->acum_threshold = 4; | ||
+ | }else if ( (PoMe->acum_threshold_level_first - PoMe->acum_threshold_level) > 1){// Down | ||
+ | if (PoMe->acum_threshold_lock == 0){ | ||
+ | PoMe->R4_acum = tmpu64_1; // Old data so old | ||
+ | PoMe->R2_acum = tmpu32_1; | ||
+ | PoMe->acum_counter = 1; | ||
+ | PoMe->acum_threshold_level_first = PoMe->acum_threshold_level; | ||
+ | PoMe->acum_threshold_lock = 1; | ||
+ | PoMe->acum_threshold = (1024 / PoMe_sum_counter_max); // One second | ||
+ | } | ||
+ | }else | ||
+ | if ( (PoMe->acum_threshold_lock == 0) & (PoMe->acum_counter == 1) ) | ||
+ | SetAccumThreshold(PoMe); | ||
+ | PoMe->acum_threshold=8; // @bug: ВРЕМЕННО | ||
+ | |||
+ | if ( (PoMe->acum_counter >= PoMe->acum_threshold) // Превысили порог накопления для текущего qcno | ||
+ | || (overflow_F_) // Overflow in R2_acum or R4_acum | ||
+ | ){ | ||
+ | PoMe->Accumulators_are_ready = PoMe->acum_counter; PoMe->acum_counter = 0; | ||
+ | PoMe->R4_acum_copy = PoMe->R4_acum; PoMe->R4_acum = 0; | ||
+ | PoMe->R2_acum_copy = PoMe->R2_acum; PoMe->R2_acum = 0; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | /** | ||
+ | Позволяет установить оценку дисперсии (мощности шумовой составляющей) корреляционных сумм и | ||
+ | зафиксировать её. | ||
+ | @param PoMe - указатель на структуру данных блока оценки с/ш | ||
+ | @param stdn2_IQ - устанавливаемое значение оценки дисперсии квадратур | ||
+ | @return 0, если прошло успешно, 1, если предлагаемое число после сдвига не влазиет в 32 разряда | ||
+ | */ | ||
+ | int SetVariancePowerMeasure(PowerMeasure_struct *PoMe, quint32 stdn2_IQ ){ | ||
+ | if (__CLZ(stdn2_IQ) >= x_stdn2_shift){ // Если предлагаемое число можно сдвинуть, не переполнив 32 разряда | ||
+ | PoMe->x_stdn2_est = stdn2_IQ; | ||
+ | // В случае увеличения порядка фильтра добавить сюда PoMe->x_stdn2_extr = stdn2_IQ; | ||
+ | PoMe->x_stdn2_est_shifted = stdn2_IQ<<x_stdn2_shift; | ||
+ | return 0; | ||
+ | }else return 1; | ||
+ | } | ||
+ | |||
+ | |||
+ | /** | ||
+ | Разрешает работу фильтру дисперсии квадратру, сбрасывает его счетчик. | ||
+ | @param PoMe - указатель на структуру данных блока оценки с/ш | ||
+ | */ | ||
+ | void AllowVariancePowerMeasure(PowerMeasure_struct *PoMe){ | ||
+ | PoMe->allow_stnd2_est = 1; | ||
+ | PoMe->start_counter = 0; | ||
+ | } | ||
+ | |||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | /** | ||
+ | Возвращает число подряд идущих нулевых разрядов слева в бинарном представлении 32-разрядного числа. | ||
+ | Например, для x=b'00000111 вернет 29. | ||
+ | @param x | ||
+ | */ | ||
+ | int __CLZ(int x){ | ||
+ | |||
+ | int i; | ||
+ | |||
+ | for (i=31; i>=0; i--){ | ||
+ | if (x >> i) | ||
+ | return (31 - i); | ||
+ | } | ||
+ | return 32; | ||
+ | } | ||
+ | #endif | ||
+ | |||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | #define sh_sqrt 10 | ||
+ | #else | ||
+ | static const int sh_sqrt=10; // Смещение вывода функции fix_sqrt | ||
+ | #endif | ||
+ | /** | ||
+ | Нормирует 1.0 <= x <=4.0 * (2** -sh_sqrt) . | ||
+ | @param x - нормируемое число | ||
+ | @param exp - указатель, через который возвращается сдвиг | ||
+ | @return Результат нормировки | ||
+ | */ | ||
+ | quint32 norm_x_PoMe(quint32 x, qint32 * exp){ | ||
+ | *exp =0; | ||
+ | int razr=32-__CLZ(x); | ||
+ | // printf("razr = %d \n", razr); | ||
+ | if(razr<sh_sqrt){ | ||
+ | x=x<<(sh_sqrt-razr); | ||
+ | *exp=-(sh_sqrt-razr); | ||
+ | // printf("razr < exp = %d; x = %d \n", *exp, x); | ||
+ | } | ||
+ | else if(razr > (sh_sqrt+1)){ | ||
+ | x=x>>(razr-sh_sqrt); | ||
+ | *exp=razr-sh_sqrt; | ||
+ | // printf("razr > exp = %d; x = %d \n", *exp, x); | ||
+ | } | ||
+ | if( (*exp) & 1){ | ||
+ | x=x<<1; | ||
+ | (*exp)--; | ||
+ | // printf("exp not even exp = %d; x = %d \n", *exp, x); | ||
+ | } | ||
+ | return x; | ||
+ | } | ||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | #define K_sqrt1 (qint32)(0.09977*(1<<sh_sqrt)+0.5) | ||
+ | #define K_sqrt2 (qint32)(0.71035*(1<<sh_sqrt)+0.5) | ||
+ | #define K_sqrt3 (qint32)(0.3866*(1<<sh_sqrt)+0.5) | ||
+ | #else | ||
+ | static const qint32 K_sqrt1 = (qint32)(0.09977*(1<<sh_sqrt)+0.5); | ||
+ | static const qint32 K_sqrt2 = (qint32)(0.71035*(1<<sh_sqrt)+0.5); | ||
+ | static const qint32 K_sqrt3 = (qint32)(0.3866*(1<<sh_sqrt)+0.5); | ||
+ | #endif | ||
+ | //#define sqrt_27_bit | ||
+ | /** | ||
+ | Целочисленный алгорит вычисления корня \f$ y = \sqrt{x} \f$. | ||
+ | ** алгоритм с плав. зап. взят IAR\ARM\src\lib\dlib\xxsqrt.h | ||
+ | ** для sh_sqrt=10 погрешность sqrt( 0 < x < 4) не более 0.004 | ||
+ | ** для sh_sqrt=12 погрешность sqrt( 0 < x < 4) не более 0.001 | ||
+ | @param x - целое положительное число, из которого вычисляется корень | ||
+ | @return Результат вычисления корня | ||
+ | */ | ||
+ | quint32 sqrt_PoMe(quint32 x){ // x - с ц.р. = 2**-sh_sqrt | ||
+ | int exp; | ||
+ | x = norm_x_PoMe(x,&exp); // нормировка 1.0<= x <=4.0 для сходимости, exp кратна 2 | ||
+ | int y1; | ||
+ | y1 =( ( (K_sqrt2 - ((K_sqrt1*x)>>sh_sqrt)) * x ) >> sh_sqrt ) + K_sqrt3; | ||
+ | exp=exp/2-sh_sqrt/2; | ||
+ | if (exp>0) return y1<<exp; | ||
+ | else return y1>>(-exp); | ||
+ | } | ||
+ | |||
+ | |||
+ | const quint16 Power2[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096}; | ||
+ | const quint16 SizePower2 = 13; | ||
+ | /** | ||
+ | Функция нахождения ближайшего большего или равного числа, являющегося степенью двойки. | ||
+ | @todo Перейти на __CLZ | ||
+ | @param x | ||
+ | @return Степень, в которую требуется возвести 2, чтоб получить искомое число | ||
+ | */ | ||
+ | quint32 NearestPower2(quint32 x){//// Ближайшее большее или равное x число 2^n (возвращаем n) | ||
+ | int i; | ||
+ | if (x >= Power2[SizePower2-1]) return SizePower2-1; // Граничные условия | ||
+ | for (i=0; i<SizePower2; i++){ | ||
+ | if (x <= Power2[i]) // Первое число в последовательности, которое привысит или будет равно x | ||
+ | return i; // и будет ответом | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | </source> | ||
+ | </div> | ||
+ | </div> | ||
+ | |||
+ | <br /> | ||
+ | <div class="NavFrame collapsed"> | ||
+ | <div class="NavHead">PowerMeasure.h</div> | ||
+ | <div class="NavContent"> | ||
+ | <source lang="c"> | ||
+ | #ifndef POWERMEASURE_H_ | ||
+ | #define POWERMEASURE_H_ | ||
+ | |||
+ | #ifndef RECEIVER_ALPACA | ||
+ | #define RECEIVER_ALPACA 1 // Альпака | ||
+ | #endif | ||
+ | #ifndef RECEIVER_NIIKP_ARM | ||
+ | #define RECEIVER_NIIKP_ARM 2 // НИИ КП'шный проект | ||
+ | #endif | ||
+ | #ifndef RECEIVER_TYPE | ||
+ | #define RECEIVER_TYPE RECEIVER_NIIKP_ARM | ||
+ | #endif | ||
+ | |||
+ | |||
+ | #include "types.h" // Определяет типы переменных q* | ||
+ | |||
+ | /** Структура данных блока измерения эквивалентного отношения сигнал/шум | ||
+ | для одного корреляционного канала. */ | ||
+ | typedef struct { | ||
+ | |||
+ | quint32 x_A2_est[1]; ///< Вектор состояния Ф СС за квадратом амплитуды КК, оценка=экстраполяция | ||
+ | quint32 x_A_est; ///< Оценка амплитуды | ||
+ | |||
+ | quint32 x_stdn2_est; ///< Оценка дисперсии КК | ||
+ | quint32 x_stdn2_est_shifted; ///< Вектор состояния Ф СС за дисперсией КК, оценка=экстраполяция, сдвинут влево | ||
+ | |||
+ | /** @name Аккумуляторы и их триггеры */ | ||
+ | quint32 R2; ///< Первичный акк. \f$ I^2 + Q^2 \f$ | ||
+ | quint64 R4; ///< Первичный акк. \f$ (I^2 + Q^2)^2 \f$ | ||
+ | |||
+ | quint32 R2_acum; ///< Вторичный аккумулятор R2 | ||
+ | quint64 R4_acum; ///< Вторичный аккумулятор R4 | ||
+ | |||
+ | quint32 R2_acum_copy; ///< Триггер R2_acum | ||
+ | quint64 R4_acum_copy; ///< Триггер R4_acum | ||
+ | //@} | ||
+ | |||
+ | /** @name Счетчики для аккумуляторов */ | ||
+ | quint16 sum_counter; ///< для R2, R4 | ||
+ | quint16 acum_counter; ///< для R2_acum, R4_acum | ||
+ | //@} | ||
+ | |||
+ | /** @name Пороги накоплений R2_acum, R4_acum */ | ||
+ | quint16 acum_threshold; | ||
+ | quint16 acum_threshold_lock; | ||
+ | qint16 acum_threshold_level; | ||
+ | qint16 acum_threshold_level_first; | ||
+ | //@} | ||
+ | |||
+ | quint16 fail_counter; ///< Число подряд идущих срывов измерения амплитуды (комплексные корни) | ||
+ | |||
+ | quint32 start_counter; ///< Счетчик тактов от начала включения блока | ||
+ | |||
+ | quint8 allow_stnd2_est; ///< Разрешить оценивать и фильтровать дисперсию квадратур | ||
+ | |||
+ | int Accumulators_are_ready; ///< Флаг готовности триггеров R2_acum_copy, R4_acum_copy и копия счетчика в одном лице | ||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | /** @name Сохраненные измерения, поступающие на вход фильтров */ | ||
+ | quint32 SQ_A_izm; ///< Квадрата амплитуды | ||
+ | quint32 SQ_stdn_izm; ///< Квадрата СКО | ||
+ | //@} | ||
+ | quint32 qcno; ///< Оценка отношения с/ш, в абсолютных единицах | ||
+ | double qcno_dBHz; ///< Оценка отношения с/ш, в дБГц | ||
+ | double qcno_dBHz_extr; ///< Экстраполяция на следующий такт отношения с/ш, в дБГц | ||
+ | #endif | ||
+ | |||
+ | quint32 IQ_Power; ///< Оценка \f$ E[I^2 + Q^2] \f$ | ||
+ | |||
+ | } PowerMeasure_struct; | ||
+ | |||
+ | |||
+ | #if (RECEIVER_TYPE == RECEIVER_ALPACA) | ||
+ | #define PoMe_sum_counter_max 128 ///< Число суммирований в аккумуляторах R2, R4 | ||
+ | #define PoMe_obr_Kf_stdn_0 256 ///< Обратный коэффициент Ф СС за дисперсией КК | ||
+ | |||
+ | /** | ||
+ | I,Q in signed short => | ||
+ | - log2((2^15)^2 * 2 / 2^6 * 128) = 32 | ||
+ | - log2((2^15)^4 * 2 / 2^6 * 128) = 64 | ||
+ | |||
+ | U2_SHIFT <-> : | ||
+ | - 1) log2(max U^2 >> U2_SHIFT) < 32 | ||
+ | - 2) log2(max U^4 >> U2_SHIFT) < 64 | ||
+ | - 3) PoMe_sum_counter_max < max_acum_counter (if hasn't reserve in 1) and 2) ) | ||
+ | - 4) min U^2 >> U2_SHIFT > 0 | ||
+ | |||
+ | Estimates of stdn2 and A2 are shifted by U2_SHIFT relative real values. | ||
+ | */ | ||
+ | #define U2_SHIFT 6 ///< Сдвиг I^2+Q^2 перед аккумулированием | ||
+ | |||
+ | #define PoMe_NoiseU2Bit (20) ///< Typical \f$ \log_2(Noise^2) \f$, exponent of two | ||
+ | #define PoMe_NoiseU2Bit_shifted (PoMe_NoiseU2Bit-U2_SHIFT) ///< PoMe_NoiseU2Bit-U2_SHIFT | ||
+ | #define x_stdn2_shift = (8); ///< Сдвиг дисперсии квадратур во внутренней структуре фильтра | ||
+ | |||
+ | /** @name Делитель вторичных аккумуляторов для каждого времени накопления, сдвиги */ | ||
+ | #define PoMe_Threshold_5_sh 1 // Период: 2*PoMe_sum_counter_max | ||
+ | #define PoMe_Threshold_4_sh 2 // 4*PoMe_sum_counter_max | ||
+ | #define PoMe_Threshold_3_sh 3 // 8*PoMe_sum_counter_max | ||
+ | #define PoMe_Threshold_2_sh 5 // 32*PoMe_sum_counter_max | ||
+ | #define PoMe_Threshold_1_sh 6 // 64*PoMe_sum_counter_max | ||
+ | #define PoMe_Threshold_def_sh 5 // 32*PoMe_sum_counter_max | ||
+ | //@} | ||
+ | |||
+ | /** @name Делитель вторичных аккумуляторов для каждого времени накопления */ | ||
+ | #define PoMe_Threshold_5 (1<<PoMe_Threshold_5_sh) | ||
+ | #define PoMe_Threshold_4 (1<<PoMe_Threshold_4_sh) | ||
+ | #define PoMe_Threshold_3 (1<<PoMe_Threshold_3_sh) | ||
+ | #define PoMe_Threshold_2 (1<<PoMe_Threshold_2_sh) | ||
+ | #define PoMe_Threshold_1 (1<<PoMe_Threshold_1_sh) | ||
+ | #define PoMe_Threshold_def (1<<PoMe_Threshold_def_sh) | ||
+ | //@} | ||
+ | |||
+ | #define PoMe_Tcorr 0.001 ///< For qcno_dBHz calculation - длительность одного такта Ф | ||
+ | |||
+ | /** "Число лидирующих нулей" - число первых нулей бинарного представления. | ||
+ | Данная функция реализована рекурсивно для совместимости с ARM НИИ КП | ||
+ | @param x Входное 32-разрядное число | ||
+ | @return Число первых нулей бинарного представления переменной */ | ||
+ | int __CLZ(int x); | ||
+ | |||
+ | #else if (RECEIVER_TYPE == RECEIVER_NIIKP_ARM) /*#ifndef NIIKP_ARM_F_*/ | ||
+ | |||
+ | const int exp_kARU = 12; ///< Экспонента для переменной kARU ~ обратной крутизны | ||
+ | const int PoMe_sum_counter_max = 128; ///< Число суммирований в аккумуляторах R2, R4 | ||
+ | const int PoMe_obr_Kf_stdn_0 = 256; ///< Обратный коэффициент Ф СС за дисперсией КК | ||
+ | const quint16 max_fail_counter = 2; ///< Число разрешенных fail_counter до снятия канала | ||
+ | |||
+ | /** | ||
+ | I,Q in signed short => | ||
+ | - log2((2^15)^2 * 2 / 2^6 * 128) = 32 | ||
+ | - log2((2^15)^4 * 2 / 2^6 * 128) = 64 | ||
+ | |||
+ | U2_SHIFT <-> : | ||
+ | - 1) log2(max U^2 >> U2_SHIFT) < 32 | ||
+ | - 2) log2(max U^4 >> U2_SHIFT) < 64 | ||
+ | - 3) PoMe_sum_counter_max < max_acum_counter (if hasn't reserve in 1) and 2) ) | ||
+ | - 4) min U^2 >> U2_SHIFT > 0 | ||
+ | |||
+ | Estimates of stdn2 and A2 are shifted by U2_SHIFT relative real values. | ||
+ | */ | ||
+ | const int U2_SHIFT = 0; ///< Сдвиг I^2+Q^2 перед аккумулированием | ||
+ | |||
+ | const qint16 PoMe_NoiseU2Bit = 6; ///< Typical \f$ log_2(Noise^2)\f$, exponent of two | ||
+ | const qint16 PoMe_NoiseU2Bit_shifted = (PoMe_NoiseU2Bit-U2_SHIFT); ///< PoMe_NoiseU2Bit-U2_SHIFT | ||
+ | const qint16 x_stdn2_shift = 8; ///< Сдвиг дисперсии квадратур во внутренней структуре фильтра | ||
+ | |||
+ | /** @name Делитель вторичных аккумуляторов для каждого времени накопления, сдвиги */ | ||
+ | const qint16 PoMe_Threshold_5_sh = 2; // 4 (x 128 мс) | ||
+ | const qint16 PoMe_Threshold_4_sh = 3; // 8 | ||
+ | const qint16 PoMe_Threshold_3_sh = 4; // 16 | ||
+ | const qint16 PoMe_Threshold_2_sh = 4; // 16 | ||
+ | const qint16 PoMe_Threshold_1_sh = 5; // 32 | ||
+ | const qint16 PoMe_Threshold_def_sh = 5; // 32 | ||
+ | //@} | ||
+ | |||
+ | /** @name Делитель вторичных аккумуляторов для каждого времени накопления */ | ||
+ | const qint16 PoMe_Threshold_5 = (1<<PoMe_Threshold_5_sh); | ||
+ | const qint16 PoMe_Threshold_4 = (1<<PoMe_Threshold_4_sh); | ||
+ | const qint16 PoMe_Threshold_3 = (1<<PoMe_Threshold_3_sh); | ||
+ | const qint16 PoMe_Threshold_2 = (1<<PoMe_Threshold_2_sh); | ||
+ | const qint16 PoMe_Threshold_1 = (1<<PoMe_Threshold_1_sh); | ||
+ | const qint16 PoMe_Threshold_def = (1<<PoMe_Threshold_def_sh); | ||
+ | //@} | ||
+ | |||
+ | #endif /* if (RECEIVER_TYPE == RECEIVER_NIIKP_ARM) */ | ||
+ | |||
+ | void InitPowerMeasure(PowerMeasure_struct *PoMe, quint32 Init_qcno); | ||
+ | |||
+ | void DoPowerMeasure(PowerMeasure_struct *PoMe); | ||
+ | |||
+ | void AccumPowerMeasure(PowerMeasure_struct *PoMe, quint32 U2); | ||
+ | |||
+ | int SetVariancePowerMeasure(PowerMeasure_struct *PoMe, quint32 stdn2_IQ); | ||
+ | |||
+ | void AllowVariancePowerMeasure(PowerMeasure_struct *PoMe); | ||
+ | |||
+ | #endif // POWERMEASURE_H_ | ||
+ | </source> | ||
+ | </div> | ||
+ | </div> | ||
+ | |||
+ | |||
+ | == Проблемы == | ||
+ | |||
+ | Doxygen, во всяком случае мой, некорректно работает с директивами препроцессора <code>#if, #ifdef</code> и т.п. Пока удается решить эту проблему перечислением в Doxyfile (поле PREDEFINED) значений всех используемых в таких выражениях define'ов. | ||
+ | |||
== Ссылки == | == Ссылки == | ||
Строка 1318: | Строка 2177: | ||
* [http://sourceforge.net/projects/doxygate Doxygate] | * [http://sourceforge.net/projects/doxygate Doxygate] | ||
* [http://www.doxygenorg.ru/ Документация на русском] | * [http://www.doxygenorg.ru/ Документация на русском] | ||
− | |||
− | |||
− |
Текущая версия на 21:40, 19 апреля 2011
Doxygen — это кроссплатформенная система документирования исходных текстов, которая поддерживает C++, Си, Objective-C, Python, Java, IDL, PHP, C#, Фортран, VHDL и, частично, D.
Doxygen генерирует документацию на основе набора исходных текстов и также может быть настроен для извлечения структуры программы из недокументированных исходных кодов. Возможно составление графов зависимостей программных объектов, диаграмм классов и исходных кодов с гиперссылками.
Doxygen имеет встроенную поддержку генерации документации в формате HTML, LaTeX, man, RTF и XML. Также вывод может быть легко сконвертирован в CHM, PostScript, PDF.
Для html-представления документации, размещаемого на web-серверах, существует удобный способ организации поиска (при помощи создаваемого Doxygen'ом PHP-модуля) и ссылок на внешнюю документацию.
Doxygen - консольная программа в духе классической Unix. Она работает подобно компилятору, анализируя исходные тексты и создавая документацию.
Содержание[убрать] |
[править] Что требуется установить для полноценной работы
[править] Doxygen
Основная программа
[править] Graphiz
Graphviz – это свободно распространяемый пакет утилит для визуализации данных. Нам он нужен для того, чтобы Doxygen мог показать в документации отношения наследования, графы вызовов и прочую информацию в виде наглядных изображений.
[править] LaTeX
При установленном пакете того или иного LaTeX-дистрибутива, Doxygen конвертирует TeX-разметку в комментариях в изображения, а затем вставляет их в итоговый отчет. Также генерирует TeX-файлы, а затем PDF.
[править] Doxywizard
Параметры создания документации читаются из конфигурационного файла, имеющего простой текстовый формат (см. ниже). Для упрощения манипуляций с конфигурационным файлом (а он содержит довольно много настроек), существует несколько утилит с графическим интерфейсом. Одна из них, doxywizard, поставляется вместе с Doxygen.
[править] Комментирование исходного текста
Практически любой элемент программы (класс, функция, переменная) может быть задокументирован в системе Doxygen.
Документирование выполняется на основе двух видов комментариев:
- краткий (brief)
- и полный (detailed).
Краткие комментарии обычно описывают предназначение комментируемого элемента, а полные содержат информацию по его использованию и функционированию и чаще всего являются многострочными.
К каждому элементу программы не может быть привязано более одного краткого и полного комментария.
Для документирования какого-либо элемента программы, соответствующий комментарий располагают перед этим элементом в тексте программы. Например:
//! Оценка вектора состояния СС за дисперсией квадратурных компонент int x_stdn2_est;
Существует множество вариантов оформления комментариев:
- Возможно использовать комментарии в стиле системы JavaDoc, применяемой при документировании исходных текстов на языке Java:
/** * Оценка вектора состояния СС за дисперсией квадратурных компонент */ int x_stdn2_est;
или так
/*! * Оценка вектора состояния СС за дисперсией квадратурных компонент */ int x_stdn2_est;
как и для предыдущего случая, знаки "*" не обязательны для промежуточных строк:
/*! Оценка вектора состояния СС за дисперсией квадратурных компонент */ int x_stdn2_est;
- Еще один вариант - использование дополнительных знаков "/" или "!" в каждой строке (QT-Style):
/// /// Оценка вектора состояния СС за дисперсией квадратурных компонент /// int x_stdn2_est;
или //! //! Оценка вектора состояния СС за дисперсией квадратурных компонент //! int x_stdn2_est;
По умолчанию любой многострочный комментарий является подробным. Для объявления кратких комментариев можно так же использовать несколько методов:
* Использование команды \brief в блоке комментария:
/*! \brief краткий комментарий. * краткий комментарий. * * после пустой строки начинается подробный комментарий. */ int x_stdn2_est; 2.Для однострочных комментариев:
/// краткое описание. /** Полное описание. */ int x_stdn2_est;
или
//! краткое описание. //! многострочное //! подробное описание. int x_stdn2_est;
Иногда желательно расположить комментарий после, либо на одной строке с описываемым элементом. Для такого случая так же существуют несколько возможных способов:
1. int x_stdn2_est;; /*!< Подробный комментарий */ 2. int x_stdn2_est;; /**< Подробный комментарий */ 3. int x_stdn2_est;; //!< Подробный комментарий 4. //!< 5. int x_stdn2_est;; ///< Подробный комментарий ///< 6. int x_stdn2_est;; //!< Краткий комментарий 7. int x_stdn2_est;; ///< Краткий комментарий
Обычно предполагается, что документирующие комментарии находятся рядом с документируемым элементом. Однако, Doxygen позволяет поместить комментарий практически в любой части файла, связав его с каким-либо элементом. В этом случае необходимо указывать в блоке комментария ряд специальных команд.
Например так будет выглядеть описание класса Test, размещенное в любом месте файла:
/*! \class Test \brief Тестовый класс. Полное описание класса. */
Кроме команды \class, можно использовать множество других:
\struct - документирует структуру \union - документирует объединение \enum - документирует перечисление \fn - документирует функцию \var - документирует переменную \def - документирует макрос подстановки #define \file - документирует файл \namespace - документирует пространство имен. \typedef - документирование объявления типа \interface - документирование IDL интерфейса \package - документирование пакета на языке Java
[править] Востребованные команды
[править] Комментирование структур, переменных и т.д.
Переменные часто удобно объединять в группы:
quint32 R2; ///< Первичный акк. \f$ I^2 + Q^2 \f$
quint64 R4; ///< Первичный акк. \f$ (I^2 + Q^2)^2 \f$
quint32 R2_acum; ///< Вторичный аккумулятор R2
quint64 R4_acum; ///< Вторичный аккумулятор R4
quint32 R2_acum_copy; ///< Триггер R2_acum
quint64 R4_acum_copy; ///< Триггер R4_acum
//@}
[править] Комментирование функции
Позволяет установить оценку дисперсии (мощности шумовой составляющей) корреляционных сумм и
зафиксировать её.
@param PoMe - указатель на структуру данных блока оценки с/ш
@param stdn2_IQ - устанавливаемое значение оценки дисперсии квадратур
@return 0, если прошло успешно, 1, если предлагаемое число после сдвига не влазиет в 32 разряда
*/
int SetVariancePowerMeasure(PowerMeasure_struct *PoMe, quint32 stdn2_IQ ){
if (__CLZ(stdn2_IQ) >= x_stdn2_shift){ // Если предлагаемое число можно сдвинуть, не переполнив 32 разряда
PoMe->x_stdn2_est = stdn2_IQ;
// В случае увеличения порядка фильтра добавить сюда PoMe->x_stdn2_extr = stdn2_IQ;
PoMe->x_stdn2_est_shifted = stdn2_IQ<<x_stdn2_shift;
return 0;
}else return 1;
}
[править] Вставка TeX-формул
Для вставки TeX-формулы используются команды \f$ ... \f$
и \f[ ... \f]
, которые обрамляют TeX-разметку:
Выражение в тексте:
Выражение по центру, с новой строки:
\f[
u_{d,k} = - atan{frac{Q_k}{I_k}},
\f]
его характеристики хорошо изучены, работа наглядна.
*/
Для расширенного синтаксиса нужно дополнить опцию в Doxyfile'e:
[править] Bug, ToDo, Warning, Note
Одноименные команды вставляют одноименные заметки. Далее doxygen формирует отдельные списки, по которым можно быстро найти интересующее место в коде.
@warning Не трогать значение этой переменной
@todo Переписать функцию под новую структуру данных
@bug Ошибочно работает при x<0
@note Подробнее изложено в рабочем журнале
*/
[править] Пример из жизни
Пример документирования файлов PowerMeasure.c и PowerMeasure.h. Результат можно подглядеть тут.
[править] Проблемы
Doxygen, во всяком случае мой, некорректно работает с директивами препроцессора #if, #ifdef
и т.п. Пока удается решить эту проблему перечислением в Doxyfile (поле PREDEFINED) значений всех используемых в таких выражениях define'ов.