Подскажите алгоритм уменьшения времени расчёта радиации

Сейчас считаю так, модуль ESP8266:

struct DATA {
  uint32_t DOSE_CBM20[34];
  volatile uint8_t SECONDS = 0;
  uint64_t SUMM = 0;
  uint32_t RESULT = 0;
};

DATA DATA;

IRAM_ATTR void timerISR() 
{
  ++DATA.SECONDS;
  if (DATA.SECONDS >= 33)
    DATA.SECONDS = 0;
  DATA.DOSE_CBM20[DATA.SECONDS] = 0;
  timer0_write(ESP.getCycleCount() + 80000000L);                        //Тактовая частота 80MHz, получаем секунду
}

IRAM_ATTR void SBM20() 
{
  ++DATA.DOSE_CBM20[DATA.SECONDS];
}

void setup() {
  noInterrupts();
  
  timer0_isr_init(); 
  timer0_attachInterrupt(timerISR);                                 //настраиваем прерывание (привязка к функции)
  timer0_write(ESP.getCycleCount() + 80000000L);                    //Тактовая частота 80MHz, получаем секунду
  
  attachInterrupt(14, SBM20, FALLING);

  interrupts();
  Serial.begin(115200);
}


void loop() {
  DATA.SUMM = 0;
      
  for (uint32_t DOSE_CBM20 : DATA.DOSE_CBM20)
    DATA.SUMM = DATA.SUMM + DOSE_CBM20;

  
  Serial.println(DATA.SUMM);
}

Время расчёта 34 секунды, для расчёта фона отличный результат, данные со счётчика соответствуют данным других дозиметров.

Но стоит приблизить прибор к источнику, так он ещё 34 секунды показывает завышенные показания, пока круг не обнулиться, уважаемые форумчане, подскажите каким алгоритмом показания с дозиметра можно сделать более актуальными, куда копать?

К сожалению, не понял точный смысл этих строк, но догадываюсь))

 for (uint32_t DOSE_CBM20 : DATA.DOSE_CBM20)
    DATA.SUMM = DATA.SUMM + DOSE_CBM20;

И если

Надо делать “скользящий” массив - при поступлении нового значения - отбрасывать первое, сдвигать массив на одну позицию , и на свободное место вписывать новое значение. Т.е. , нужно получать актуальный массив данных и
делать расчёт каждую секунду.
Возможно, будет достаточно, из общей суммы вычесть старое значение(заранее сохранив его в памяти), и, добавить новое
см. “алгоритм скользящего окна”

1 лайк

Вы бы поаккуратнее с использованием volatile для членов классов. Не то, чтобы этого делать нельзя, можно, конечно, но надо чётко понимать, что делаешь. Боюсь, в Вашем случае этого нет.

Вообще-то вместо этого принято использовать кольцевой буфер - чтобы не гонять данные постоянно туда-сюда.

МелкоМягкий, Вы бы написали подробно, что считаете и как считаете, тогда можно было бы подумать, как это сделать оптимальнее. А когда приведен готовый код - он какой есть, такой есть, и количество вариантов оптимизации резко уменьшается (притом, уменьшается как раз за счет самых эффективных).

Вот лично мне непонятно, как вообще можно считать радиацию, если у Вас нигде не фигурирует период полураспада. А вот прерывания к расчету радиации ну никак не могут иметь отношения, поэтому, зачем Вы привели их, совершенно непонятно.
У меня складывается впечатление, что текст вопроса вообще не имеет никакого отношения к тому, что Вам на самом деле нужно.

1 лайк

вапще лехко. Но к теме вопроса, да, это отношение не имеет.

А, ну да, как в анекдоте:
В. Ваши сильные стороны?
О. Я умею быстро считать.
В. Сколько будет 8765 умножить на 4321?
О. 123456.
В. Но это неверно.
О. Зато быстро.

Почему именно столько? А не, например, 1 секунда, для усреднения разбитая на 10 интервалов по 100 мСек ?

хм… туплю, наверное… почему при ПРИБЛИЖЕНИИ к источнику показания должны снижаться?

Вообще-то когда исправный ручной дозиметр за секунды меняет показания, о скорости алгоритма можно уже не беспокоиться…

Безопасные дозы радиации улавливаемые классическими датчиками должны детектироваться именно в режиме статического накопления неподвижным прибором. В случае скользящего окна вы конечно же увидите тенденцию, но точный замер будет гарантировано после заполнения всего окна.

Если следовать выдержке:

ESP8266 : следует использовать volatileдля глобальных переменных, которые изменяются в рамках процедуры обработки прерываний (ISR) и считываются основным циклом программы, и наоборот. Это предотвращает необходимость компилятора делать предположения о значении переменной и гарантирует, что при каждом обращении к переменной из памяти считывается её самое актуальное значение.

Получается, это как раз тот момент, для чего он нужен, но в чём может быть проблема, пожалуйста расскажите?

