grrrr / nsgt

Non Stationary Gabor Transform (NSGT), Python implementation
http://grrrr.org/research/software/nsgt
Artistic License 2.0
95 stars 28 forks source link

Q-factor too high for frequencies #18

Open ivanmkc opened 8 years ago

ivanmkc commented 8 years ago

Hi,

Many thanks for this great package. I'm using it for musical note analysis and thus I'm putting in the minimum frequency as midi2hz(21) and the maximum as midi2hz(108). 21 and 108 are the lowest and highest notes on a piano respectively, in midi format, and midi2hz converts midi values to Hertz.

My code is thus:

Ls = len(segmentWindow)
numBins = int(np.ceil(108 - 21))
scl = LogScale(midi2hz(21), midi2hz(108), numBins)
nsgt = NSGT(scl, samplingRate, Ls, real=True, matrixform=True)

I'm getting the following warning: UserWarning: Q-factor too high for frequencies 27.50,29.10,30.78,32.57,34.46,36.46,38.58,40.82,43.19,45.69,48.35,51.15,54.12,57.26,60.59,64.10,67.82,71.76,75.92,80.33,84.99,89.93,95.15,100.67,106.51,112.69,119.23,126.15,133.48,141.22,149.42,158.09,167.27,176.98,187.25 warn("Q-factor too high for frequencies %s"%",".join("%.2f"%fi for fi in f[q >= qneeded]))

  1. Do you know why this is?
  2. How would you recommend fixing this?

Thanks

grrrr commented 8 years ago

Hi Ivan, high Q factors (high spectral resolution) need large frame sizes aka time support in mathematical terms. I need to formalize this sometime, it's a reoccurring question. Obviously your "segment length" is about a factor 6 or so too small to resolve your low frequency bins.

Am 31.07.2016 um 19:42 schrieb Ivan Cheung notifications@github.com:

Hi,

Many thanks for this great package. I'm using it for musical note analysis and thus I'm putting in the minimum frequency as midi2hz(21) and the maximum as midi2hz(108). 21 and 108 are the lowest and highest notes on a piano respectively, in midi format, and midi2hz converts midi values to Hertz.

My code is thus: ` Ls = len(segmentWindow)

numBins = int(np.ceil(108 - 21)) scl = LogScale(midi2hz(21), midi2hz(108), numBins) nsgt = NSGT(scl, samplingRate, Ls, real=True, matrixform=True) `

I'm getting the following warning: UserWarning: Q-factor too high for frequencies 27.50,29.10,30.78,32.57,34.46,36.46,38.58,40.82,43.19,45.69,48.35,51.15,54.12,57.26,60.59,64.10,67.82,71.76,75.92,80.33,84.99,89.93,95.15,100.67,106.51,112.69,119.23,126.15,133.48,141.22,149.42,158.09,167.27,176.98,187.25 warn("Q-factor too high for frequencies %s"%",".join("%.2f"%fi for fi in f[q >= qneeded]))

  1. Do you know why this is?
  2. How would you recommend fixing this?

Thanks

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grrrr/nsgt/issues/18, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJ-JvFi4mBhUEZAYqS6tLqYcYi4C7eeks5qbN6HgaJpZM4JZFLA .

ivanmkc commented 8 years ago

Hi Thomas,

Thanks for responding. I understand the need for more samples to support more spectral resolution.

  1. I'm wondering if there's anything I can change besides reducing the number of bins. I tried reducing the number of bins by a factor of 4 and it worked to remove the warning, but it took 3 times longer to compute which was counter-intuitive for me. Shouldn't it take less time for less bins?
  2. How do I reduce the q factor? Can I set this?
  3. Also, in nsfgwin, there is the line of code:

qneeded = f_(Ls/(8._sr))

Where does the 8 come from? Is it kind of arbitrary right now?

Thanks

On Sun, Jul 31, 2016 at 3:47 PM, Thomas Grill notifications@github.com wrote:

Hi Ivan, high Q factors (high spectral resolution) need large frame sizes aka time support in mathematical terms. I need to formalize this sometime, it's a reoccurring question. Obviously your "segment length" is about a factor 6 or so too small to resolve your low frequency bins.

Am 31.07.2016 um 19:42 schrieb Ivan Cheung notifications@github.com:

Hi,

Many thanks for this great package. I'm using it for musical note analysis and thus I'm putting in the minimum frequency as midi2hz(21) and the maximum as midi2hz(108). 21 and 108 are the lowest and highest notes on a piano respectively, in midi format, and midi2hz converts midi values to Hertz.

My code is thus: ` Ls = len(segmentWindow)

numBins = int(np.ceil(108 - 21)) scl = LogScale(midi2hz(21), midi2hz(108), numBins) nsgt = NSGT(scl, samplingRate, Ls, real=True, matrixform=True) `

I'm getting the following warning: UserWarning: Q-factor too high for frequencies

27.50,29.10,30.78,32.57,34.46,36.46,38.58,40.82,43.19,45.69,48.35,51.15,54.12,57.26,60.59,64.10,67.82,71.76,75.92,80.33,84.99,89.93,95.15,100.67,106.51,112.69,119.23,126.15,133.48,141.22,149.42,158.09,167.27,176.98,187.25 warn("Q-factor too high for frequencies %s"%",".join("%.2f"%fi for fi in f[q >= qneeded]))

  1. Do you know why this is?
  2. How would you recommend fixing this?

Thanks

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grrrr/nsgt/issues/18, or mute the thread < https://github.com/notifications/unsubscribe-auth/AAJ-JvFi4mBhUEZAYqS6tLqYcYi4C7eeks5qbN6HgaJpZM4JZFLA

.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/grrrr/nsgt/issues/18#issuecomment-236452447, or mute the thread https://github.com/notifications/unsubscribe-auth/ABgzgQWXhx9p5d7agyZZr7zRpdWUM02fks5qbPvngaJpZM4JZFLA .

sevagh commented 3 years ago

@grrrr what do you think of adding the following code to the nsgt Scale class - I can submit the PR

class Scale:
    dbnd = 1.e-8

    def __init__(self, bnds):
        self.bnds = bnds

    def __len__(self):
        return self.bnds

    def Q(self, bnd=None):
        # numerical differentiation (if self.Q not defined by sub-class)
        if bnd is None:
            bnd = np.arange(self.bnds)
        return self.F(bnd)*self.dbnd/(self.F(bnd+self.dbnd)-self.F(bnd-self.dbnd))

    def __call__(self):
        f = np.array([self.F(b) for b in range(self.bnds)],dtype=float)
        q = np.array([self.Q(b) for b in range(self.bnds)],dtype=float)
        return f,q

    def suggested_sllen(self, sr):
        f,q = self()

        Ls = int(np.ceil(max((q*8.*sr)/f)))

        # make sure its divisible by 4
        Ls = Ls + -Ls % 4

        return Ls

The way to use it is to get the suggested sllen that supports your desired frequencies and Q factors (from which you can get trlen for slicq) - the same should apply for the length argument to the non-sliced transform:

scl = LogScale(fmin, fs/2, fbins)

# use slice length required to support desired frequency scale/q factors
sllen = scl.suggested_sllen(fs)

# optional trlen for sliced-q, otherwise Ls=sllen
trlen = sllen//4
trlen = trlen + -trlen % 2 # make trlen divisible by 2