Comments (11)
Ordering of zeros and poles in output vectors doesn't matter (it's just a set of complex numbers).
Gain should also be the same (or, at least, very close to scipy's result). If the gain is very small, there may be some insignificant difference, but it's caused by round-off errors.
What input parameters did you specify (lower
, upper
, fs
)?
from nwaves.
Yes, scipy seems more precise. Maybe the calculation of the warped frequencies and the transformation into lowpass, bandpass, highpass, or bandstop are different?
Here some test code:
`var fs = 48000d;
var downsamplingFactor = 50;
var fsd = fs / downsamplingFactor;
var lower = 11.220184543019641;//calculated fractional-octave band
var upper = 14.125375446227549;
var bw = new Filters.Butterworth.BandPassFilter(lower / fsd, upper / fsd, 6);
var (z, p, k) = (bw.Tf.Zeros, bw.Tf.Poles, bw.Tf.Gain);
var tf = DesignFilter.TfToSos(bw.Tf);
var sosFilter = new FilterChain(tf);`
from nwaves.
The calculation is essentially the same (as far as I can judge from reading a sciPy codebase). But in your particular case the filter is very narrow, so round-off errors become an important factor. Actually, in sciPy the frequency response for your parameters is not good too:
from nwaves.
UPD: anyway, the filtering will be OK if you do it as below, using SOS:
var fs = 48000d;
var downsamplingFactor = 50;
var fsd = fs / downsamplingFactor;
var lower = 11.220184543019641;//calculated fractional-octave band
var upper = 14.125375446227549;
var filter = new Filters.Butterworth.BandPassFilter(lower / fsd, upper / fsd, 6);
var sos = DesignFilter.TfToSos(filter.Tf);
var sosFilter = new FilterChain(sos);
// 1) SOS will mitigate the numeric effects:
// 2) re-estimate gain (this isn't available in ver.0.9.4 yet, but it's in current codebase)
var gain = sosFilter.EstimateGain();
var filteredSignal = sosFilter.ApplyTo(_signal, gain);
from nwaves.
Good to know, I'll try the estimate gain solution.
But at the moment I'm stuck with the scipy 'y = filtfilt(num, den, x)' equivalent ZiFilter.ZeroPhase. It returns big differences. I think because of the pad type. Default in scipy is odd padding. NWaves has only zero padding...
from nwaves.
Oh ... I'm just beginning to understand. ZiFilter.ZeroPhase has an "implicit" odd padding, right? I'm trying to figure out where the big differences come from...
from nwaves.
I found one issue. In TransferFunction.Zi the 'zi' array length should be size - 1:
var zi = new double[size - 1];
from nwaves.
An other issue seems to be the padLength in ZiFilter.ZeroPhase. It should be:
padLength = 3 * Math.Max(_a.Length, _b.Length);
instead of:
padLength = 3 * (Math.Max(_a.Length, _b.Length) - 1);
from nwaves.
Yes, for some reason, sciPy filtfilt
default parameter is not compliant with MATLAB/NWaves filtfilt
.
In MATLAB/NWaves default padlen is 3 * (max(len(a), len(b)) - 1)
. If you need to achieve the same results in sciPy as in MATLAB/NWaves, specify this value explicitly. Example:
double[] num = {1, 0.2, 0.5, -0.6, 0.3};
double[] den = {1, -0.2, 0.4, 0.1};
var filter = new ZiFilter(num, den);
// ============== lfilter_zi(num, den): ==================
double[] zi = filter.Tf.Zi;
// ============== filtfilt(num, den, np.arange(20), padlen=3*(5-1)): ==================
var input = new DiscreteSignal(1, Enumerable.Range(0, 20));
var output = filter.ZeroPhase(input);
In MATLAB:
y = filtfilt([1 0.2 0.5 -0.6 0.3], [1 -0.2 0.4 0.1], 0:19)
In sciPy:
num = [1, 0.2, 0.5, -0.6, 0.3]
den = [1, -0.2, 0.4, 0.1]
x = np.arange(20)
zi = lfilter_zi(num, den)
# [ 0.07692308, -0.33846154, -0.40769231, 0.3]
# in NWaves: { 0.07692308, -0.33846154, -0.40769231, 0.3, 0 }
y = filtfilt(num, den, x, padlen=12) # 3* (max(len(num), len(den)) - 1)
PS. As for Zi
length, it's not an issue. One trailing element is added for convenience (in internal computations). Simply ignore the last element.
from nwaves.
One more comment on this: After many tests and some learning, I think that the inaccuracies arise because the gain (k) is not taken into account in the calculations with zeros and poles (z, p) in TransferFunction or DesignFilter.
Anyway ... NWaves is great for studying signal analysis, implementing math algorithms, OOP, and working with music audio. For general DSP and scientific use cases, further improvements are required (e.g. the z, p, k and the analog to digital filter transformations (lp to hp, bp, bs)).
Thank you for this library and your very good explanations! I hope you continue :-)
from nwaves.
Thank you for your kind words!
The gain takes part in computations (actually it's always reflected in TF numerator). The reasons for inaccuracies in this particular case is the specifics of your particularly narrow filter (MATLAB, sciPy and NWaves - all of them give different results for this filter parameters due to numeric errors). Just check out other filters (with wider passband) - you'll see NWaves/MATLAB/sciPy will produce equivalent results.
from nwaves.
Related Issues (20)
- Playing saved audio HOT 2
- FeatureExtractor ComputeFrom FastCopy bug HOT 3
- FIR Bandpass Resampling becomes unstable after a long duration HOT 9
- Is there method for series filter? or parallel filter? HOT 2
- How to obtain digital SOS filter from analog zeros and poles? HOT 1
- FFT compatible with OpenAI Whisper features HOT 1
- Help with realtime resampling HOT 3
- Analog poles and zeros of elliptic filter are different from scipy HOT 2
- How to use the polyphase filters implementation
- Buggy RLS filter implementation HOT 3
- how to use stft like scipy.signal "f, t, tf_data = signal.stft(wavedata, fs=fs, window='hamming', nperseg=N_fft, noverlap=int(N_fft*0.8))"? Now we cannot get f,t value. The tf_data is different from var spectrogram = stft.Spectrogram(discreteSignal, normalize: true). HOT 2
- Question: Pitch Patterns
- out of memory using Stft.Spectrogram function HOT 1
- WaveFile: Compiler Warning (level 2) CS0652 @ line 134
- PowerSpectrum and Magnitude spectrum missing from FFT64, RealFFT, RealFFT64
- Order of instruction wrong on wiki page HOT 1
- Pitch shifter produces garbled noise HOT 1
- python speech features fbanks HOT 4
- DiscreteSignal.Samples contain more samples than the original signal HOT 2
- Pitch.FromYin triggers exception for certain sample rates and pitch ranges HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nwaves.