A Collection of Useful C++ Classes for Signal Processing
-
- KVRian
- 1096 posts since 28 May, 2010 from Finland
Pfft,
There's this one fork in Github: https://github.com/gerasim13/DSPFilters/
At least someone has improved it.
It would be worth fixing the library, because it's good one.
I'm willing to fix the part that's complicating my own program, because I have to get it to work, but have to brush up some C++ knowledge.
There's this one fork in Github: https://github.com/gerasim13/DSPFilters/
At least someone has improved it.
It would be worth fixing the library, because it's good one.
I'm willing to fix the part that's complicating my own program, because I have to get it to work, but have to brush up some C++ knowledge.
-
- KVRian
- 1265 posts since 9 Sep, 2005 from Oulu, Finland
Hmm, interesting, I haven't seen this fork before. I guess it's worth trying to see how this works.Fluky wrote:Pfft,
There's this one fork in Github: https://github.com/gerasim13/DSPFilters/
At least someone has improved it.
-
antonyomusabini antonyomusabini https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=363267
- KVRer
- 1 posts since 21 Jul, 2015
AUTO-ADMIN: Non-MP3, WAV, OGG, SoundCloud, YouTube, Vimeo, Twitter and Facebook links in this post have been protected automatically. Once the member reaches 5 posts the links will function as normal.
Hi everyone,I am trying to implement the Vinnie Falcao's DSP Filters into a robotic platform.
I need real time processing, so I filter data by chunk-by-chunk.
When I use a 1st order Butterworth filter, the last value of the input chunk is not correctly filtered. (while filtering with higher orders I didn't have this error).
Here is a simple code to reproduce the same error :
Code: Select all (#)
std::vector<double> chunk(10,50); // an example of input chunk
double* audioData[1];
audioData[0] = chunk.data(); // my double* is now considered as constant
Dsp::FilterDesign
<Dsp::Butterworth::Design::LowPass <1>, 1 > f; // 1st order, 1 channel, lowpass
Dsp::Params params;
params[0] = 44100; // sample rate
params[1] = 1; // order
params[2] = 1000; // cutoff frequency
f.setParams (params);
f.process (chunk.size(), audioData);
It should be : 3.33029 9.54723 14.936 19.6069 23.6556 27.165 30.2069 32.8436 35.129 37.11
As a result, the next chunk is not filtered correctly neither.
Does anybody have already faced with this problem, or am I missing something ?
Thank you in advance for your answers.
Antonyo Musabini
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
The thing is that you inherit the original design if you want to keep compatibility. And I'd rather develop my own toolkit (with its own advantages and also drawbacks, of course, everything is a matter of compromise) than trying to understand someone else's. Which is what I did.Fluky wrote:It would be worth fixing the library, because it's good one.
-
- KVRian
- 1096 posts since 28 May, 2010 from Finland
So you're working on a library that might replace this one in the future?Miles1981 wrote:The thing is that you inherit the original design if you want to keep compatibility. And I'd rather develop my own toolkit (with its own advantages and also drawbacks, of course, everything is a matter of compromise) than trying to understand someone else's. Which is what I did.Fluky wrote:It would be worth fixing the library, because it's good one.
And you claim that your architecture is better?
Does it have parameter smoothing already similar to DSPFilters?
I could probably implement the BandShelf faster by writing my own SmoothFilterDesign class, but since the DSPFilters has so much in it already, it would be a shame to leave it that way. Unless its designs can be easily transformed to another attempt at a similar library.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
No, I don't have parameter smoothing (I guess you are refering to the class you were trying to use?), but it is straightforward to implement something like that in Audio Toolkit. You just need to implement a crossover as the summation filter. I may implement it if there is a need for it.
And yes, I think my library can easily replace DSPFilter. But the design is completely different.
And yes, I think my library can easily replace DSPFilter. But the design is completely different.
-
- KVRian
- 1096 posts since 28 May, 2010 from Finland
Well. Since I'm in need of a parameter smoothing Butterworth band shelf, then can you implement those in AudioTK?
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
I'll have to check... If I understand what you want, it's that when a parameter changes in the filter, the effects are smoothed over some samples? Could be achieved with the TimeVarying IIR (it precomputes a set of coeffs if the frequency changes), but it's not straightforward (so that the whole sets of parameters are not recomputed each time and so that the state is not reseted after each change).
-
- KVRian
- 1096 posts since 28 May, 2010 from Finland
Yes. And the implementation of Dsp:SmoothFilterDesign is a good one, there you can set the amount of samples that you want it to transition over. I don't know how it works though.Miles1981 wrote:I'll have to check... If I understand what you want, it's that when a parameter changes in the filter, the effects are smoothed over some samples?
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
Well, it's quite crude and slow, but it works: https://github.com/gerasim13/DSPFilters ... edFilter.h
My design doesn't allow me to do exactly the same, but ideally it can be done if you want to recompute all coefficients each time (which is quite time consuming, as there is at least one tan() function inside!). But I need to think carefully about how to do this efficiently without having to rewrite all the coefficients computations.
My design doesn't allow me to do exactly the same, but ideally it can be done if you want to recompute all coefficients each time (which is quite time consuming, as there is at least one tan() function inside!). But I need to think carefully about how to do this efficiently without having to rewrite all the coefficients computations.
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
I don't use the filters for real time processing, so I can't speak from experience. However, I just rebuilt and ran DSPFiltersDemo. I set it to the 440 Hz sine wave and lower cutoffs. If there was an error there would be noticeable pops in the output but it played smoothly.antonyomusabini wrote: When I use a 1st order Butterworth filter, the last value of the input chunk is not correctly filtered. (while filtering with higher orders I didn't have this error).
What compiler are you using and platform are you building for?
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
Since DSPFiltersDemo compiles and works, I think that would be a good start. From what I can determine looking at MainPanel.cpp, it appears that the "Smooth" filters want 2 filters, the current filter and the filter you are transitioning to and the number of samples to transition over. It creates a new filter and copies params[] over intelligently in the setup.Fluky wrote:Yes. And the implementation of Dsp:SmoothFilterDesign is a good one, there you can set the amount of samples that you want it to transition over. I don't know how it works though.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
The SmoothFilter only wants one filter, not two. It can work for this library this way because all the coefficients are set via a vector and not by name. Doing so in ATK would be overkill...
So there are two solutions for you at the moment if you want to switch to ATK:
- use the TimeVaryingIIRFilters and feed in a new vector with the frequency you want to filter. Unfortunatelt, there are not as many filter designs for this one as there are for the usual IIRFilter. The good side is that it is in direct form 2
- use the IIRFilter and make the transition yourself, at the level of the pipeline. It's not reusable and IIRFilter is not DirectForm2 (but it is easy to implement a new one that is and then reuse the coefficient computation classes).
Option 2 would close to this (just use a InPointer and OutPointer as in the ATK plugins):
Haven't tested it, but something like that would do the trick.
So there are two solutions for you at the moment if you want to switch to ATK:
- use the TimeVaryingIIRFilters and feed in a new vector with the frequency you want to filter. Unfortunatelt, there are not as many filter designs for this one as there are for the usual IIRFilter. The good side is that it is in direct form 2
- use the IIRFilter and make the transition yourself, at the level of the pipeline. It's not reusable and IIRFilter is not DirectForm2 (but it is easy to implement a new one that is and then reuse the coefficient computation classes).
Option 2 would close to this (just use a InPointer and OutPointer as in the ATK plugins):
Code: Select all
ATK::SinusGeneratorFilter<double> generator;
generator.set_output_sampling_rate(1024*64);
generator.set_amplitude(1);
generator.set_frequency(100);
ATK::IIRFilter<ATK::BesselLowPassCoefficients<double> > filter;
filter.set_input_sampling_rate(1024*64);
filter.set_output_sampling_rate(1024*64);
filter.set_cut_frequency(100);
filter.set_order(3);
void process(int64_t size)
{
// let's say that I want to change the cut_frequency to new_cut_frequency
// For this, I set this variable as well as old_cut_frequency (former cut_frequency) and remaining_transition_samples to 1024
// I'll process new samples by chunks of 32 elements
// I should do something more clever to also track how many of the 32 samples were processed last time
int processing_samples = std::min (remaining_transition_samples, size);
if (processing_samples > 0)
{
double taper = (new_cut_frequency - old_cut_frequency) * 32. / remaining_transition_samples;
for(int i = 0; i < processing_samples; i += 32)
{
filter->set_cut_frequency(i/32 * taper + old_cut_frequency)
filter->process(std::min(32, processing_samples - i));
}
remaining_transition_samples -= processing_samples;
old_cut_frequency = filter->get_cut_frequency();
}
if(remaining_transition_samples = 0)
{
remaining_transition_samples = -1;
filter->set_cut_frequency(new_cut_frequency);
}
if(processing_samples < size)
{
filter->process(size - processing_samples);
}
}
-
- KVRian
- 1096 posts since 28 May, 2010 from Finland
I think I might switch to ATK, but can you get the Butterworth BandShelf there as well?Miles1981 wrote:The SmoothFilter only wants one filter, not two. It can work for this library this way because all the coefficients are set via a vector and not by name. Doing so in ATK would be overkill...
So there are two solutions for you at the moment if you want to switch to ATK:
- use the TimeVaryingIIRFilters and feed in a new vector with the frequency you want to filter. Unfortunatelt, there are not as many filter designs for this one as there are for the usual IIRFilter. The good side is that it is in direct form 2
- use the IIRFilter and make the transition yourself, at the level of the pipeline. It's not reusable and IIRFilter is not DirectForm2 (but it is easy to implement a new one that is and then reuse the coefficient computation classes).
Option 2 would close to this (just use a InPointer and OutPointer as in the ATK plugins):
Haven't tested it, but something like that would do the trick.Code: Select all
ATK::SinusGeneratorFilter<double> generator; generator.set_output_sampling_rate(1024*64); generator.set_amplitude(1); generator.set_frequency(100); ATK::IIRFilter<ATK::BesselLowPassCoefficients<double> > filter; filter.set_input_sampling_rate(1024*64); filter.set_output_sampling_rate(1024*64); filter.set_cut_frequency(100); filter.set_order(3); void process(int64_t size) { // let's say that I want to change the cut_frequency to new_cut_frequency // For this, I set this variable as well as old_cut_frequency (former cut_frequency) and remaining_transition_samples to 1024 // I'll process new samples by chunks of 32 elements // I should do something more clever to also track how many of the 32 samples were processed last time int processing_samples = std::min (remaining_transition_samples, size); if (processing_samples > 0) { double taper = (new_cut_frequency - old_cut_frequency) * 32. / remaining_transition_samples; for(int i = 0; i < processing_samples; i += 32) { filter->set_cut_frequency(i/32 * taper + old_cut_frequency) filter->process(std::min(32, processing_samples - i)); } remaining_transition_samples -= processing_samples; old_cut_frequency = filter->get_cut_frequency(); } if(remaining_transition_samples = 0) { remaining_transition_samples = -1; filter->set_cut_frequency(new_cut_frequency); } if(processing_samples < size) { filter->process(size - processing_samples); } }
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
I didn't try the bandshelf :/ I had the equations for the usual low pass, high pass, band pass and band stop. I'll have to check for the band shelf (more or less just add a fraction of the input!).
As I've said, the current IIRFilter is not Direct Form 2, so there is also some work that I can there. Let me check tonight (I first have to fix my side chain compressor uploads...) if I can make something.
As I've said, the current IIRFilter is not Direct Form 2, so there is also some work that I can there. Let me check tonight (I first have to fix my side chain compressor uploads...) if I can make something.