34 lines
1.4 KiB
Python
34 lines
1.4 KiB
Python
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)
|