Bhuvan Kumar
Bhuvan Kumar

Reputation: 564

Angle Interpolation

I was trying to interpolate the angle which are in list.

Dir DirOffset
0   109.6085
30  77.5099
60  30.5287
90  -10.2748
120 -75.359
150 -147.6015
180 -162.7055
210 21.0103
240 3.5502
270 -11.5475
300 -39.8371
330 -109.5473
360 109.6085

enter image description here

I have written the code to interpolate angle(It keeps on calculating the mean in between angle to reach the interpolation value) which is taking long time. Please help me if some one have the faster and shorter code.

enter image description here

from cmath import rect, phase
from math import radians, degrees, sqrt

#Calculate the mean of angles in List
def mean_angle(degArray):
    return degrees(phase(sum(rect(1, radians(d)) for d in degArray)/len(degArray)))

#Calculate Interpolation Angle
def Interpolate_angle(Dir, DirOffset, ValuetoInterpolate):
    #Create Lower and Higher bin of ValuetoInterpolate
    DirLBin = round(float(ValuetoInterpolate)/30,0)*30
    DirHBin = round(float(ValuetoInterpolate+15)/30,0)*30

    #Check if the ValuetoInterpolate lies between Lower and Higher bin
    if DirLBin == DirHBin:
        DirLBin = DirHBin-30
        if DirLBin <= ValuetoInterpolate <= DirHBin:
            DBin = [float(DirLBin), float(DirHBin)]
            Doff = [DirOffset[Dir.index(DirLBin)], DirOffset[Dir.index(DirHBin)]] 
        else:
            DirHBin = DirLBin+30
            DBin = [float(DirLBin), float(DirHBin)]
            Doff = [DirOffset[Dir.index(DirLBin)], DirOffset[Dir.index(DirHBin)]] 

    else:
        DBin = [float(DirLBin), float(DirHBin)]
        Doff = [DirOffset[Dir.index(DirLBin)], DirOffset[Dir.index(DirHBin)]]

    #Run 50 iterations to calculate the mean of angle and find the ValuetoInterpolate    
    for i in range(51):
        DMean = mean_angle(DBin)
        DOMean = mean_angle(Doff)
        if DMean < 0 :
            DMean = 360+DMean

        if DBin[0] <= ValuetoInterpolate <=DMean:
            DBin = [float(DBin[0]), float(DMean)]
            Doff = [float(Doff[0]), float(DOMean)]
        else:
            DBin = [float(DMean), float(DBin[1])]
            Doff = [float(DOMean), float(Doff[1])] 

    return DOMean

Dir = range(0,370,30)
DirOffset = [109.6085,77.5099,30.5287,-10.2748,-75.359,-147.6015,-162.7055,21.0103,3.5502,-11.5475,-39.8371,-109.5473,109.6085]
ValuetoInterpolate = 194.4
print Interpolate_angle(Dir, DirOffset, ValuetoInterpolate)

Upvotes: 2

Views: 1677

Answers (2)

tomcheney
tomcheney

Reputation: 1810

Here is a Pandas/Numpy based solution for interpolating an angle series with NaN data.

import pandas as pd
import numpy as np

def interpolate_degrees(series: pd.Series) -> pd.Series:
    # I don't want to modify in place 
    series = series.copy()
    
    # convert to radians
    a = np.radians(series)
    
    # unwrap if not nan
    a[~np.isnan(a)] = np.unwrap(a[~np.isnan(a)])
    series.update(a)
    
    # interpolate unwrapped values
    interpolated = series.interpolate()
    
    # wrap 0 - 360 (2*pi)
    wrapped = (interpolated + 2*np.pi) % (2 * np.pi)
    
    # cconvert back to degrees
    degrees = np.degrees(wrapped)
    series.update(degrees)
    return series

Usage:

angle = [350, np.nan, 355, np.nan, 359, np.nan, 1, np.nan, 10]
df = pd.DataFrame(data=angle, columns=['angle'])

df['interpolated'] = interpolate_degrees(df.angle)

example output

Upvotes: 2

Bhuvan Kumar
Bhuvan Kumar

Reputation: 564

I got the solution for above question after searching answers from stackoverflow, then I modified little bit to get the solution as per my requirement. The solution might be useful for some one in need of it.

I interpolated the Degrees using below function for each directional bin (0,30,60....360) till 360(360 and 0 degree will be same) and store them in dictionary to create a DataFrame(pandas DataFrame) and left join it with main DataFrame and process further.

enter image description here

def InterpolateDegrees(109.6085,77.5099)

will return interpolated array of DirectionOffset 0 to 30 degree with an interval of 0.1 (0.0, 0.1, 0.2, 0.3......28.7, 29.8, 29.9)

import numpy as np
from math import fabs

def InterpolateDegrees(start, end, BinSector=12):
    BinAngle = 360/BinSector
    amount = np.arange(0,1,(1/(BinAngle/0.1)))
    dif = fabs(end-start)
    if dif >180:
        if end>start:
            start+=360
        else:
            end+=360

    #Interpolate it
    value = (start + ((end-start)*amount))

    #Wrap it
    rzero = 360

    Arr = np.where((value>=0) & (value<=360), (value), (value % rzero))
    return Arr

Upvotes: 3

Related Questions