#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import cffi
import numpy as np
import matplotlib.pyplot as plt
from math import exp,log

c_header = '''double Compute (double x);
void plot ();
'''
def print_table (tab):
  return
  K  = 4095.0
  R0 = 10.0
  s  = 'static constexpr Pair measured [] = {\n'
  l  = len(tab)
  r  = range (0, l)
  for n in r:
    m  = tab [l - n - 1]
    R  = m[1]
    u  = K * R / (R + R0)
    s += '  {{ {:+6.1f},{:8.3f} }},\n'.format(u, m[0])
  s += '};\n'
  print (s)

def adc (R):
  K0 = 4095.0
  R0 = 10.0
  return K0 * R / (R + R0)

def R_NTC_T (t):
  T  = 273.15 + t
  T0 = 298.15
  R0 = 10000.0;
  B  = 3977.0
  R  = R0 * exp (B * (1.0 / T - 1.0 / T0))
  return 0.001 * R

def beta_diff (table):
  print ('t[°C] : R comp [kΩ] | R table [kΩ] | odchylka [%]')
  for m in table:
    t = m[0]
    R = R_NTC_T (t)
    D = 100.0 * (R - m[1]) / R
    print('{:+5g} : {:8.3f}    |  {:8.3f}    |   {:+.2g}%'.format(t, R, m[1], D))

def ComuputeStHaCoeff (table):
  e = table[ 5]; a = log (1000.0 * e[1]); f = 1.0 / (e[0] + 273.15) # 0 °C
  e = table[ 8]; b = log (1000.0 * e[1]); g = 1.0 / (e[0] + 273.15) # 25°C
  e = table[11]; c = log (1000.0 * e[1]); h = 1.0 / (e[0] + 273.15) # 50°C
  e = table[13]; d = log (1000.0 * e[1]); i = 1.0 / (e[0] + 273.15) # 70°C
  M = np.matrix ([[1.0, a, a**2, a**3],
                  [1.0, b, b**2, b**3],
                  [1.0, c, c**2, c**3],
                  [1.0, d, d**2, d**3]])
  I = M.getI(); # inverze matice
  V = np.matrix ([f, g, h, i])
  X = I * V.transpose()
  letters = ['A','B','C','D']; n=0;
  X = X.tolist()
  R = []
  print('Steinhart-Hart koeficienty :')
  for x in X:
    print('  {:s} = {:+20.14e}'.format(letters[n], x[0]))
    n += 1
    R.append (x[0])
  return R

def SteinhartHart (r, coe):
  R  = 1000.0 * r
  A  = coe[0]; B = coe[1]; C = coe[2]; D = coe[3];
  L  = log(R); K  = L;  # Ku podivu koeficienty vypočítané ze 4 bodů tabulky
  W  = A                # Steinhart-Hart metodou dávají lepší výsledky než
  W += B * K;  K *= L;  # výrobcem udávaný koeficient beta.
  W += C * K;  K *= L;
  W += D * K
  return 1.0 / W - 273.15   # [°C]
  
def stha_diff (table, c):
  print ('rozdíl teplot vypočtený podle Steinhart-Hart formule :')
  for m in table:
    t = SteinhartHart(m[1], c)
    print ('{:+5g} => {:g}'.format(m[0], t))
def SHCompute (u, c):
  K = 4095.0; R0 = 10.0
  R = u * R0 / (K - u)
  return SteinhartHart(R, c)
def graph_err (tab, C,c):
  #return
  xs = np.arange(134.0, 4010.0, 1.0); ys = []
  for x in xs: ys.append (SHCompute(x,c) - C.Compute(x))
  xc = []; yc = []
  for m in tab:
    x = adc (m[1])
    xc.append (x)
    yc.append (SHCompute(x,c) - m[0])
  fig,ap = plt.subplots (1, figsize=(6.0,4.0))
  fig.suptitle ('Chyba NTC', fontsize=15)
  ap.plot (xs, ys)
  ap.plot (xc, yc, '.')
  ap.legend (['Odchylka od vzorce', 'Body tabulky'])
  plt.grid()
  plt.xlabel('ADC [0-4095]')
  plt.ylabel('teplota [°C]')
  plt.savefig('err.png')
  #plt.show()
def graph(tab, c):
  #return
  xs = [];  ys = [];
  for m in tab:
    xs.append (adc (m[1]))
    ys.append (m[0])
  xc = np.arange(100.0, 4050.0, 10.0);  yc = [];
  for x in xc: yc.append(SHCompute(x,c))
  fig,ap = plt.subplots (1, figsize=(6.0,4.0))
  fig.suptitle ('NTC 10k', fontsize=15)
  ap.plot (xs, ys, linewidth=3)
  ap.plot (xc, yc)
  ap.legend (['Tabulka výrobce','Steinhart-Hart vzorce'])
  plt.grid()
  plt.xlabel('ADC [0-4095]')
  plt.ylabel('teplota [°C]')
  plt.savefig('ntc.png')
  #plt.show()

def main_func():
  table = [(-40,334.202),(-38,293.759),(-30,177.797),(-25,131.380),(-20,97.923),(-15,73.612),(-10,55.805),
           (-5,42.655),(0,32.869),(5,25.527),(10,19.977),(15,15.750),(20,12.507),(25,10.0),(30,8.049),
           (35,6.521),(40,5.315),(45,4.358),(50,3.594),(55,2.980),(60,2.483),(65,2.080),(70,1.750),(80,1.256),
           (90,0.916),(100,0.678),(110,0.509),(120,0.386),(125,0.338)]
  print_table (table)
  c = ComuputeStHaCoeff(table)
  #stha_diff   (table, c)
  ffi = cffi.FFI()
  ffi.cdef(c_header)
  C = ffi.dlopen("./spline.so")
  C.plot()
  graph_err   (table, C,c)
  ffi.dlclose (C)
  graph       (table, c)
  return
  beta_diff   (table)

if __name__ == '__main__':
  main_func()
  print ("END OK")