0

I have a sparse data set, f44, made up of bearings in degrees and ssi (dbm) values:

       ssi
deg       
4.0    -69
59.0   -73
162.0  -73
267.0  -61
319.0  -75

I reindexed f44 to include all the missing indices from 0-359:

f44i = f44.reindex(np.arange(0,360))

When I interpolate (using quadratic) and plot the figure, it's apparent that the result doesn't interpolate between the first/lowest bearing and the highest:

f44i = f44i.interpolate(method='quadratic')
f44i.plot()

naive interpolation

How can I interpolate this data in a way that will fill in between 0 and 360 degrees? The pandas Series.interpolate documentation does not appear to have anything built-in, nor does the scipy documentation.

datu-puti
  • 1,306
  • 14
  • 33

2 Answers2

1

I have an alternative approach to this problem using scipy to interpolate onto a closed curve. First, I converted your data from (deg, ssi) to psuedo cartesian coordinates (x,y) assuming deg is the polar angle and ssi is the (negative) of the radial distance. Then you can use the method defined here to interpolate a closed curve onto a set of (x,y) points.

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

dic = {'deg': [4.0, 59.0, 162.0, 267.0, 319.0],
       'ssi': [-69, -73, -73, -61, -75]}

f44  = pandas.DataFrame(data=dic)

'''
Now, lets do the following. Convert your data from (deg, ssi) to (x,y)
where x = ssi* cosd(deg), y=ssi*sind(deg). Now we need to interpolate a closed
curve onto these set of cartesian points.  
'''

f44['x'] = -f44['ssi']*np.cos( np.deg2rad(f44['deg']))
f44['y'] = -f44['ssi']*np.sin( np.deg2rad(f44['deg']))

x = f44.as_matrix(columns=[f44.columns[2]])[:,0]
y = f44.as_matrix(columns=[f44.columns[3]])[:,0]
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]

tck, u = interpolate.splprep([x, y], s=0, per=True)
xi, yi = interpolate.splev(np.linspace(0, 1, 1000), tck)

# Save interpolated data to new dataframe. 
f44i = pandas.DataFrame(data = {'x':xi, 'y':yi})

f44i['deg'] = np.rad2deg( np.arctan2(f44i['y'],f44i['x']))
f44i['ssi'] =-np.sqrt( f44i['x']**2 + f44i['y']**2)

for i,l in enumerate(f44i['deg']):
    if l < 0:
        f44i['deg'][i] = 360 + f44i['deg'][i]

fig, ax = plt.subplots(1, 1)
ax.plot(f44i['deg'], f44i['ssi'], '.', markersize=0.5)
ax.plot(f44['deg'], f44['ssi'], '.', color='red')
plt.show()

Now we get a curve that looks like the one below. (re-converted from the psuedo cartesian coordinates to your preferred (deg, ssi) coordinates). Also, I have created a new dataframe to replace the f44i you created. You can make this code more suitable for your specific application.

Interpolation using a closed curve.

  • That's a great approach, thank you. I like the output from mine better, the second peak in yours doesn't make much sense to me since there is no value that really justifies that peak. I'll see if I can dissect your answer and apply a better interpolation function. – datu-puti Dec 19 '17 at 19:40
  • 1
    Thank you. You're right that trying to fit a spline with less points leads to oscillations (see [Runge's Phenomena](https://en.wikipedia.org/wiki/Runge%27s_phenomenon)). The interpolation will get better with a larger number of points. You can also try playing with different smoothing parameters and degree for the B-spline to get a better curve (`s=0` enforces that the interpolated curve passes through all points). –  Dec 19 '17 at 19:50
0

I'm not convinced this is the best way to do this, but it seems to work. Please add something if there is a better way.

Since I'm only interested in 0-360 degrees, I can duplicate the dataset from -360-0, and 360-720, expanding my original data set to the left and right, like so:

import numpy as  np    

# Create left side
f44il = f44i.copy()
f44il.index = np.arange(-360,0)

# Create right side
f44ir = f44i.copy()
f44ir.index = np.arange(360,720)

Interpolating and plotting the result looks promising (the third command shows 0-360 in a different color):

f44expanded = pd.concat([f44il, f44i, f44ir]).interpolate(method='quadratic')
f44expanded.plot()
f44expanded[np.arange(0,360)].plot()

repeating data

Then I can just create a new series from the interpolated data with an index from 0-360, which looks like it gives me exactly what I want:

f44final = f44expanded[np.arange(0,360)]
f44final.plot()

final plot

I suspect there is a better way to do this, so feel free to add an answer if you know of one.

datu-puti
  • 1,306
  • 14
  • 33