View Categories

Случайные числа

Я думаю понятие случайных величин вам знакомо: они случайны. Иногда в самодельном устройстве бывает нужна случайная величина, например для какой-нибудь игры или световых эффектов. Монетка, игральный кубик или лото-машина являются отличными источниками случайных чисел, потому что это - физический процесс. Микроконтроллер же не может генерировать настоящие случайные числа, потому что он - точное вычислительное устройство, у которого нет случайностей. Что делать? Использовать такое понятие, как псевдослучайные числа. Псевдослучайное число получается путём различных математических действий с начальным числом, то есть имея начальное число, мы можем сгенерировать на его основе целую кучу других чисел. Но тут есть две проблемы:

  • Через какое-то количество итераций (тысяч, миллионов, а может и больше) ряд сгенерированных псевдослучайных чисел начнёт повторяться. Для наших целей это не так страшно, можно об этом не думать
  • Генератору псевдослучайных чисел нужно начальное случайное число. И мы можем его получить - об этом ниже

Arduino и случайные числа #

Arduino-фреймворк имеет пару готовых функций для работы с псевдослучайными числами:

  • random(max) – возвращает псевдослучайное число в диапазоне от 0 до (max – 1)
  • random(min, max) – возвращает псевдослучайное число в диапазоне от min до (max – 1)
  • randomSeed(value) – установить новое начальное число для отсчёта

Запустите следующий код:

void setup() {
    Serial.begin(115200);
    Serial.println(random(100));
    Serial.println(random(100));
    Serial.println(random(100));
}

void loop() {
}

В мониторе порта появятся три числа, при перезагрузке МК это будут те же самые три числа. Чтобы запустить новую последовательность, нужно задать стартовое значение для генератора:

  • Прочитать сигнал с никуда не подключенного аналогового пина и установить его в качестве начального: randomSeed(analogRead(0)). Пин ловит наводки из воздуха и сигнал с него действительно случайный
  • Если устройство взаимодействует с окружающим миром или с пользователем, то можно при наступлении различных событий (нажатие кнопки, срабатывание датчика, принятие данных, и т.д.) отправлять в randomSeed() текущее время с момента запуска программы: randomSeed(micros())
  • В esp8266 часто используют вариант c randomSeed(micros()) сразу после того, как будет установлено подключение к WiFi при запуске программы: время подключение каждый раз сильно отличается

Случайный bool #

Иногда бывает нужен случайный флаг, то есть true/false. Делается это очень просто - bool принимает значение true при любом отличном от нуля значении. Это можно использовать для получения случайного логического значения с заданной вероятностью! Просто присваиваем логической переменной результат функции random(), в которую передаём число, обратное вероятности получения false:

bool rndFlag = random(5);   // 1/5 false

Переменная rndFlag получит значение false с вероятностью 1/5, то есть 20%. Если нужен true с вероятностью - используем инверсию:

bool rndFlag = !random(10); // 1/10 true

Теперь переменная rndFlag получит значение true с вероятностью 1/10.

Для задания вероятности true в процентах можно использовать следующую формулу:

random(100) <= percent;     // 0-100% true

Аппаратный рандом? #

В уроке про АЦП я показывал, что если пин никуда не подключен - то он ловит "из воздуха" всякие шумы и наводки. Эти шумы имеют природу, близкую к случайной, и было бы глупо этим не воспользоваться!

Первые два бита из результата analogRead() имеют самый большой шум. Давайте на него посмотрим, выведя несколько результатов в график. Получить первые два бита можно так: analogRead(A0) & 0b11:

Выглядит весьма случайно, никакой закономерности не прослеживается. Но значения меняются всего от 0 до 3, поэтому можно попробовать их перемножать и складывать, например так:

uint32_t rnd = 0;
for (int i = 0; i < 16; i++) {
    rnd *= 4;
    rnd += analogRead(A0) & 3;
}

Имеем неплохое рассеяние и огромное количество случайных значений, полученных путём перемножения и сложения "шума". Такой сид можно использовать для стартового значения генератора.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Прокрутить вверх