¿Cuál es la semilla más pequeña y simple para un generador de números aleatorios?

39

Un pequeño microcontrolador (Atmel de 8 bits) controla varias luces para presentar un espectáculo de luces con muchas secuencias de luces aleatorias de fantasía.

Un pseudo-RNG adecuado hace su trabajo muy bien, pero estoy buscando una buena semilla para ello. Será necesaria una semilla porque si alguien enciende múltiples dispositivos al mismo tiempo, no se verá bien si todos generan las mismas secuencias de efectos hasta que se separen lentamente debido a las pequeñas diferencias en sus fuentes de reloj individuales. / p>

Un método muy bueno para sembrar un pseudo-RNG, que uso a menudo, es posible en el caso de un dispositivo que debe iniciarse presionando un botón o presionando un interruptor. Tan pronto como se enciende el µc, se puede iniciar un temporizador muy rápido, y el valor de este temporizador siembra el RNG tan pronto como se presiona el botón por primera vez.

El problema es que, en este escenario, no hay botones. El programa debe iniciarse tan pronto como se encienda el dispositivo.

El lugar en el PCB es extremadamente limitado (no caben más que algunas de las piezas SMD más pequeñas), así que estoy buscando la solución más pequeña y simple posible. Por lo tanto, descartaré soluciones sofisticadas como hardware RNG verdadero, receptores de radio, etc.

Todo lo que tengo es un contador de temporizador de 16 bits en la CPU, y un puerto no utilizado que tiene acceso a un ADC.

Mi solución actual es usar una resistencia (lo más inexacta posible) para proporcionar aproximadamente la mitad de la tensión de alimentación al pin del ADC, y sembrar el RNG con el primer valor de conversión de AD. Sin embargo, en la actualidad, la mayoría de las resistencias del 10% tienen una inexactitud muy por debajo del 1% (sería divertido imaginar la cara de un proveedor cuando les digo que queremos las resistencias SMD de peor calidad que puedan encontrar), por lo que hay una posibilidad muy alta de unidades múltiples comenzando con la misma semilla.

Una mejor alternativa sería realizar conversiones múltiples y construir un valor a partir de los bits menos significativos de estas mediciones. Sin embargo, antes he usado el ADC de este tipo µc y sé que es muy preciso. Ejecutar el ADC a la velocidad más rápida posible podría ayudar aquí.

¿Alguien tiene una sugerencia mejor? No se requiere que la semilla esté perfectamente distribuida uniformemente, pero cuanto más uniforme sea la distribución, mejor. Una semilla de 16 bits con una distribución perfectamente uniforme sería un sueño demasiado bueno para ser verdad, pero creo que una distribución media decente de 5 o 6 bits podría ser suficiente.

    
pregunta vsz

10 respuestas

24

Coloque una resistencia paralela y un condensador entre el pin A / D y tierra. Haga que la resistencia sea bastante alta, preferiblemente muy por encima del requisito de impedancia de la señal de entrada para el A / D. Haga que el tiempo de RC sea constante alrededor de 10 µs. Por ejemplo, 100 kΩ y 100 pF suena como una buena combinación.

Para obtener un valor con cierta aleatoriedad, coloque el pin alto durante un tiempo, luego ajústelo a alta impedancia y tome una lectura A / D unos pocos µs más tarde. En particular, si abusa del tiempo de adquisición A / D, el voltaje que verá dependerá de los valores R y C, la corriente de fuga del pin, otro ruido cercano y la temperatura.

Agarre el bit bajo o los dos bits bajos y repita según sea necesario para obtener cualquier número de bits aleatorios.

Para un patrón más aleatorio, realice este procedimiento ocasionalmente e inyecte el bit bajo del resultado A / D en el generador de números aleatorios que ya está utilizando.

    
respondido por el Olin Lathrop
22

