Switched to using OPA4354 quad op-amp for improved performance

This commit is contained in:
Bill Cox
2014-09-29 12:04:41 -04:00
parent 1a94963fa1
commit e18c871523
16 changed files with 42 additions and 350 deletions

7
software/Makefile Normal file
View 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
View 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
View 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)