Um pequeno microcontrolador (Atmel de 8 bits) controla várias luzes para apresentar um show de luzes com muitas sequências de luzes aleatórias sofisticadas.
Um pseudo-RNG adequado faz seu trabalho bem, mas estou procurando uma boa semente para ele. Uma semente será necessária porque se alguém ligar vários dispositivos ao mesmo tempo, não parecerá bom se todos gerarem as mesmas seqüências de efeitos até que se afastem lentamente devido às pequenas diferenças em suas fontes de relógio individuais.
Um método muito bom para propagar um pseudo-RNG, que eu costumava usar, é possível no caso de um dispositivo que deve ser iniciado pressionando um botão ou pressionando um botão. Assim que o µc for ligado, um timer muito rápido poderá ser iniciado, e o valor desse timer semeará o RNG assim que o botão for pressionado pela primeira vez.
O problema é que, nesse cenário, não há botões. O programa deve iniciar assim que o dispositivo for ligado.
O local no PCB é extremamente limitado (nada mais do que algumas das menores peças SMD podem caber), então estou procurando a solução menor e mais simples possível. Portanto, descartarei soluções sofisticadas, como o verdadeiro hardware RNG, receptores de rádio etc.
Tudo o que tenho é um contador de timer de 16 bits na CPU e um alfinete de porta não utilizado que tenha acesso a um ADC.
Minha solução atual é usar apenas um resistor (o mais impreciso possível) para fornecer aproximadamente metade da tensão de alimentação ao pino do ADC e propagar o RNG com o primeiro valor de conversão do AD. No entanto, hoje em dia a maioria dos resistores de 10% tem uma imprecisão bem abaixo de 1% (seria divertido imaginar o rosto de um fornecedor quando eu lhes digo que queremos os resistores SMD da pior qualidade que eles encontrarem), então há uma chance muito alta de várias unidades começando com a mesma semente.
Uma alternativa melhor seria fazer várias conversões e criar um valor a partir dos bits menos significativos dessas medidas. No entanto, eu usei o ADC desse tipo µc antes e sei que é muito preciso. A execução do ADC na velocidade mais rápida possível pode ajudar aqui.
Alguém tem uma sugestão melhor? Não é necessário que a semente seja perfeitamente distribuída uniformemente, mas quanto mais uniforme for a distribuição, melhor. Uma semente de 16 bits com uma distribuição perfeitamente uniforme seria um sonho bom demais para ser verdade, mas acho que uma distribuição decente na metade de 5 ou 6 bits pode ser suficiente.
fonte
Respostas:
Coloque um resistor e um capacitor paralelos entre o pino A / D e o terra. Torne o resistor razoavelmente alto, de preferência bem acima do requisito de impedância do sinal de entrada para o A / D. Faça o tempo de RC constante, talvez em torno de 10 µs. Por exemplo, 100 kΩ e 100 pF parecem uma boa combinação.
Para obter um valor com alguma aleatoriedade, mova o pino alto por um tempo, depois ajuste-o para alta impedância e faça uma leitura A / D alguns µs depois. Particularmente, se você abusar adequadamente do tempo de aquisição do A / D, a tensão que ele verá dependerá dos valores de R e C, da corrente de fuga do pino, de outros ruídos próximos e da temperatura.
Pegue o bit baixo ou o baixo dois bits e repita conforme necessário para obter qualquer número de bits aleatórios.
Para um padrão mais aleatório, execute este procedimento ocasionalmente e injete o bit baixo do resultado A / D no gerador de números aleatórios que você já está usando.
fonte
Algumas opções possíveis:
Pré-programe um endereço serial exclusivo para cada dispositivo. Se você tiver um algoritmo RNG bom o suficiente, mesmo uma lista seqüencial de endereços seriais produzirá resultados totalmente diferentes.
Dependendo do seu MCU / configuração, você pode ter duas fontes de relógio diferentes disponíveis para o relógio do sistema e a entrada do watchdog timer / timer. Se um / ambos tiverem variação significativa, você poderá usá-lo para gerar uma semente adequadamente diferente. Aqui está um exemplo que escrevi que usa um timer interno de vigilância do Arduino e um relógio externo do sistema XTAL .
Use um transistor BJT e construa um amplificador altamente dependente de beta. Isso pode ser lido de um ADC para a semente.
Capacitores / indutores são normalmente especificados para uma tolerância muito pior do que os resistores. Você pode construir algum tipo de circuito de filtro (RC, RL, LC) com estes e medir a saída com o ADC.
fonte
Memória não inicializada
Você pode tentar usar a memória não inicializada no micro controlador. O truque é encontrar os bits que têm os chinelos mais "equilibrados" e são realmente aleatórios. O procedimento é ler toda a memória, redefinir e repetir algumas vezes para medir quais bits são verdadeiramente aleatórios. Então você usa este mapa para ler bits aleatórios suficientes para propagar seu PRNG ou LFSR!
Este método deve dar-lhe sementes aleatórias, mesmo com hardware idêntico, mais detalhes (e links) estão disponíveis em este hack-a-dia artigo
Eu gosto desse método porque ele não requer nenhum circuito ou pinos adicionais; seu AVR já possui ram, você só precisa encontrar os bits instáveis (aleatórios). Além disso, o procedimento de mapeamento pode ser automatizado; você pode aplicar o mesmo código e procedimento a cada dispositivo e obter resultados verdadeiramente aleatórios!
fonte
O que eu fiz para um MP3 player com capacidade aleatória é usar apenas uma semente sequencial diferente a cada ligação. Comecei em 1 e guardei isso na EEPROM, de modo que, no próximo ciclo de energia, usei 2 etc. Isso ocorreu em um ATMEGA168. Como helloworld922 observou, mesmo uma simples semente seqüencial irá gerar sequências pseudo-aleatórias completamente diferentes.
Eu usei um dos geradores de sequência aleatória linear congruente, isso fornece uma distribuição uniforme.
Obviamente, se você deseja que várias unidades tenham sequências diferentes, mesmo que elas tenham o mesmo número de ciclos de energia, você precisa de algo para iniciar aleatoriamente.
Isso pode ser feito por qualquer um dos métodos propostos pelos outros pôsteres - Um método em que posso pensar poderia usar o cruzamento de zero CA que entra no processador, se você o tiver (para controle de fase da lâmpada, por exemplo)? Isso pode ser usado para amostrar o cronômetro no primeiro cruzamento após a inicialização e, em seguida, usado como semente.
Existem botões na unidade para selecionar o modo etc? Nesse caso, você pode testar o contador na primeira vez em que o botão é pressionado após a programação da MCU, você pode gerar uma semente aleatória inicialmente e armazená-la na EEPROM. Toda energização após esse ponto usaria a semente armazenada.
fonte
Um ADC é uma fonte muito boa de aleatoriedade.
Você não precisa confiar nas tolerâncias do resistor. Qualquer resistor irá gerar ruído térmico e o mesmo efeito físico introduzirá ruído no ADC ao executar todas as etapas de amostragem e conversão. (A folha de dados informará sobre a quantidade de ruído e quais configurações são as piores / as melhores.)
Você não deve deixar o pino ADC flutuando; isso pode deixar a tensão flutuar muito longe e corre o risco de saturar a entrada.
(Muitos MCUs permitem que você use algo como metade da tensão de alimentação como uma entrada ADC, para calibração. Isso economiza o resistor externo e ainda gera ruído. Novamente, consulte a folha de dados para a pior / melhor configuração.)
Você não precisa confiar em uma única medição ADC; você pode combinar várias medidas com uma função simples de hash ou soma de verificação (o CRC seria suficiente). Se você precisar começar a usar o RNG imediatamente, poderá combinar posteriormente o resultado do ADC com a semente atual do RNG.
fonte
40uV
de banda de 10kHz possui ruído Johnson. Você precisaria de um ADC> 14 bits ou um circuito amplificador para medir isso razoavelmente.Você pode salvar a semente de uma sessão para outra? Em caso afirmativo, é possível ativar todas as unidades por algum período aleatório após a criação? Dessa forma, todas as unidades serão enviadas com sementes predefinidas que provavelmente não serão as mesmas.
Outro pensamento: como você vincula várias unidades para que elas sejam ativadas simultaneamente? Se estiverem em série, adicione algum tipo de capacitor para que o (n + 1 )ésimo dispositivo inicie alguns ciclos de relógio após o enésimo dispositivo. Idealmente, os capacitores descarregariam muito rapidamente no desligamento do dispositivo; portanto, a cada inicialização / reinicialização, há um intervalo maior entre as seqüências.
Se eles estiverem em paralelo, você ainda poderá aleatoriamente um pouco o tempo de inicialização. Presumo que exista algum tipo de filtragem de energia usando capacitores. Nesse caso, fabricar os dispositivos com circuitos de filtragem ligeiramente diferentes faria com que cada dispositivo iniciasse em um momento ligeiramente diferente, causando divergência após várias reinicializações.
Uma variação disso é adicionar variação aos sinais do relógio, se possível. Uma diferença de 0,1% na velocidade do relógio pode ter pouco impacto no show de luzes, enquanto altera a taxa em que você percorre a tabela PRNG rapidamente.
fonte
Se você estiver executando na fonte de relógio "calibrada" interna. Você não pode salvar uma semente depois de algum tempo, preferencialmente na EEPROM. O relógio mudará e será diferente de unidade para unidade. Para salvar um novo valor após algum tempo novamente (talvez a cada 10 minutos ou mais, ou após um tempo curto o suficiente para ocorrer dentro do prazo normal do dispositivo. Quanto mais tempo o dispositivo estiver ligado, maior será a probabilidade de salvar um valor "diferente" na EEPROM.
Dê um salto de vez em quando (de vez em quando) e faça nova propagação enquanto o dispositivo estiver ligado (salve esse novo valor na EEPROM).
fonte
Que tal estender sua idéia original de conversão do AD com base em um resistor variável, adicionando um LDR ou termistor? (O primeiro precisaria "olhar" para fora, não sei se isso é viável; mas a variação da luz pode ser maior que a variação da temperatura entre os dispositivos iniciados aproximadamente na mesma hora e no mesmo local. ..)
fonte
2 soluções em potencial, ambas assumindo que você precisa de uma semente única por unidade.
Se você piscar suas unidades uma por uma na fábrica, o arquivo hexadecimal poderá ser modificado programaticamente por algum script intermediário no programador. Se for controlado por PC, você pode substituir uma inicialização variável pela data e hora. Garantido para ser único para cada unidade!
Os dispositivos Dallas 1 wire usam apenas um pino e cada um vem com um número de série exclusivo de 64 bits. Você pode usar isso como a semente.
fonte
Você pode deixar um pino ADC flutuante para alimentar o gerador de números aleatórios (RNG) com ruído capturado. Deve ser o suficiente para gerar uma semente ou até usá-la como o gerador RNG.Não se esqueça de usar o tempo mínimo de conversão possível.
A outra solução poderia ser um gerador de ruído aplicado ao pino ADC.
fonte
0
ou aproxima0
. Vou verificar novamente para ver se é esse o caso.0
quando está flutuando?