Algunas opciones posibles:

  1. Preprograme una dirección serie única para cada dispositivo. Si tiene un algoritmo RNG lo suficientemente bueno, incluso una lista secuencial de direcciones seriales producirá resultados muy diferentes.

  2. Dependiendo de su MCU / configuración, es posible que tenga dos fuentes de reloj diferentes disponibles para el reloj del sistema y la entrada del contador del temporizador / temporizador de vigilancia. Si uno / ambos de estos tienen una variación significativa, puede usar esto para generar una semilla adecuadamente diferente. Este es un ejemplo que escribí que usa un temporizador interno de vigilancia de Arduino y un reloj externo del sistema XTAL .

  3. Use un transistor BJT y genere un amplificador dependiente de beta. Esto se puede leer de un ADC para la semilla.

  4. Los condensadores / inductores se suelen especificar con una tolerancia mucho peor que las resistencias. Podría construir algún tipo de circuito de filtro (RC, RL, LC) con estos y medir la salida con el ADC.

respondido por el helloworld922
8

Memoria no inicializada

Puede intentar utilizar la memoria no inicializada en el microcontrolador. El truco es encontrar los bits que tienen la mayoría de los flip-flops 'balanceados', y en realidad son aleatorios. El procedimiento es leer toda la memoria, reiniciar y repetir varias veces para medir qué bits son realmente aleatorios. Luego, ¡usa este mapa para leer suficientes bits aleatorios para propagar su PRNG o LFSR!

Este método debería proporcionarle semillas aleatorias, incluso con hardware idéntico; más detalles (y enlaces) están disponibles en este hack-a-day article

Me gusta este método porque no requiere ningún circuito o pin adicional; su AVR ya tiene ram, solo necesita encontrar los bits inestables (aleatorios). También el procedimiento de mapeo podría ser automatizado; ¡Puede aplicar el mismo código y procedimiento a cada dispositivo, y obtener resultados verdaderamente aleatorios!

    
respondido por el esoterik
7

Lo que hice para un reproductor de MP3 con capacidad aleatoria es utilizar una semilla secuencial diferente en cada encendido. Comencé en 1 y lo guardé en la EEPROM, de modo que en el siguiente ciclo de encendido usé 2, etc. Esto estaba en un ATMEGA168. Como helloworld922 señaló, incluso una semilla secuencial simple generará secuencias pseudo aleatorias completamente diferentes.

Utilicé uno de los generadores de secuencia aleatorios congruentes lineales, esto da una distribución uniforme.

int i;
seed = seed * 2053 + 13849;
i = (seed % max) + 1;  // max is the maximum value I want out of the function

Por supuesto, si quieres que varias unidades tengan secuencias diferentes, aunque tengan el mismo número de ciclos de energía, necesitas algo para comenzar al azar.

Esto se puede hacer por cualquiera de los métodos propuestos por los otros carteles. ¿Un método que se me ocurra podría usar el cruce por cero de CA que ingresa al procesador si lo tiene (por ejemplo, para el control de la fase de la lámpara)? Esto podría usarse para muestrear el temporizador en el primer cruce después del encendido y luego usarse como semilla.

¿Hay algún botón en la unidad para seleccionar el modo, etc.? Si es así, puede muestrear el contador la primera vez que se presiona el botón después de programar la MCU, puede generar inicialmente una semilla aleatoria y almacenarla en EEPROM. Cada Encendido después de este punto usaría la semilla almacenada.

    
respondido por el Kevin White
5

Un ADC es una muy buena fuente de aleatoriedad.

No es necesario confiar en las tolerancias de resistencia. Cualquier resistencia generará ruido térmico , y el mismo efecto físico introducirá ruido en el ADC cuando se realiza Todos los pasos de muestreo y conversión. (La hoja de datos le informará sobre la cantidad de ruido y qué ajustes de configuración son los mejores / peores).

No debes dejar el pin ADC flotando; esto podría permitir que el voltaje flote demasiado lejos y los riesgos saturan la entrada.
(Muchas MCU le permiten usar algo como la mitad de la tensión de alimentación como una entrada ADC, para la calibración. Esto ahorra la resistencia externa y aún le genera ruido. De nuevo, consulte la hoja de datos para la configuración peor / mejor).

