Я разрабатываю небольшую тестовую программу, чтобы увидеть, возможно ли добавить шум в АЦП для получения битов с избыточной дискретизацией.Немного теории, прежде чем мы начнем.Теорема выборки Найквиста предполагает, что увеличение разрешения на один бит требует четырех дополнительных выборок, и, как правило, еще n битов требует на 2 ^ (n + 1) больше выборок.Я имитирую идеальный 10-битный АЦП, который монотонно возвращает значение от 0,103 без шума для входа от 0 до 2 В.
Чтобы получить больше битов, необходимо добавить случайно распределенный шум (он не должен быть фактически случайным, но он должен казаться случайным, как белый шум.)У меня проблема в том, что, хотя разрешение увеличивается, фактическое значение смещается на небольшое отрицательное значение.Вот один пример вывода на вход 1 вольт (ссылка 2 вольт, поэтому счетчик должен быть ровно половина для монотонной АЦП):
10 bits: 512 volts: 1.0
11 bits: 1024 volts: 1.0
12 bits: 2046 volts: 0.9990234375
13 bits: 4093 volts: 0.999267578125
14 bits: 8189 volts: 0.999633789062
15 bits: 16375 volts: 0.999450683594
16 bits: 32753 volts: 0.999542236328
17 bits: 65509 volts: 0.999588012695
18 bits: 131013 volts: 0.999549865723
24 bits: 8384565 volts: 0.999518036842
28 bits: 134152551 volts: 0.999514393508
В самом деле, независимо от того, сколько раз я не запустить моделированиеЯ всегда получаю около 0,9995 вместо 1;и последнее значение должно быть 134,217,728, а не 134,152,551, что составляет около 65,771 или около 1/4 из дополнительных 18 битов разрешения (совпадение? Я ныряю на 4.) Я подозреваю, что мой PRNG смещен каким-то образом, ноЯ использую Mersenne Twister по умолчанию, который поставляется с Python.
#!/usr/bin/python
#
# Demonstrates how oversampling/supersampling with noise can be used
# to improve the resolution of an ADC reading.
#
# Public domain.
#
import random, sys
volts = 1.000
reference = 2.000
noise = 0.01
adc_res = 10
def get_rand_bit():
return random.choice([-1, 1])
def volts_with_noise():
if get_rand_bit() == 1:
return volts + (noise * random.random() * get_rand_bit())
else:
return volts
def sample_adc(v):
# Sample ADC with adc_res bits on given voltage.
frac = v / reference
frac = max(min(frac, 1.0), 0.0) # clip voltage
return int(frac * (2 ** adc_res))
def adc_do_no_noise_sample():
return sample_adc(volts)
def adc_do_noise_sample(extra_bits_wanted):
# The number of extra samples required to gain n bits (according to
# Nyquist) is 2^(n+1). So for 1 extra bit, we need to sample 4 times.
samples = 2 ** (extra_bits_wanted + 1)
print "Sampling ", samples, " times for ", extra_bits_wanted, " extra bits."
# Sample the number of times and add the totals.
total = 0
for i in range(samples):
if i % 100000 == 99999:
print float(i * 100) / samples
sys.stdout.flush()
total += sample_adc(volts_with_noise())
# Divide by two (to cancel out the +1 in 2^(n+1)) and return the integer part.
return int(total / 2)
def convert_integer_to_volts(val, num_bits):
# Get a fraction.
frac = float(val) / (2 ** num_bits)
# Multiply by the reference.
return frac * reference
if __name__ == '__main__':
# First test: we want a 10 bit sample.
_10_bits = adc_do_no_noise_sample()
# Next, create additional samples.
_11_bits = adc_do_noise_sample(1)
_12_bits = adc_do_noise_sample(2)
_13_bits = adc_do_noise_sample(3)
_14_bits = adc_do_noise_sample(4)
_15_bits = adc_do_noise_sample(5)
_16_bits = adc_do_noise_sample(6)
_17_bits = adc_do_noise_sample(7)
_18_bits = adc_do_noise_sample(8)
_24_bits = adc_do_noise_sample(14)
_28_bits = adc_do_noise_sample(18)
# Print results both as integers and voltages.
print "10 bits: ", _10_bits, " volts: ", convert_integer_to_volts(_10_bits, 10)
print "11 bits: ", _11_bits, " volts: ", convert_integer_to_volts(_11_bits, 11)
print "12 bits: ", _12_bits, " volts: ", convert_integer_to_volts(_12_bits, 12)
print "13 bits: ", _13_bits, " volts: ", convert_integer_to_volts(_13_bits, 13)
print "14 bits: ", _14_bits, " volts: ", convert_integer_to_volts(_14_bits, 14)
print "15 bits: ", _15_bits, " volts: ", convert_integer_to_volts(_15_bits, 15)
print "16 bits: ", _16_bits, " volts: ", convert_integer_to_volts(_16_bits, 16)
print "17 bits: ", _17_bits, " volts: ", convert_integer_to_volts(_17_bits, 17)
print "18 bits: ", _18_bits, " volts: ", convert_integer_to_volts(_18_bits, 18)
print "24 bits: ", _24_bits, " volts: ", convert_integer_to_volts(_24_bits, 24)
print "28 bits: ", _28_bits, " volts: ", convert_integer_to_volts(_28_bits, 28)
Буду признателен за любые предложения по этому вопросу.В конечном итоге я планирую перенести это на недорогой микроконтроллер для реализации АЦП с высоким разрешением.Скорость будет очень важна, поэтому я, вероятно, буду использовать LFSR для генерации битов PRNG, которые не будут вдвое хуже, чем твистер Мерсенна, но должны быть достаточно хороши для большинства применений и, надеюсь, достаточно хороши для этого.