nanoPhD
nanoPhD

Reputation: 400

Numpy Masking with Array

I'm not certain of the best way of asking this question, so I apologize ahead of time.

I'm trying find a peak on each row of an NxM numpy array of audio signals. Each row in the array is treated individually and I'd like to get all values a certain number of standard deviations above the noise floor for each N in the array in frequency space. In this experiment I know that I do not have a signal above 400Hz so I'm using that as my noise floor. I'm running into issues when trying to mask. Here is my code snippet:

from scipy import signal
import numpy as np


Pxx_den = signal.periodogram(input, fs=sampleRate ,nfft=sampleRate,axis=1)
p = np.array(Pxx_den)[1].astype(np.float)
noiseFloor = np.mean(p[:,400:],axis=1)
stdFloor = np.std(p[:,400:],axis=1)
p = np.ma.masked_less(p,noiseFloor+stdFloor*2)

This example will generate an error of:

ValueError: operands could not be broadcast together with shapes (91,5001) (91,)

I've deduced that this is because ma.masked_less works with a single value and does not take in an array. I would like the output to be an NxM array of values greater than the condition. Is there a Numpy way of doing what I'd like or an efficient alternative?

I've also looked at some peak detection routines such as peakUtils and scipy.signal.find_peaks_cwt() but they seem to only act on 1D arrays.

Thanks in advance

Upvotes: 1

Views: 814

Answers (1)

hpaulj
hpaulj

Reputation: 231385

Before getting too far into using masked arrays makes sure that the following code handles them. It has to be aware of how masked arrays works, or defer to masked array methods.

As to the specific problem, I think this recreates it:

In [612]: x=np.arange(10).reshape(2,5)

In [613]: np.ma.masked_less(x,np.array([3,6]))
...
ValueError: operands could not be broadcast together with shapes (2,5) (2,)

I have a 2d array, and I try to apply the < mask with different values for each row.

Instead I can generate the mask as a 2d array matching x:

In [627]: mask= x<np.array([3,6])[:,None]

In [628]: np.ma.masked_where(mask,x)
Out[628]: 
masked_array(data =
 [[-- -- -- 3 4]
 [-- 6 7 8 9]],
             mask =
 [[ True  True  True False False]
 [ True False False False False]],
       fill_value = 999999)

I can also select the values, though in a way that looses the 2d structure.

In [631]: x[~mask]
Out[631]: array([3, 4, 6, 7, 8, 9])

In [632]: np.ma.masked_where(mask,x).compressed()
Out[632]: array([3, 4, 6, 7, 8, 9])

Upvotes: 3

Related Questions