I have noisy heading data for a vehicle that I would like to filter. However, the vehicle heading must be an angle between -180 and +180 degrees, so there are several 360 degree "jumps" in the data (that I need to keep) where the vehicle's heading crosses this threshold (see figure). Using a basic lowpass filter on the data works to filter out the noise, but does not give the desired result where these angle wraps occur (see figure). Does anyone have any ideas on a good solution for this problem? (blue is raw, orange is filtered)
I ended up unwrapping the data, applying the filter, and re-wrapping the data as Warren suggested. Attached is the function that I created to accomplish this. I apologize for any poor python practices in this code. I am new to python.
from scipy.signal import filtfilt
def wrap_filter(filt_num, filt_denom, data, wrap_threshold=3):
"""
Parameters
----------
filt_num : Filter numerator (designed from scipy.signal.butter)
filt_denom : Filter denominator (designed from scipy.signal.butter)
data : data series to be filtered
wrap_threshold: delta in consecutive datapoints that will be considered a wrap
Returns
-------
Filtered data accounting for angle wraps.
"""
#initialize
key = 0
data_dict = {}
data_list = []
filt_data_list = []
prev_data=data[0]
filter_pad_length = 500
#break data into dictionary at wrap points
for data_point in data:
if abs(prev_data - data_point) > wrap_threshold:
data_dict[key] = data_list
data_list = [data_point]
key += 1
else:
data_list.append(data_point)
prev_data = data_point
#add last section of data
data_dict[key] = data_list
#filter each section of data and append to final data list
for data_section in data_dict:
if len(data_dict[data_section]) > filter_pad_length: #filter padlen
filt_data_section = list(filtfilt(filt_num, filt_denom, data_dict[data_section], padlen=filter_pad_length))
#filt_data_list.append(filt_data_section)
filt_data_list += filt_data_section
else:
filt_data_list += data_dict[data_section]
return filt_data_list