Недавно для железки на stm32 мне понадобился генератор случайной последовательности байтов.
L4x2 (и более дорогие) - имеют внутренний TRNG (True Random Numbers Generanor) - но дороговаты, а младшие модели (412-432) реально недоступны лично мне на рынке, есть только в виде Nucleo... Пришлось экспериментировать:
- шум транзисторов и стабилитронов - легко создать, хорошо воспроизводится, но требуется 9+ вольт питания, да и уровень маловат (десятки микровольт) - нужно городить усилители, а прикосновение рукой к донглу полностью подменяет шум меандром 50Гц...
- шум стабилизаторов (а ля lm317) - гораздо интереснее (единицы милливольт), но под осциллографом раскрылось, что на самом деле это периодическая пила случайной амплитуды. Для тестирования радио-устройств - нормально, а вот для генератора действительно случайных чисел - сомнительно.
- в конце концов решил использовать реально дешевый f103c8t6 - и попытаться что то вытянуть из шума АЦП... Вернее из его самого младшего разряда. Поток с младшего бита имеет примерно такой вид: "000000000101110000000000100010000000011001000", то есть, что-то похожее на случайные числа перемежающиеся блоками нулей случайной длины. Пробовал проредить нули - бяка. Решил поиграться с XOR - и даже первый результат (a[0]^a[10]) превзошел ожидания. Далее долгие эксперименты по разному сочетанию битов. Результат прилагаю. (Результат уже на esp8266, оно превосходно работает и на ней).
Итак mytrng.h
Код в Arduino esp8266 для тестирования:
Не забудьте исправить пути до инклюд-файлов на свои.
Первый "инклюд" не нужен под esp, там и так это объявлено, только под stm.
Если кому надо - вот он:
А это результат - таблица частот выпадения значений:
разброс = 100* (max-min)/avg
Учтите, что разброс уменьшается при увеличении размера выборки, так у меня на выборке около 70000 он был 33%, а тут на выборке примерно 400000 уже 11%, что радует глаз в гораздо большей степени
Верхнее левое число таблицы - количество 0-байтов, потом 1... справа верх 15 ну и право низ соответственно 255.
Баланс 0 и 1 терпимый - разница менее 1%.
ВАЖНО:
- увы нельзя использовать один и тот же вывод и для генерации случайных чисел и как просто АЦП
- вывод АЦП должен "висеть в воздухе"! То есть на NodeMCU вы получите вместо случайных чисел пачку нулей (проверил ). Впрочем никто не запрещает аккуратно перерезать дорожку.
- это не быстрый генератор (около 1ms на бит - там внутри есть миллисекундная задержка между запросами к АЦП - если ее убрать, равномерность резко ухудшается)
Кому как а мне для моей задачи - хватило.
L4x2 (и более дорогие) - имеют внутренний TRNG (True Random Numbers Generanor) - но дороговаты, а младшие модели (412-432) реально недоступны лично мне на рынке, есть только в виде Nucleo... Пришлось экспериментировать:
- шум транзисторов и стабилитронов - легко создать, хорошо воспроизводится, но требуется 9+ вольт питания, да и уровень маловат (десятки микровольт) - нужно городить усилители, а прикосновение рукой к донглу полностью подменяет шум меандром 50Гц...
- шум стабилизаторов (а ля lm317) - гораздо интереснее (единицы милливольт), но под осциллографом раскрылось, что на самом деле это периодическая пила случайной амплитуды. Для тестирования радио-устройств - нормально, а вот для генератора действительно случайных чисел - сомнительно.
- в конце концов решил использовать реально дешевый f103c8t6 - и попытаться что то вытянуть из шума АЦП... Вернее из его самого младшего разряда. Поток с младшего бита имеет примерно такой вид: "000000000101110000000000100010000000011001000", то есть, что-то похожее на случайные числа перемежающиеся блоками нулей случайной длины. Пробовал проредить нули - бяка. Решил поиграться с XOR - и даже первый результат (a[0]^a[10]) превзошел ожидания. Далее долгие эксперименты по разному сочетанию битов. Результат прилагаю. (Результат уже на esp8266, оно превосходно работает и на ней).
Итак mytrng.h
Код:
#ifndef _mytrng_h_
#define _mytrng_h_
class TRNG {
public:
inline TRNG(void) { buf = 0; }
inline ~TRNG(void){}
inline void Init( u16 p){ port = p; for (u8 i = 0; i < 12; i++) { buf = buf << 1 | Bit();} }
inline u8 Bit(void){ delay(1); buf = buf << 1 | (analogRead(port) & 1); return (buf&1)^(buf>>1&1)^(buf>>2&1)^(buf>>10&1); }
inline u8 Byte(void){ u8 r = 0; for (u8 i = 0; i < 8; i++) { r = r << 1 | Bit();} return r;}
inline u8 Byte(u8 max) { return Byte()*max/0xff; }
inline u16 Word(void){ u16 r = 0; for (u8 i = 0; i < 2; i++) { r = r << 8 | Byte();} return r;}
inline u16 Word(u16 max) { return Word()*max/0xffff; }
inline u32 Dword(void){ u32 r = 0; for (u8 i = 0; i < 2; i++) { r = r << 16 | Word();} return r;}
inline u32 Dword(u32 max) { return Dword()*max/0xffffffff; }
private:
u16 buf;
u16 port;
};
#endif
Код:
//#include "d:/include/mytypes.h"
#include "d:/include/mytrng.h"
TRNG Random;
void setup() {
Serial.begin(115200);
Random.Init(A0);
}
void loop() {
Serial.println(Random.Byte());
}
Первый "инклюд" не нужен под esp, там и так это объявлено, только под stm.
Если кому надо - вот он:
Код:
#ifndef _mytypes_h_
#define _mytypes_h_
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned long u32;
typedef signed long i32;
#endif
Код:
1705 1682 1725 1718 1691 1739 1799 1714 1657 1637 1739 1648 1756 1673 1637 1693
1657 1637 1739 1648 1756 1673 1637 1693 1712 1720 1687 1697 1717 1660 1720 1729
1712 1720 1687 1697 1717 1660 1720 1729 1634 1736 1727 1697 1744 1665 1728 1649
1634 1736 1727 1697 1744 1665 1728 1649 1715 1696 1715 1737 1762 1690 1723 1704
1715 1696 1715 1737 1762 1690 1723 1704 1694 1660 1749 1649 1744 1661 1694 1736
1694 1660 1749 1649 1744 1661 1694 1736 1602 1768 1799 1644 1673 1661 1711 1712
1602 1768 1799 1644 1673 1661 1711 1712 1717 1739 1677 1741 1687 1753 1730 1684
1717 1739 1677 1741 1687 1753 1730 1684 1733 1727 1723 1726 1668 1723 1687 1662
1733 1727 1723 1726 1668 1723 1687 1662 1745 1738 1765 1702 1666 1734 1679 1719
1745 1738 1765 1702 1666 1734 1679 1719 1682 1713 1757 1723 1686 1691 1653 1749
1682 1713 1757 1723 1686 1691 1653 1749 1693 1757 1717 1774 1620 1727 1718 1776
1693 1757 1717 1774 1620 1727 1718 1776 1674 1701 1740 1704 1740 1724 1704 1700
1674 1701 1740 1704 1740 1724 1704 1700 1629 1680 1688 1672 1805 1615 1713 1643
1629 1680 1688 1672 1805 1615 1713 1643 1799 1687 1690 1674 1632 1698 1726 1688
1799 1687 1690 1674 1632 1698 1726 1688 1710 1753 1722 1711 1728 1625 1760 1764
1710 1753 1722 1711 1728 1625 1760 1764 1646 1728 1744 1707 1762 1697 1757 1713
обработано байт: 436698, min: 1602, max: 1805, avg: 1705, разброс: 11 %
Учтите, что разброс уменьшается при увеличении размера выборки, так у меня на выборке около 70000 он был 33%, а тут на выборке примерно 400000 уже 11%, что радует глаз в гораздо большей степени
Верхнее левое число таблицы - количество 0-байтов, потом 1... справа верх 15 ну и право низ соответственно 255.
Баланс 0 и 1 терпимый - разница менее 1%.
ВАЖНО:
- увы нельзя использовать один и тот же вывод и для генерации случайных чисел и как просто АЦП
- вывод АЦП должен "висеть в воздухе"! То есть на NodeMCU вы получите вместо случайных чисел пачку нулей (проверил ). Впрочем никто не запрещает аккуратно перерезать дорожку.
- это не быстрый генератор (около 1ms на бит - там внутри есть миллисекундная задержка между запросами к АЦП - если ее убрать, равномерность резко ухудшается)
Кому как а мне для моей задачи - хватило.
Последнее редактирование: