Switched to using OPA4354 quad op-amp for improved performance
This commit is contained in:
7
software/Makefile
Normal file
7
software/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
all: infnoise
|
||||
|
||||
infnoise: infnoise.c
|
||||
gcc -Wall -std=c99 -O3 -m64 -march=native -o infnoise infnoise.c -lm
|
||||
|
||||
clean:
|
||||
rm -f infnoise
|
||||
81
software/infnoise.c
Normal file
81
software/infnoise.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
/* This could be built with one opamp for the multiplier, a comparator with
|
||||
rail-to-rail outputs, and switches and caps and resistors.*/
|
||||
static inline uint8_t updateA(long double *A, long double K, long double noise) {
|
||||
if(*A > 1.0) {
|
||||
*A = 1.0;
|
||||
} else if (*A < 0.0) {
|
||||
*A = 0.0;
|
||||
}
|
||||
*A += noise;
|
||||
if(*A > 0.5) {
|
||||
*A = K**A - (K-1);
|
||||
return 1;
|
||||
}
|
||||
*A += noise;
|
||||
*A = K**A;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t computeRandBits(long double *A, uint32_t N, long double K, long double noiseAmplitude) {
|
||||
uint32_t bits = 0;
|
||||
for(uint32_t i = 0; i < N; i++) {
|
||||
//printf("%f\n", (double)*A);
|
||||
long double noise = noiseAmplitude*(((double)rand()/RAND_MAX) - 0.5);
|
||||
uint8_t result = updateA(A, K, noise);
|
||||
bits = (bits << 1) | result;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
static uint32_t computeMax(uint32_t *values, uint32_t numRuns, uint32_t N, long double K,
|
||||
long double noiseAmplitude, uint32_t *maxValue) {
|
||||
long double A = 0.0;
|
||||
|
||||
memset(values, 0, (1 << N)*sizeof(uint32_t));
|
||||
computeRandBits(&A, 30, K, noiseAmplitude); // Randomize state
|
||||
for(uint32_t i = 0; i < numRuns; i++) {
|
||||
uint32_t value = computeRandBits(&A, N, K, noiseAmplitude); // Randomize state
|
||||
//printf("%u\n", value);
|
||||
values[value]++;
|
||||
}
|
||||
*maxValue = 0;
|
||||
uint32_t maxOccurance = 0;
|
||||
for(uint32_t i = 0; i < 1 << N; i++) {
|
||||
uint32_t occurance = values[i];
|
||||
if(occurance > maxOccurance) {
|
||||
maxOccurance = occurance;
|
||||
*maxValue = i;
|
||||
}
|
||||
}
|
||||
printf("Max occurance at K=%.2f: %u. Most common value was %x\n", (double)K, maxOccurance, *maxValue);
|
||||
return maxOccurance;
|
||||
}
|
||||
|
||||
int main() {
|
||||
uint32_t N = 18;
|
||||
long double noiseAmplitude = 1.0/(1 << 20);
|
||||
uint32_t numRuns = 1 << 26;
|
||||
//long double K = sqrt(2.0);
|
||||
long double K = 1.8;
|
||||
uint32_t *values = calloc(1 << N, sizeof(uint32_t));
|
||||
|
||||
srand(time(NULL));
|
||||
uint32_t maxValue1, maxValue2;
|
||||
computeMax(values, numRuns, N, 2.0, noiseAmplitude, &maxValue1);
|
||||
computeMax(values, numRuns, N, 2.0, noiseAmplitude, &maxValue2);
|
||||
uint32_t max1 = values[maxValue1];
|
||||
printf("max1 = %u, total bits = %f\n", max1, log((double)numRuns/max1)/log(2.0));
|
||||
computeMax(values, numRuns, N, K, noiseAmplitude, &maxValue1);
|
||||
computeMax(values, numRuns, N, K, noiseAmplitude, &maxValue2);
|
||||
uint32_t max2 = values[maxValue1];
|
||||
printf("max2 = %u, total bits = %f\n", max2, log((double)numRuns/max2)/log(2.0));
|
||||
printf("Computed bits/clock: %f\n", log(numRuns/max2)/log(numRuns/max1));
|
||||
printf("Estimated bits/clock: %f\n", log(K)/log(2.0));
|
||||
}
|
||||
33
software/infnoise.py
Normal file
33
software/infnoise.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from random import random
|
||||
from math import sin
|
||||
from math import pi
|
||||
|
||||
def updateA(A, Vsup, noise, offset):
|
||||
"""This could be built with one opamp for the multiplier, a comparator with
|
||||
rail-to-rail outputs, and switches and caps and resistors."""
|
||||
A += noise
|
||||
Vref = Vsup/2.0 # Resistor divider
|
||||
# A 3 resistor divider is used to deal with opamp offset voltage
|
||||
# The problem is that 0.0*1.9 == 0, and if the op-amp thinks 0V is actually -1e-6*1.9V,
|
||||
# it will try to drive as low as it can, getting stuck at 0V forever.
|
||||
# About a 1% shift should be enough.
|
||||
A = Vref + 0.99*(A - Vref)
|
||||
if A > Vref:
|
||||
# Possitive offset is the bad direction in this case
|
||||
A = Vsup - (Vsup - (A+offset))*1.9
|
||||
print "\b1",
|
||||
else:
|
||||
# Negative offset is the bad direction in this case
|
||||
A = (A-offset)*1.9
|
||||
print "\b0",
|
||||
return A
|
||||
|
||||
A = -0.01 # Just to test that it can recover from Opamp offset voltage
|
||||
Vsup = 3.3
|
||||
for i in range(2000):
|
||||
# Model noise as a large predictable sin wave and a 1fV (fempto-volt) small unpredictable noise source
|
||||
# The important point is that the 1fV of noise is enough to randomize the output.
|
||||
noise = 0.1 * sin(i*2*pi/16) + 1.0e-15*(random() - 0.5)
|
||||
# In comparison, without the 1fV of noise, the same result is computed every time:
|
||||
#noise = 0.1 * sin(i*2*pi/16)
|
||||
A = updateA(A, Vsup, noise, 0.001)
|
||||
Reference in New Issue
Block a user