0
$\begingroup$

I am trying to produce a box function filter of a signal in python. I expected to find this functionality in scipy.signal, but I can't find any solutions. What I am trying to do is this.

I have 2 signals that look like this: enter image description here

I have the peaks plotted for both of the signals, as you can see. I am trying to create a box function filter so that I can get a result like this:

enter image description here

Here, the two signals are filtered so that that peaks are centered in a constant variable window, lets say 5.

You can also see that signals are normalized so that all maxima are 1 and all minima are 0. Is there any prebuilt solution for this?

EDIT

I'm getting closer to figuring it out, but I keep having trouble. Here is my code so far:

raw_signal = [0.04583763329719659,
 0.04805497846973594,
 0.04829505014640745,
 0.05887341212655883,
 0.05002700454497244,
 0.03658229798020329,
 0.03785355329455342,
 0.041801968109211884,
 0.02233076920674648,
 0.058624423036235385,
 0.04285942959540989,
 0.05198790422582533,
 0.07342396020248998,
 0.05624460427497979,
 0.053187046069069766,
 0.05705776529794093,
 0.055122999401646666,
 0.03843830454570707,
 0.05200852137932088,
 0.057458145238342695,
 0.04733597124868538,
 0.07260882812261116,
 0.05444879316200968,
 0.06107602057454642,
 0.05144282440596726,
 0.03842927653749939,
 0.062157345746527426,
 0.049414162276661955,
 0.06244672513275873,
 0.026325066210119985,
 0.049222807501791976,
 0.048303400035365485,
 0.033270250060013495,
 0.06265669035201427,
 0.0464532491605496,
 0.04716381918115076,
 0.05001360514143016,
 0.04871139499300625,
 0.03684319926833268,
 0.06930899362487253,
 0.04683942206611391,
 0.053229054537951015,
 0.05761049069405999,
 0.06470925254689064,
 0.0671662015520269,
 0.04771008352690842,
 0.06945096065464895,
 0.016286753452732228,
 0.05102230607008096,
 0.01769710761436727,
 0.06242152849154081,
 0.019350205184309743,
 0.03038432296307292,
 0.0609150647505885,
 0.05489945724548306,
 0.05819547914143186,
 0.026275048367097043,
 0.015321600585593842,
 0.05769180825154763,
 0.04853383834415581,
 0.04002726600447204,
 0.03246579690312501,
 0.05159124229976442,
 0.04558678156172391,
 0.04065268985868897,
 0.05376688459364232,
 0.03983559690823313,
 0.02996508228534367,
 0.024953327010734938,
 0.05553271730605047,
 0.04297505620343145,
 0.05980710957373958,
 0.04593995363393333,
 0.05778656013717409,
 0.040827999691828154,
 0.019963644081144594,
 0.051858118604286574,
 0.06540824360854458,
 0.05649360937240999,
 0.04654800250136759,
 0.05910070285608526,
 0.058185853049508296,
 0.05541932878259104,
 0.04814119565708097,
 0.015593319767504,
 0.0365044306818163,
 0.06034806101524737,
 0.037100095869391225,
 0.054988950068945996,
 0.02537936052249279,
 0.031081240376806818,
 0.06072348878660705,
 0.011991354040219449,
 0.044582271584658884,
 0.060200185907888226,
 0.040700219324207865,
 0.04851865196542349,
 0.056848127496778034,
 0.03311677974124905,
 0.05129374585521873]
def make_chunks(lst, n):
    """Yield successive n-sized chunks from lst."""
    chunks = []
    for i in range(0, len(lst), n):
        chunks.append(lst[i:i + n])
    
    return chunks


def get_local_max_min(windowed_chunks):

    max_coords = []
    min_coords = []
    original_idx = 0

    for i in windowed_chunks:
        local_maxima = max(i)
        local_minima = min(i)
        local_max_idx = i.index(local_maxima) + original_idx
        local_min_idx = i.index(local_minima) + original_idx
        local_max_coords = [local_max_idx, local_maxima]
        local_min_coords = [local_min_idx, local_minima]
        max_coords.append(local_max_coords)
        min_coords.append(local_min_coords)
        original_idx += window

    return max_coords, min_coords
    

def join_and_sort_coords(max_coords, min_coords):
    
    coord_lst = max_coords + min_coords
    coord_lst = sorted(coord_lst, key=lambda x: x[0])
    
    return coord_lst
    

def box_filter(coord_list, box_filter_span):
    
    box_filter_list = []
    for i in coord_list:
        mod_val = ([i[1]]*box_filter_span)
        box_filter_list.append(mod_val)
        
    box_filter_list = [item for sublist in box_filter_list for item in sublist]
        
    return box_filter_list
    

def plot_signals(raw_signal, max_coords, min_coords, box_filter_list):
    
    plt.figure(figsize=(20,10))
#     plt.plot(raw_signal)
    plt.plot(box_filter_list)
    for x,y in max_coords:
        plt.plot(x,y, color='red', marker = 'o')
    for x,y in min_coords:
        plt.plot(x,y, color='green', marker = 'o')


window = 10
box_filter_span = 5
windowed_chunks = make_chunks(raw_signal, window)
max_coords, min_coords = get_local_max_min(windowed_chunks)
coord_list = join_and_sort_coords(max_coords, min_coords)
box_filter_list = box_filter(coord_list, box_filter_span)
plot_signals(raw_signal, max_coords, min_coords, box_filter_list)

Which produces this:

enter image description here

This is wrong because it should alternate max-min-max-min and so on, like in the second plot. You can see my plot breaking at the 3rd minima.

$\endgroup$
2
  • $\begingroup$ huh, I'm not quite sure I understand the "boxification" step. Can you take me through what that is supposed to do? $\endgroup$ – Marcus Müller Nov 11 '20 at 13:43
  • $\begingroup$ @MarcusMüller thanks for your reply. I made some edits and provided my code so far. Does this help you understand my intent? Thanks! $\endgroup$ – connor449 Nov 11 '20 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.