GithubHelp home page GithubHelp logo

Comments (9)

ADH-LukeBollam avatar ADH-LukeBollam commented on September 27, 2024 1

@ar1st0crat
Just a reminder that theres a bug in resampler where if you pass in a filter to the Resample method, it doesn't get used.

if (g < 1 && filter is null)
{
filter = new FirFilter(DesignFilter.FirWinLp(MinResamplingFilterOrder, g / 2));
input = filter.ApplyTo(signal).Samples;
}

There is no else condition to use a provided filter if it is not null.

from nwaves.

ADH-LukeBollam avatar ADH-LukeBollam commented on September 27, 2024

Just a small update, it turns out the signal quality degrades constantly over time. Even before 36 hours, the signal is starting to look more 'square' compared to at the beginning. Is this an error accumulating and eventually overflowing perhaps?

from nwaves.

ADH-LukeBollam avatar ADH-LukeBollam commented on September 27, 2024

The fix for me at the moment is to reset the filter after short sections of data with lpFilter.Reset(); but it does cause some aliasing at each boundary. Do you know if you'll have a chance to take a look at this @ar1st0crat ?

from nwaves.

ar1st0crat avatar ar1st0crat commented on September 27, 2024

Hi!
Thank you for the kind words about the library :-)
Unfortunately, at the moment I don't have much time for reviewing issues regarding NWaves.
Anyway, from what I see already, you're using high-pass filter in resampling operation. The purpose of FIR filter in resampling methods is antialising, so it must be a low-pass filter (with the cut-off frequency 0.5 / resample_factor). If you need to remove the baseline wander, then you should apply your highpass filter separately. Currently, you're applying the high-pass filter. (In NWaves cut-off frequency 0.5 is equivalent to 1.0 in sciPy/MATLAB). So, esentially you filter is HP, although you're constructing it as BP.

Hence, there are two options:

// 1) solution similar to yours:

// the filter will be essentially LP (although, technically it's BP):
var lowCutoff = 0.5 / newSr;   // high pass to remove baseline wander
var highCutoff = 0.5 / 3;   // 3 because greatest_common_divisor(128, 192) = 3
var filterOrder = 11;

var resampler = new Resampler();
var lpFilter = new FirFilter(DesignFilter.FirWinBp(filterOrder, lowCutoff, highCutoff)); 
var resampled = resampler.Resample(new NWaves.Signals.DiscreteSignal(oldSr, data), newSr, lpFilter);
return resampled.Samples;

// 2) slighly-less efficient, but more readable

var cutoff = 0.5 / newSr;   // high pass to remove baseline wander
var filterOrder = 11;

// filter to remove baseline wander, first:
var hpFilter = new FirFilter(DesignFilter.FirWinHp(filterOrder, cutoff)); 
var filtered = hpFilter.ApplyTo(new NWaves.Signals.DiscreteSignal(oldSr, data));

var resampler = new Resampler();

// resampling antialiasing LP filter will be constructed automatically inside Resample() function:
var resampled = resampler.Resample(filtered, newSr);

return resampled.Samples;

PS. Btw, is filter order=11 OK? Perhaps, it's too small. You can try bigger values. Like 101 for example. Filtering will be automatically be carried out via block convolution, so it's going to be quite fast.

from nwaves.

ADH-LukeBollam avatar ADH-LukeBollam commented on September 27, 2024

I just noticed, if you pass in a filter it doesn't actually get used at all which is probably why I was getting such bad aliasing

if (g < 1 && filter is null)

The if's need to be split up into something like:

if (g < 1)
{
	if (filter == null)
	{
		filter = new FirFilter(DesignFilter.FirWinLp(MinResamplingFilterOrder, g / 2));
	}

	input = filter.ApplyTo(signal).Samples;
}

otherwise the low pass filter you pass in won't be used.

from nwaves.

ar1st0crat avatar ar1st0crat commented on September 27, 2024

No, AFAIR, filtering is not needed for band-limited upsampling, so my code is correct.
I've just noticed - you're calling Resample() method. This method implements the so called band-limited resampling. It's quite slow and intended to be used for "complicated" resamplings (like 44.1kHz to 16 kHz, for example). In your case (128 -> 192) you have upsampling factor 3 and downsampling factor 2, so I would recommend calling ResampleUpDown():

// 1)
var lowCutoff = 0.5 / newSr;   // high pass to remove baseline wander
var highCutoff = 0.5 / 3;   // 3 because greatest_common_divisor(128, 192) = 3

var filterOrder = 99;
var filter = new FirFilter(DesignFilter.FirWinBp(filterOrder, lowCutoff, highCutoff)); 

var resampler = new Resampler();
var resampled = resampler.ResampleUpDown(new NWaves.Signals.DiscreteSignal(oldSr, data), 3, 2, filter);
return resampled.Samples;


// 2) this is the most correct version (but it will create intermediate HP-filtered signal):

var cutoff = 0.5 / newSr;   // high pass to remove baseline wander
var filterOrder = 11;

// filter to remove baseline wander, first:
var hpFilter = new FirFilter(DesignFilter.FirWinHp(filterOrder, cutoff)); 
var filtered = hpFilter.ApplyTo(new NWaves.Signals.DiscreteSignal(oldSr, data));

var resampler = new Resampler();

// resampling antialiasing LP filter will be constructed automatically inside ResampleUpDown() function:
var resampled = resampler.ResampleUpDown(filtered, 3, 2);

return resampled.Samples;

from nwaves.

ADH-LukeBollam avatar ADH-LukeBollam commented on September 27, 2024

This is just one example, my input data sample rate varies and often the resample ratio is not a nice integer, like 200=>192, 250=>192 etc.

The code for Resample() is still not working correctly if downsampling though right? If you pass in a filter yourself, it won't be used even in the case of downsampling, because it checks if the filter is null to do the filtering step.

from nwaves.

ar1st0crat avatar ar1st0crat commented on September 27, 2024

Yes, you're right. I remember about this issue and I keep it open. I wanted to revise the entire resampling part of NWaves, but unfortunately at the moment I have no time for it.

from nwaves.

ADH-LukeBollam avatar ADH-LukeBollam commented on September 27, 2024

I've figured out the source of the noise, its actually caused by poor floating point precision at large values here:

var x = n * step;

It's especially bad in my case because signal values are small, so the lack of precision is relatively quite large.
I fixed it by changing the resample code to

// eliminate any floating point quantization errors for very large sample counts
decimal step = 1 / (decimal)g;

for (var n = 0; n < output.Length; n++)
{
	var x = n * step;

	for (var i = -order; i < order; i++)
	{
		var j = (int)Math.Floor(x) - i;

		if (j < 0 || j >= input.Length)
		{
			continue;
		}

		var t = (double)(x - j); // at this point we are back to a small scale, safe to return to double type

from nwaves.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.