The Python Scipy library provides several functions to downsample signals, but they all have limitations:

  • The resample function is based on Fourier method, which means it assumes periodic signals.
  • The resample_poly function assumes "values beyond the boundary of the signal to be zero."
  • The decimate function can only downsample signals by some integer factors, not to specific number of samples.
  • The upfirdn function requires FIR filter coefficients as inputs, which I am not sure how to get.

I have a signal that's NOT periodic and the values beyound the boundary of the signal are NOT zeros, and I want to downsample the singal from 611 samples to 100 samples.

Is there a simple way to do that in Python?


EDIT: The reason why I need to downsample signals to a fixed number of samples is that I have signals with different length, and I want to use those signals to train a 1D CNN for classification/regression tasks, which requires inputs of fixed size; I prefer not to use RNN/LSTM, although those models can accept inputs with various sizes.

  • 2
    $\begingroup$ Your signal need not be periodic or have values beyond the boundary that are zeros, this just means what the resample function used assumes IF your signal were to continue for infinite time, so in each case will have a different result at the boundaries due to that assumption. Unfortunately given your sampling ratios have no common factors you would need to interpolate by 100 and then decimate by 611 to achieve your result. Have you tried resample(x, 100, 611) and does it not achieve your desired result? $\endgroup$ Nov 28 '19 at 1:59
  • 1
    $\begingroup$ Just as @LamebrainEddy, I'm 99% sure that what you are trying to do is a bad idea! Please, avoid the XY Problem and tell us what you want to do in the bigger picture, and especially why you'd want to resample to a fixed number of samples. $\endgroup$ Nov 28 '19 at 6:54
  • $\begingroup$ @MarcusMüller I have signals with different length, and I want to use those signals to train a 1D CNN, which requires inputs of fixed size, so I need to downsample signals to a fixed number of samples. $\endgroup$
    – chaohuang
    Nov 28 '19 at 20:03
  • $\begingroup$ I also clarified this in the question. $\endgroup$
    – chaohuang
    Nov 28 '19 at 20:13
  • $\begingroup$ @chaohuang that doesn't justify resampling, at all. $\endgroup$ Nov 28 '19 at 21:13

I am doing something similar to your application with 1D CNN. I think scipy.resample_poly is the most versatile function since it allows both upsampling, downsampling, or a combination of both.

Also your comment about "values beyond the boundary of the signal to be zero" can be solved by using the option "line" in padtype, as shown in the function documentation, in order to eliminate spurious effects at the head/tail of the signal.

In general if the integer number of resampling factor is still an issue to you (but it shouldn't as you can play with the length of the signal) you can play with a combination of moving average followed by interpolation on the grid.


I'd consider why you really want to do this - I personally can't think of a reason why I'd want to downsample to a specific sample number but I don't know your project

Floating an alternate idea, you could downsample until you're near around that level of decimation and then truncate? It won't be 100 samples exactly but it might be easier in the long run to allow an error tolerance in where the signal ends

To give some aid in looking for a package - you are looking for something that will resample your signal using interpolation, not integer factors.

You could write one yourself with a bit of work. You will need to choose an interpolation function to go with it - I'd advise trying some out along with different truncated sinc functions and just seeing what works

  • $\begingroup$ Thanks. Please see my edit and comment for the reason why I need to downsample signals to a fixed number of samples. $\endgroup$
    – chaohuang
    Nov 28 '19 at 20:09
  • $\begingroup$ If you downsample signals to differing amount you have also changed the pitch of your signals differing amounts if you play them at the same rate. Not sure how this affects classification tasks but I would think that you don't want this at all. I recommend truncating signals where they end, then padding with zeros to make the full amount. Again not an expert on ML applications but I wouldnt think padding would be an issue $\endgroup$ Nov 28 '19 at 22:35

First, all of these routines act on an input array. Your comment "values beyond the boundary of the signal are NOT zeros" implies that you want to process a continuous signal, or at least one that is longer than a single call and array. If you want to use these routines, you’ll need some buffer management of your signal. Second, for converting 611 to 100, using these routines, you’d need to upsample by 100 and downsample by 611.

Since you’re looking for “a simple way”, I think you’ll want to research Python DSP libraries. I don’t use any, but I’m aware of this one, for instance: http://ajaxsoundstudio.com/software/pyo

But I'll elaborate on the integer factor issue. Converting rate by integer factors is easy to understand and implement—insert zeros to go up, discard samples to go down. DSP books often present this as the only option. But every sample in your source is an impulse. Filtering it with a linear phase FIR antialiasing filter produces a windowed sinc function. You can use the windowed sinc functions of all the necessary points anywhere you want. There is no need to do it on integer multiples or divisions of the sample period.


Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.