A Collection of Useful C++ Classes for Signal Processing
-
- KVRer
- 1 posts since 21 Jan, 2015
The elliptic filter design function takes "roll off" as a parameter. I can not figure out exactly how this is related to stop band attenuation. Most other elliptic design tools take stop band attenuation as an input.
I would like to do it this way as well. Can anyone tell me how to convert from stop band attenuation to in Db, pass band ripple in Db, and filter cutoff frequencies to "roll off" rate
I would like to do it this way as well. Can anyone tell me how to convert from stop band attenuation to in Db, pass band ripple in Db, and filter cutoff frequencies to "roll off" rate
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
Does this apply to other filters as well? It seems odd that should have fixed a problem, theolalp wrote:Hi all,
I just wanted to report a bug I found when using the following filter to do block processing of the data:I was getting a discontinuity at the boundary between buffers that had nothing to do with the data I was passing to it. By looking at it in more detail, I realized the filter was processing the second sample to whatever was in the adjacent memory location at the end of the array (it was off by one sample).Code: Select all
filter = new Dsp::FilterDesign <Dsp::Butterworth::Design::HighPass <MAXORDER>, 1 >;
The problem was caused by Cascade::process(int numSamples, Sample* dest, StateType& state) const.
Instead of the line:I modified it toCode: Select all
*dest++ = state.process (*dest, *this);And that fixed it.Code: Select all
*dest = state.process (*dest, *this); ++dest;
Code: Select all
++dest;It's unfortunate that the author has been dark since 2013; not only here but the repository on github and his own website.
- KVRian
- 804 posts since 25 Apr, 2011
I believe that C++ doesn't specify the order of evaluation of the left-hand and right-hand terms in an assignment.
In the original code you modified, one compiler might first evaluate the rhs using the current value of dest, then store the result in dest, then increment dest (presumably what the author intended) - but another compiler might store the current value of dest in a temporary, then increment dest, then evaluate the rhs using the (now incremented) value, then store the result using the original value of dest.
Your modification avoids the ambiguity.
In the original code you modified, one compiler might first evaluate the rhs using the current value of dest, then store the result in dest, then increment dest (presumably what the author intended) - but another compiler might store the current value of dest in a temporary, then increment dest, then evaluate the rhs using the (now incremented) value, then store the result using the original value of dest.
Your modification avoids the ambiguity.
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
I believe a lot of code would break if the pointer increment of "*foo++" was applied before modifying the content. This is what I see in a disassembly window before the loop continuation of the function in question. dest is fetched, the result stuffed in it and the ptr incremented. So, again I ask what compiler was used to get the bad results.kryptonaut wrote:I believe that C++ doesn't specify the order of evaluation of the left-hand and right-hand terms in an assignment.
Code: Select all
mov rax,qword ptr [dest]
movsd mmword ptr [rax],xmm0
mov rax,qword ptr [dest]
add rax,8
mov qword ptr [dest],rax
- KVRAF
- 12615 posts since 7 Dec, 2004
http://en.cppreference.com/w/c/language ... precedence
If you read the actual spec you will see that the precedence is very strictly specified. There are no variations like this in critical areas like this, do you think the spec is designed by a group of fools?
*x++ = value;
This breaks down like this:
((*(x++)) = (value));
So, first (value) is computed.
Secondly, x++ is applied, as this is post-fix it first returns the existing value (x) then increments the value in memory. The result is that the dereferencing *() applies to the original value of (x), not (x + 1).
Next, the pointer is dereferenced.
Lastly, the assignment operator is applied, moving (value) into (*x).
So, this is equivalent to:
data = (value);
reference = (*x);
reference = data;
x = (x + 1);
In all compilers, all the time, everywhere. (Unless they're broken.)
If you read the actual spec you will see that the precedence is very strictly specified. There are no variations like this in critical areas like this, do you think the spec is designed by a group of fools?
*x++ = value;
This breaks down like this:
((*(x++)) = (value));
So, first (value) is computed.
Secondly, x++ is applied, as this is post-fix it first returns the existing value (x) then increments the value in memory. The result is that the dereferencing *() applies to the original value of (x), not (x + 1).
Next, the pointer is dereferenced.
Lastly, the assignment operator is applied, moving (value) into (*x).
So, this is equivalent to:
data = (value);
reference = (*x);
reference = data;
x = (x + 1);
In all compilers, all the time, everywhere. (Unless they're broken.)
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
@aciddose Yes, order and precedence are very strict in C/C++ in most cases.
However, this reminded me of an old problem I had moving some code between platforms. And I now see the problem. There are cases where some things can be compiler specific. In this case its the order in which arguments to functions or operators are evaluated. The code works fine compiled by the Microsoft compiler but it won't evaluate the same in all compilers. If someone compiled this with say GCC for ARM/Android, they would get the exact error the original poster described. This is because "dest" is used on both sides of the = and as a parameter to a function, and each compiler can evaluate left to right or right to left as it pleases.
Modifying a variable of a built-in type and using that variable in the same expression is undefined behavior.
So, the OP was correct. I was wrong and this is a bug. You just might get lucky as I did depending on the compiler used. The source should be fixed. The code is in at least 2 places.
However, this reminded me of an old problem I had moving some code between platforms. And I now see the problem. There are cases where some things can be compiler specific. In this case its the order in which arguments to functions or operators are evaluated. The code works fine compiled by the Microsoft compiler but it won't evaluate the same in all compilers. If someone compiled this with say GCC for ARM/Android, they would get the exact error the original poster described. This is because "dest" is used on both sides of the = and as a parameter to a function, and each compiler can evaluate left to right or right to left as it pleases.
Modifying a variable of a built-in type and using that variable in the same expression is undefined behavior.
So, the OP was correct. I was wrong and this is a bug. You just might get lucky as I did depending on the compiler used. The source should be fixed. The code is in at least 2 places.
- KVRAF
- 12615 posts since 7 Dec, 2004
Ah right, you're correct about reusing the same value on both sides of the assignment or both sides of any operator.
Normally operators should work left-to-right, except for a few including assignment.
So the pointer should be dereferenced first in most compilers, the function called, then the pointer dereferenced on the left of the assignment and the value assigned.
I'm surprised though that C doesn't specify this.
*dest++ = state.process(*dest, *this);
In this case both dereferences of dest should provide the same value, but you're saying the one inside the function brackets returns the incremented value for some compilers?
So in that case the assignment operator is using left-to-right rather than right-to-left order.
Normally operators should work left-to-right, except for a few including assignment.
So the pointer should be dereferenced first in most compilers, the function called, then the pointer dereferenced on the left of the assignment and the value assigned.
I'm surprised though that C doesn't specify this.
*dest++ = state.process(*dest, *this);
In this case both dereferences of dest should provide the same value, but you're saying the one inside the function brackets returns the incremented value for some compilers?
So in that case the assignment operator is using left-to-right rather than right-to-left order.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
- KVRAF
- 12615 posts since 7 Dec, 2004
A good way to look at these issues is to replace all operators with function calls, for example:
assign(dereference(postfix_increment(dest)), state.process(dereference(dest), dereference(this)));
Of course I'm ignoring the comma operator here... I'm not sure if the comma operator is applied to parameters in a function call though, I do not believe it is?
So if everything is processing from left-to-right in this line the second dereference of dest will already be incremented.
I believe the same issue occurs in this example without division by the assignment operator:
x = x + sum_squares(x, x++, x--);
So there is absolutely no way to know what the result of this line will be.
With:
x = 1
Possible results:
x = 1 + (1 + 1 + 1) = 4
x = 1 + (1 + 0 + 1) = 3
x = 1 + (1 + 1 + 4) = 7
assign(dereference(postfix_increment(dest)), state.process(dereference(dest), dereference(this)));
Of course I'm ignoring the comma operator here... I'm not sure if the comma operator is applied to parameters in a function call though, I do not believe it is?
So if everything is processing from left-to-right in this line the second dereference of dest will already be incremented.
I believe the same issue occurs in this example without division by the assignment operator:
x = x + sum_squares(x, x++, x--);
So there is absolutely no way to know what the result of this line will be.
With:
x = 1
Possible results:
x = 1 + (1 + 1 + 1) = 4
x = 1 + (1 + 0 + 1) = 3
x = 1 + (1 + 1 + 4) = 7
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
- KVRAF
- 12615 posts since 7 Dec, 2004
The linked article from a few posts above starts off with this:
Never call functions with consequences (modify external data or object members) as parameters to a function if there is any possibility of interaction between calls.
Since as I said you can replace operators with functions this rule applies absolutely everywhere.
So the only place you can call a function knowing the order of execution is when it is completely isolated from all other function calls with side-effects.
So in other words never do that.There is no concept of left-to-right or right-to-left evaluation in C++, which is not to be confused with left-to-right and right-to-left associativity of operators: the expression f1() + f2() + f3() is parsed as (f1() + f2()) + f3() due to left-to-right associativity of operator+, but the function call to f3 may be evaluated first, last, or between f1() or f2() at run time.
Never call functions with consequences (modify external data or object members) as parameters to a function if there is any possibility of interaction between calls.
Since as I said you can replace operators with functions this rule applies absolutely everywhere.
So the only place you can call a function knowing the order of execution is when it is completely isolated from all other function calls with side-effects.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
I believe that a compiler can also evaluate the arguments to a function in any order which is a slightly different issue but can also easily get one into trouble if any order dependency is assumed.
olalp's fix of just moving the increment to the next line is good. either dest++ or ++dest (with brackets around the 2 lines).
olalp's fix of just moving the increment to the next line is good. either dest++ or ++dest (with brackets around the 2 lines).
-
- KVRian
- 653 posts since 4 Apr, 2010
I think you're still referring to this?ChocoBilly wrote:Modifying a variable of a built-in type and using that variable in the same expression is undefined behavior.
So, the OP was correct. I was wrong and this is a bug. You just might get lucky as I did depending on the compiler used. The source should be fixed. The code is in at least 2 places.
Code: Select all
*dest++ = state.process (*dest, *this);Code: Select all
x = *source + *source++; // this is undefinedMy audio DSP blog: earlevel.com
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
It's not "*dest++" that's in question. You can Google the issue and see that what we're referring to is up to the compiler when "*dest" is evaluated. You cannot assume left to right. Using "*dest" on both sides and relying on the order is undefined.
-
- KVRian
- 653 posts since 4 Apr, 2010
I wish you could be more specific than "google the issue" (google what? clearly, I don't understand what the issue is if you have to tell me—sorry, but I don't want this to be my "Saturday project"). "Evaluation" is of the expression—sure you can't rely on on order of evaluation, but the expression is "state.process (*dest, *this)", so I don't see any ambiguity with evaluation order.ChocoBilly wrote:It's not "*dest++" that's in question. You can Google the issue and see that what we're referring to is up to the compiler when "*dest" is evaluated. You cannot assume left to right. Using "*dest" on both sides and relying on the order is undefined.
Again, I may be misunderstanding you, but you say 'when "dest" is evaluated'. But dest is a variable, and you said that 'It's not "*dest++: that's in question', and if not, I don't see any potential for a problem. I'm sure that you must mean at least "when "*dest" is evaluated', but without the "++" nothing changes and there is no danger of their being ambiguity.
Sorry, I just see the compiler being asked to "pass values that 'dest' and 'this' point to, to the function state.process; set the location pointed to by 'dest', to the result returned by the function, then increment 'dest'". What happens to dest on the left side of the "=" can't affect "dest" on the right dies. Please explain what I'm missing.
My audio DSP blog: earlevel.com
- KVRAF
- 12615 posts since 7 Dec, 2004
Yes, the assignment operator does not divide the "expression", the entire expression is the expression including the assignment.
For example:
y++ = (x++ = (y++ = x++) * x++ * y++);
See my post about replacing operators with functions.
For example:
y++ = (x++ = (y++ = x++) * x++ * y++);
See my post about replacing operators with functions.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
- KVRian
- 653 posts since 4 Apr, 2010
Sure, you've made a nonsense statement here, nothing like the one we're talking about. It's easy to say why the above is ambiguous for a compiler (both the right and left side are ambiguous). Now tell me exactly why the statement in question (*dest++ = ...) is ambiguous for the compiler. Don't point me to google, just explain how a compiler would fall down interpreting that. Really, the C language is not so fragile as to not understand how to evaluate this.aciddose wrote:Yes, the assignment operator does not divide the "expression", the entire expression is the expression including the assignment.
For example:
y++ = (x++ = (y++ = x++) * x++ * y++);
See my post about replacing operators with functions.
I believe that you are missing the difference between a statement and an expression, in interpreting the issue of expression evaluation. The expression on the right side of the equals sign is always evaluated before assigning to the left side. Always. In fact, nothing should be allowed by a compiler on the left side of the "=" that could be a problem (look up "lval" and "rval").
My audio DSP blog: earlevel.com
