Efficient way of accessing N multiples of k indexes and performing an operation over it

Hi all,

Im trying to implement a filter that runs over a spectrogram frequencies for each time frame and filters out inharmonic frequencies.

What I need is, given a time frame, for each frequency k in this timeframe, to access frequencies multiple of k (the harmonics), then perform some operation over them. So for frequency k, k=1,…,F, I need to access indexes, k, 2k, 3k,…, N*k (N in total), perform some operation and set the result to the position k (original frequency bin). Same calculation for all timeframes.
In resume, it would be something like this:
spec[k, :] = operation(spec[mutiple_indexes,:])

Basically its like running a operation sliding window starting in each frequency, but for each frequency this sliding window is more space (spaced by the frequency value).

I can do this iteratively, but Im wondering if there is a vectorized way of doing this.
I was thinking about torch.unfold, but it can only work on sequential patches, not of increasing stride.

Any suggestions?

Thanks!

I’m gonna assume you want to run 1D convolutions just in those specific bins rather than 2D convolutions around the harmonics.

If that were the case you can preset an slice operator which retrieves those harmonics, then you can run a 2D convolution with kernel size 1 for the frequency. With a proper padding you can keep the shape and then using the preset slice to “paste” back the values.

Kind of like this:

import torch

N = 1
T = 5
pad = (0,T // 2)
convolution = torch.nn.Conv2d(in_channels=1, out_channels=N, kernel_size=(1, T), padding=pad)

sp = torch.rand(256, 128)

preset_slice = [2*i for i in range(128)]  # Choose your own

harmonics = sp[preset_slice]

processed_harmonics = convolution(harmonics[None,None,...])

new_sp = sp.clone()
new_sp[preset_slice] = processed_harmonics[0,0]

In case of not using convolutions you can handle something similar with fold and unfold I woudl say