No es necesario confiar en una sola medición de ADC; puede combinar varias mediciones con una simple función de hash o suma de comprobación (CRC sería suficiente). Si necesita comenzar a utilizar el RNG de inmediato, más adelante puede combinar el resultado de ADC con el valor de partida actual del RNG.

    
respondido por el CL.
2

¿Puedes guardar la semilla de una sesión a otra? Si es así, ¿es factible encender cada unidad durante un período de tiempo aleatorio después de la creación? De esa forma, todas las unidades se enviarán con semillas preestablecidas que probablemente no sean las mismas.

Otro pensamiento: ¿Cómo vinculas varias unidades para que se enciendan simultáneamente? Si están en serie, agregue algún tipo de condensador para que el (n + 1) dispositivo comience unos cuantos ciclos de reloj después del noveno dispositivo. Idealmente, los condensadores se descargarían muy rápidamente al apagar el dispositivo, por lo que cada inicio / reinicio tiene una brecha mayor entre las secuencias.

Si están en paralelo, aún podría aleatorizar un poco el tiempo de inicio. Supongo que hay algún tipo de filtración de energía usando condensadores. Si es así, la fabricación de dispositivos con circuitos de filtración ligeramente diferentes provocaría que cada dispositivo se inicie en un momento ligeramente diferente, lo que provocaría divergencias después de varios reinicios.

Una variación de esto es agregar varianza a sus señales de reloj si es posible. Una diferencia de 0.1% en la velocidad del reloj podría tener poco impacto en el espectáculo de luces, mientras que cambiar la velocidad que recorres la tabla de PRNG con bastante rapidez.

    
respondido por el MichaelS
2

Si se ejecuta en una fuente de reloj "calibrada" interna. Podría no guardar una semilla después de algún tiempo, preferiblemente en la EEPROM. El reloj se desviará y diferirá de una unidad a otra. Para guardar un nuevo valor después de un tiempo nuevamente (tal vez cada 10 minutos aproximadamente, o después de un tiempo que sea lo suficientemente corto como para que ocurra dentro del tiempo de encendido normal del dispositivo. Mientras más tiempo esté encendido el dispositivo, más probabilidades tendrá de ahorrar un valor "diferente" en la EEPROM.

También dé un salto una vez de vez en cuando (no muy seguido) y reinicie mientras el dispositivo está encendido (guarde este nuevo valor en EEPROM).

    
respondido por el Mats
2

¿Qué hay de ampliar su idea original de convertir AD en función de una resistencia variable al agregar un LDR o un termistor? (El primero tendría que ser capaz de "mirar" al exterior, no sé si eso es posible, pero la variación en la luz puede ser mayor que la variación en la temperatura entre los dispositivos que se inició aproximadamente al mismo tiempo en aproximadamente el mismo lugar. ..)

    
respondido por el Hagen von Eitzen
1

2 soluciones potenciales, ambas asumiendo que necesita una semilla única por unidad.

  1. Si actualiza sus unidades una por una en la fábrica, el script hexadecimal del programador puede modificar el archivo hexadecimal mediante programación. Si está controlado por PC, puede sobrescribir una inicialización de variable con la fecha y la hora. ¡Garantizado para ser único para cada unidad!

  2. Los dispositivos de cable Dallas 1 usan solo un pin y cada uno viene con un número de serie exclusivo de 64 bits. Puedes usar esto como la semilla.

respondido por el Loganf
1

Puede dejar un pin de ADC flotante para alimentar el generador de números aleatorios (RNG) con ruido capturado. Debería ser suficiente para generar una semilla o incluso usarla como generador de RNG.

No olvides utilizar el mínimo tiempo de conversión posible.

La otra solución podría ser una generador de ruido aplicado en el pin ADC.

    
respondido por el jnk0le

Lea otras preguntas en las etiquetas