Извините не правильно выразился, когда приближаю дозиметр к источнику показания растут, но если удаляю, показания начинают падать не сразу, а через 34 секунды, пока не пройдёт полный круг.

Что-то вроде этого?

uint32_t WINDOW(uint32_t *nums, uint8_t k) {
 
  uint32_t sum = 0;
  for (uint8_t i = 0; i < k; i++) {                                      
    sum += nums[i];
  }

  uint32_t res = sum; 
  uint8_t count = sizeof(nums) / sizeof(uint32_t);
  for (uint8_t i = k; i < count; i++) {                                
    sum += nums[i] - nums[i - k]; 
    res = max(res, sum);
  }

  return res / k;
}

Но при каких условиях его начинать сужать?

С форумов подцепил информацию, что сумма срабатываний счётчика за 34 секунды равна дозе мкР/ч.

++DATA.SECONDS;
  if (DATA.SECONDS >= 33)
    DATA.SECONDS = 0;
  DATA.DOSE_CBM20[DATA.SECONDS] = 0;

Так я же его вроде и реализовал, считаем до 33 элемента включительно, затем возвращаемся к нулевому значению и так по кругу, или Вы о другом?

Извините за первое сообщение написал его сумбурно, попытаюсь объяснить идею подробно:

1. На форумах я нашёл информацию, что сумма срабатываний счётчика СБМ-20 за последние 34 секунды равна дозе мкР/ч, что похоже соответствует правде, так как эти показания сходятся с показаниями двух дозиметров, которые у меня имеются.

2. Алгоритм счёта такой:

2.1 Программа считает количество срабатываний счётчика СБМ-20 в течении одной секунды и суммирует их, записывая полученное значение в ячейку массива.

2.2 Затем когда секунда проходит, срабатывает прерывание и мы переходим к следующей ячейке и снова в неё записываем сумму срабатывания счётчика.

2.3 Когда мы подходим к 35 элементу массива, то возвращаемся к нулевому, что бы зациклить расчёт по кругу (получается идём с 0 до 33, затем снова возвращаемся к 0 и т.д.).

2.4 В цикле loop считаем сумму значений всего массива.

Если такой алгоритм подходит для счёта фона радиации, то не подходит для поиска источника радиации, потому что стоит нам поднести источник радиации к счётчику, как его значения резко растут, но стоит источник тут же отдалить от счётчика, завышенный фон продолжит держаться, пока не пройдёт 34 секунды (полный круг) и значения массива не начнут обнуляться.

Поэтому уважаемые форумчане, подскажите порядок действий расчётов при кратковременном поднесении источника радиации к счётчику?

UPD. Хотя здесь на форумах находил, что период в 46 секунд для счётчика СБМ-20 равен дозе мкР/ч, возможно это значение использовать вернее.

А где здесь про члены класса? Вы ведь используете не просто volatile переменную, а volatile член класса. Я ж Вам именно про этот нюанс написал, читайте внимательнее:

(если вдруг не знаете, слова struct и class в С++ почти синонимы, разница невелика. В любом случае, и то и другое описывает класс)

Выводите попутно значение последней измеренной секунды. Можете его домножать на 34, чтобы мгновенно получать то же самое значение, что получилось бы с накоплением.

Сделайте кнопку сброса, чтобы при изменении положения датчика не ждать полный цикл, а иметь возможность вот прямо сейчас начать новое измерение.

Нет, при чём здесь max()?

Ничего сужать не надо.
Имеем массив M[n] элементов.
Заводишь функцию, в которую 1раз в сек передаёшь значения с датчика за секунду.
Она при каждом вызове сдвигает массив на один элемент. M[n] = M[n-1], и.т.д
последний элемент теряется, а в М[0] -записываем новое значение.
Пропускаем первые n вызовов(пока массив не заполнится), и всё. Дальше
имеем на каждую следующую секунду актуальные значения в массиве для расчёта.

Задаю наводящий вопрос: почему именно 34 секунды?

опоздали, я уже спросил в #8.
И даже получил ответ

Ладно, будем считать, что ответ получен.
Тогда следующий наводящий вопрос для ТС: а если вместо 34 взять, например, 17 секунд? Можно в этом случае вычислить правильную величину в мкР/ч?
А если 10 секунд?

2 лайка

Можно, но точность падает, а хотелось бы не терять её.

Элементарно, Ватсон! Для увеличения точности нужно увеличивать время измерения. Так что следует определиться, либо мы измеряем точно, либо быстро. Это взаимоисключающие условия.

Другими словами, уменьшить время расчета, не теряя точность, невозможно. А вопрос был именно о сокращении времени.

Но в любом случае совершенно неочевидно, что разумный компромисс приходится именно на 34 секунды.

Это же два разных алгоритма. Для подсчета фона используйте этот. Для поиска источника - сократите до секунды.

Достаточно тупо вывести на динамик и удирать при начавшемся писке :slightly_smiling_face: