Doxygen — различия между версиями

Материал из SRNS
Перейти к: навигация, поиск
(Graphiz)
 
(не показаны 13 промежуточных версий 1 участника)
Строка 7: Строка 7:
 
Для html-представления документации, размещаемого на web-серверах, существует удобный способ организации поиска (при помощи создаваемого Doxygen'ом PHP-модуля) и ссылок на внешнюю документацию.
 
Для html-представления документации, размещаемого на web-серверах, существует удобный способ организации поиска (при помощи создаваемого Doxygen'ом PHP-модуля) и ссылок на внешнюю документацию.
  
Doxygen - консольная программа в духе классической Unix. Она работает подобно компилятору, анализируя исходные тексты и создавая документацию. [ Пример.]
+
Doxygen - консольная программа в духе классической Unix. Она работает подобно компилятору, анализируя исходные тексты и создавая документацию.
 +
 
  
 
== Что требуется установить для полноценной работы ==
 
== Что требуется установить для полноценной работы ==
 +
  
 
=== Doxygen ===
 
=== Doxygen ===
  
 
Основная программа
 
Основная программа
 +
  
 
=== Graphiz ===
 
=== Graphiz ===
  
 
[http://ru.wikipedia.org/wiki/Graphviz 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'ов.
 +
 
  
 
== Ссылки ==
 
== Ссылки ==

Текущая версия на 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


[править] Востребованные команды

[править] Комментирование структур, переменных и т.д.

Переменные часто удобно объединять в группы:

 /** @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
 //@}


[править] Комментирование функции

/**
Позволяет установить оценку дисперсии (мощности шумовой составляющей) корреляционных сумм и
зафиксировать её.
@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$ E = mc^2 \f$ */


Выражение по центру, с новой строки:

/** Воспользуемся дискриминатором
\f[
u_{d,k} = - atan{frac{Q_k}{I_k}},
\f]
его характеристики хорошо изучены, работа наглядна.
*/


Для расширенного синтаксиса нужно дополнить опцию в Doxyfile'e:

EXTRA_PACKAGES         = amssymb,amsfonts,amsmath,mathtext


[править] Bug, ToDo, Warning, Note

Одноименные команды вставляют одноименные заметки. Далее doxygen формирует отдельные списки, по которым можно быстро найти интересующее место в коде.

/**
@warning Не трогать значение этой переменной
@todo Переписать функцию под новую структуру данных
@bug Ошибочно работает при x<0
@note Подробнее изложено в рабочем журнале
*/

[править] Пример из жизни

Пример документирования файлов PowerMeasure.c и PowerMeasure.h. Результат можно подглядеть тут.



[править] Проблемы

Doxygen, во всяком случае мой, некорректно работает с директивами препроцессора #if, #ifdef и т.п. Пока удается решить эту проблему перечислением в Doxyfile (поле PREDEFINED) значений всех используемых в таких выражениях define'ов.


[править] Ссылки

Персональные инструменты
Пространства имён

Варианты
Действия
SRNS Wiki
Рабочие журналы
Приватный файлсервер
QNAP Сервер
Инструменты