mirror of
https://github.com/osmarks/random-stuff
synced 2024-11-09 22:09:55 +00:00
files
This commit is contained in:
parent
494e8c9352
commit
152c0fdbd3
97
arithmetic_coder.py
Normal file
97
arithmetic_coder.py
Normal file
@ -0,0 +1,97 @@
|
||||
from fractions import Fraction
|
||||
|
||||
def uniform(syms):
|
||||
def pdist(seq):
|
||||
return {s: Fraction(1, len(syms)) for s in syms}
|
||||
return pdist
|
||||
|
||||
def cdfs(distribution):
|
||||
cdf_lo = {}
|
||||
cdf_hi = {}
|
||||
total_probability = 0
|
||||
for sym, prob in distribution.items():
|
||||
cdf_lo[sym] = total_probability # we could also use the last symbol as the lower bound but this is more explicit
|
||||
total_probability += prob
|
||||
cdf_hi[sym] = total_probability
|
||||
return cdf_lo, cdf_hi
|
||||
|
||||
def encode(sequence, pdist):
|
||||
a = Fraction(0, 1)
|
||||
b = Fraction(1, 1)
|
||||
|
||||
bits = []
|
||||
|
||||
for i, x in enumerate(sequence):
|
||||
distribution = pdist(sequence[:i])
|
||||
cdf_lo, cdf_hi = cdfs(distribution)
|
||||
rang = b - a
|
||||
b = a + rang * cdf_hi[x]
|
||||
a += rang * cdf_lo[x]
|
||||
|
||||
# if our interval is sufficiently constrained, emit bits
|
||||
while True:
|
||||
if a < b < Fraction(1, 2):
|
||||
bits.append(0)
|
||||
a *= 2
|
||||
b *= 2
|
||||
elif Fraction(1, 2) < a < b:
|
||||
bits.append(1)
|
||||
a *= 2
|
||||
b *= 2
|
||||
a -= 1
|
||||
b -= 1
|
||||
else:
|
||||
break
|
||||
|
||||
# it may still be the case that a and b are in [0,1], i.e. we have not emitted enough bits
|
||||
# to constrain it in the decoder
|
||||
while a > 0 or b < 1:
|
||||
c = (a + b) / 2 # slightly suboptimal: try and write out midpoint
|
||||
if c < Fraction(1, 2):
|
||||
bits.append(0)
|
||||
a *= 2
|
||||
b *= 2
|
||||
else:
|
||||
bits.append(1)
|
||||
a *= 2
|
||||
a -= 1
|
||||
b *= 2
|
||||
b -= 1
|
||||
|
||||
return bits
|
||||
|
||||
def decode(bits, pdist):
|
||||
a = Fraction(0, 1)
|
||||
b = Fraction(1, 1)
|
||||
scale = Fraction(1, 2)
|
||||
|
||||
sequence = []
|
||||
while bits:
|
||||
distribution = pdist(sequence)
|
||||
cdf_lo, cdf_hi = cdfs(distribution)
|
||||
for (lo, hi), sym in zip(zip(cdf_lo.values(), cdf_hi.values()), cdf_lo.keys()):
|
||||
if lo <= a < b <= hi: # if message interval is subset of symbol interval, emit symbol
|
||||
sequence.append(sym)
|
||||
# expand working interval and adjust scale up
|
||||
# (effectively, consume symbol in weird base)
|
||||
range = hi - lo
|
||||
a = (a - lo) / range
|
||||
b = (b - lo) / range
|
||||
scale /= range
|
||||
break
|
||||
else:
|
||||
# consume a bit
|
||||
bit = bits.pop(0)
|
||||
a += bit * scale
|
||||
b = a + scale
|
||||
scale /= 2
|
||||
|
||||
return sequence
|
||||
|
||||
dist = lambda seq: {"a": Fraction(98, 100), "b": Fraction(1, 100), "c": Fraction(1, 100)}
|
||||
input = "abbabaccabbabbbbbba"
|
||||
bits = encode(input, dist)
|
||||
print(bits)
|
||||
result = "".join(decode(bits, dist))
|
||||
print(input, result)
|
||||
assert input == result, "oh no"
|
84
bmp280_prometheus.py
Normal file
84
bmp280_prometheus.py
Normal file
@ -0,0 +1,84 @@
|
||||
import smbus
|
||||
import struct
|
||||
import time
|
||||
from prometheus_client import start_http_server, Gauge
|
||||
import sys
|
||||
|
||||
location = sys.argv[1]
|
||||
|
||||
bus = smbus.SMBus(1)
|
||||
ADDR = 0x76
|
||||
ID_REGISTER = 0xD0
|
||||
TARGET_ID = 0x58
|
||||
CTRL_MEAS_REGISTER = 0xF4
|
||||
PRESSURE_REGISTER_BASE = 0xF7
|
||||
TEMP_REGISTER_BASE = 0xFA
|
||||
CALIBRAITON_VALUES = {
|
||||
"dig_T1": {"address": (0x88, 0x89), "unpack": "<H"},
|
||||
"dig_T2": {"address": (0x8A, 0x8B), "unpack": "<h"},
|
||||
"dig_T3": {"address": (0x8C, 0x8D), "unpack": "<h"},
|
||||
"dig_P1": {"address": (0x8E, 0x8F), "unpack": "<H"},
|
||||
"dig_P2": {"address": (0x90, 0x91), "unpack": "<h"},
|
||||
"dig_P3": {"address": (0x92, 0x93), "unpack": "<h"},
|
||||
"dig_P4": {"address": (0x94, 0x95), "unpack": "<h"},
|
||||
"dig_P5": {"address": (0x96, 0x97), "unpack": "<h"},
|
||||
"dig_P6": {"address": (0x98, 0x99), "unpack": "<h"},
|
||||
"dig_P7": {"address": (0x9A, 0x9B), "unpack": "<h"},
|
||||
"dig_P8": {"address": (0x9C, 0x9D), "unpack": "<h"},
|
||||
"dig_P9": {"address": (0x9E, 0x9F), "unpack": "<h"}
|
||||
}
|
||||
|
||||
def setup():
|
||||
assert bus.read_byte_data(ADDR, ID_REGISTER) == TARGET_ID
|
||||
bus.write_byte_data(ADDR, CTRL_MEAS_REGISTER, 0b101_101_11) # max oversampling mode (we don"t really care about power), power on
|
||||
calibration = {}
|
||||
for key, value in CALIBRAITON_VALUES.items():
|
||||
calibration[key] = struct.unpack(value["unpack"], bytes([bus.read_byte_data(ADDR, value["address"][0]), bus.read_byte_data(ADDR, value["address"][1])]))[0]
|
||||
return calibration
|
||||
|
||||
def read_raw_adc(base):
|
||||
msb, lsb, xlsb = bus.read_i2c_block_data(ADDR, base, 3)
|
||||
return (msb << 16 | lsb << 8 | xlsb) >> 4
|
||||
|
||||
def bmp280_compensate_T_double(adc_T, dig_T1, dig_T2, dig_T3, **kwargs):
|
||||
var1 = (adc_T / 16384.0 - dig_T1 / 1024.0) * dig_T2
|
||||
var2 = ((adc_T / 131072.0 - dig_T1 / 8192.0) *
|
||||
(adc_T / 131072.0 - dig_T1 / 8192.0)) * dig_T3
|
||||
t_fine = int(var1 + var2)
|
||||
T = (var1 + var2) / 5120.0
|
||||
return T, t_fine
|
||||
|
||||
def bmp280_compensate_P_double(adc_P, t_fine, dig_P1, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9, **kwargs):
|
||||
var1 = t_fine / 2.0 - 64000.0
|
||||
var2 = var1 * var1 * dig_P6 / 32768.0
|
||||
var2 = var2 + var1 * dig_P5 * 2.0
|
||||
var2 = (var2 / 4.0) + (dig_P4 * 65536.0)
|
||||
var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0
|
||||
var1 = (1.0 + var1 / 32768.0) * dig_P1
|
||||
if var1 == 0.0:
|
||||
return 0 # avoid exception caused by division by zero
|
||||
p = 1048576.0 - adc_P
|
||||
p = (p - (var2 / 4096.0)) * 6250.0 / var1
|
||||
var1 = dig_P9 * p * p / 2147483648.0
|
||||
var2 = p * dig_P8 / 32768.0
|
||||
p = p + (var1 + var2 + dig_P7) / 16.0
|
||||
return p
|
||||
|
||||
calibration = setup()
|
||||
|
||||
temperature = Gauge("bmp280_temperature", "Temperature in Celsius", ("location",))
|
||||
pressure = Gauge("bmp280_pressure", "Pressure in Pascals", ("location",))
|
||||
|
||||
def read_temperature_pressure():
|
||||
adc_T = read_raw_adc(TEMP_REGISTER_BASE)
|
||||
adc_P = read_raw_adc(PRESSURE_REGISTER_BASE)
|
||||
T, t_fine = bmp280_compensate_T_double(adc_T, **calibration)
|
||||
P = bmp280_compensate_P_double(adc_P, t_fine, **calibration)
|
||||
temperature.labels(location=location).set(T)
|
||||
pressure.labels(location=location).set(P)
|
||||
|
||||
start_http_server(9091)
|
||||
|
||||
while True:
|
||||
read_temperature_pressure()
|
||||
time.sleep(1)
|
Loading…
Reference in New Issue
Block a user