3

I’m using a program on a Raspberry Pi that measures the voltage across a probe within salt water to calculate the salinity of the water. The relationship is not linear but becomes a fairly straight line when a power trend line is plotted on a log-log plot. This means that the probes could be calibrated using only two values and simply interpolating a straight line between them when plotted on a log-log graph.

Salinity graphs

Unfortunately, the pre-existing program assumed a linear relationship using standard axes and I’m not sure how to change it to interpolate for a straight line on a log-log plot. Any help would be appreciated, please note that this is the first bit of coding I’ve done so my knowledge isn’t great. I've included bits of the code that involve the interpolation below:

import smbus
import time

# imports for plotting

import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate

# do the first plot - all values zero

nprobe=4

x=np.array([10.0, 30.0, 10.0, 30.0])
y=np.array([10.0, 10.0, 20.0, 20.0])
z=np.array([0., 0., 0., 0.])

# changing probe 1 to my handmade probe 1
fresh=np.array([0.,0.,0.,0.])
sea  =np.array([100.0,100.0,100.0,100.0])
range=np.array([100.0,100.0,100.0,100.0])
range=1.0*(sea-fresh)


# grid for plots - 20 is a bit coarse - was 100 give explicit (0,1) limits as no bcs here
###########   xi, yi = np.linspace(x.min(), x.max(), 50), np.linspace(y.min(), y.max(), 50)
xi, yi = np.linspace(0, 1, 50), np.linspace(0, 1, 50)
xi, yi = np.meshgrid(xi, yi)

rbf= scipy.interpolate.Rbf(x,y, z, function='linear')
zi= rbf(xi, yi)

plt.ion()

tank=plt.imshow(zi, vmin=0, vmax=50, origin='lower', extent=[0, 44, 0, 30])

plt.scatter(x, y, c=z)
plt.colorbar()

plt.draw()

Also, later on in the program:

# make r1 an array, results between 0-100 where 0 is 0% salinity and 100 is 2.5% salinity
        z=100.0*(r1-fresh)/range

        print time.strftime("%a, %d %b %Y, %H:%M:%S")
        print "measured reading at above time (r1)"
        print r1[0],r1[1],r1[2],r1[3]
        print "fresh values used for calibration"
        print fresh
        print "range between calibration values"
        print range
        print "percentage seawater (z)"
        print z

# interpolate
        rbf= scipy.interpolate.Rbf(x,y, z, function='linear')
        zi= rbf(xi, yi)
# alt interpolate
#########       zi=scipy.interpolate.griddata((x,y), z, (xi,yi), method='linear')

        print "zi"
        print zi
ali_m
  • 71,714
  • 23
  • 223
  • 298
Morthwyl
  • 31
  • 1
  • 3

1 Answers1

1

How about

import numpy as np
import scipy
import scipy.interpolate

import matplotlib.pyplot as plt

def log_interp1d(x, y, kind='linear'):
    """
    Returns interpolator function
    """
    log_x = np.log10(x)
    log_y = np.log10(y)
    lin_int = scipy.interpolate.interp1d(log_x, log_y, kind=kind)
    log_int = lambda z: np.power(10.0, lin_int(np.log10(z)))
    return log_int

powerlaw = lambda x, amp, index: amp * (x**index)

num_points = 20

# original data
xx = np.linspace(1.1, 10.1, num_points)
yy = powerlaw(xx, 10.0, -2.0)

# get interpolator
interpolator = log_interp1d(xx, yy)

# interpolate at points
zz = np.linspace(1.2, 8.9, num_points-1)
# interpolated points
fz = interpolator(zz)

plt.plot(xx, yy, 'o', zz, fz, '+')
plt.show()
Severin Pappadeux
  • 18,636
  • 3
  • 38
  • 64