I found my results of my testing of the 48 bit IIR's. This example is an IIR filter of many ten's of order. All measurements were from a digital loopback with full accuracy (full 24 bits resolution with no operating system issues). No analog at all.
The Noise level is:
Here's the THD:
The 48 bit filter shows basically no harmonic distortions. The noise margin is +10dB for the 48 bit.
But both 32 bit and 48 bit are quite good.
Edit: to highlight differences.
"HighEnd Audio" IIR filters

 Respected Member
 Posts: 283
 Joined: Fri Mar 19, 2010 4:49 am
You do not have the required permissions to view the files attached to this post.
Last edited by bearcat on Sun May 13, 2012 2:05 am, edited 2 times in total.

 Respected Member
 Posts: 283
 Joined: Fri Mar 19, 2010 4:49 am
My code performs no sign testing.

 XCore Expert
 Posts: 844
 Joined: Sun Jul 11, 2010 1:31 am
You can calculate everything as unsigned always, by biasing alllilltroll wrote:Bearcat, do you use 2comp. longmult or do test the sign and then branch to unsigned longmult ?
numbers (by 0x8000_0000_0000_0000). You'll end up with an
accumulator that is biased by some constant number (because
your filter coefficients are fixed), so just add its negative at the
end. You can totally ignore overflow, all of this is integer after
all :)

 Respected Member
 Posts: 283
 Joined: Fri Mar 19, 2010 4:49 am
I do plan on using the 48bit filters for subwoofer processing and crossovers, unlike the application shown above which I had written the filter for. Limit cycles are certainly an issue down there. I plan on performing similiar measurements in the future when I actually use the 48 bit version.

 XCore Expert
 Posts: 956
 Joined: Fri Dec 11, 2009 3:53 am
 Location: Sweden, Eskilstuna
Do you mean like this ?segher wrote:You can calculate everything as unsigned always, by biasing alllilltroll wrote:Bearcat, do you use 2comp. longmult or do test the sign and then branch to unsigned longmult ?
numbers (by 0x8000_0000_0000_0000). You'll end up with an
accumulator that is biased by some constant number (because
your filter coefficients are fixed), so just add its negative at the
end. You can totally ignore overflow, all of this is integer after
all :)
int64y(n) is the signal
int32A is the signed filter coeff that is only changed every now and then, but not every sample
k=0x8000_0000_0000_0000 is the offset
hi:mi:lo is the result as a int96
If(A>=0)
offset= k*A is precalculated when the filter coef. is updated
(y(n)+k)*A + offset = A*y(n)+k*A  k*A = A*y(n)
end
if(A<0)
offset = k*A is precalculated when the filter coef. is updated
(y(n)+k)*(A) + offset = A*y(n)  k*A+k*A=(A*y(n))
end

 XCore Expert
 Posts: 844
 Joined: Sun Jul 11, 2010 1:31 am
Yes, something like that. It saves instructions because the correction
it has to do at the end is always the same, not dependent on the sign
bit of things; so a) it does not have to calculate with the sign bits, and
b) some expressions can be combined in the end.
Even easier of course is to use the MACCUS instruction, which
unfortunately does not exist ;)
it has to do at the end is always the same, not dependent on the sign
bit of things; so a) it does not have to calculate with the sign bits, and
b) some expressions can be combined in the end.
Even easier of course is to use the MACCUS instruction, which
unfortunately does not exist ;)

 XCore Expert
 Posts: 956
 Joined: Fri Dec 11, 2009 3:53 am
 Location: Sweden, Eskilstuna
ASMmaster segher, I might need some helt with negative coeffs.segher wrote:Yes, something like that. It saves instructions because the correction
it has to do at the end is always the same, not dependent on the sign
bit of things; so a) it does not have to calculate with the sign bits, and
b) some expressions can be combined in the end.
The 96bit result exists in hi:mi:lo
Even easier of course is to use the MACCUS instruction, which
unfortunately does not exist ;)
For positive coeffs, you can do it like this, and with only one coef. A as in this example, the Offset Ohi:Omi can be prenegated and replace the zero's in the lmul avoiding the lsub in the end.
Insignal: Yhi:Ylo
Coeff: A
Result: hi:mi:lo
Code: Select all
POS:
lmul Ohi,Omi,A,offset,zero,zero // Calculate the offset
POSloop:
add Yhi,Yhi,offset //add offset to insignal
lmul carry, lo, Ylo, A, zero, zero
lmul hi, mi, Yhi, A, zero, carry
//Calc 2comp. value by subtracting the offset.
lsub borrow,hi,hi,Ohi,zero
lsub s0,mi,mi,Omi,borrow
sub lo,lo,borrow
Code: Select all
NEG:
lmul Ohi,Omi,A,offset,zero,zero
NEGloop:
add Yhi,Yhi,offset //add offset to insignal
lmul carry, lo, Ylo, A, zero, zero
lmul hi, mi, Yhi, A, zero, carry
//Calc 2comp.
lsub borrow,hi,Ohi,hi,zero
lsub borrow,mi,Omi,mi,borrow
sub lo,lo,borrow
//negate hi:mi:lo
not hi,hi
not mi,mi
neg lo,lo

 XCore Expert
 Posts: 844
 Joined: Sun Jul 11, 2010 1:31 am
Your "negate" at the end is incorrect, it does not carry.
You're doing Oxx, and then negating it; you can just do xOx
instead.
If you do things right, there is no difference whatsoever between
positive and negative numbers, which is the point. By adding the
offset, you're shifting the [80000000..7fffffff] range to [0..ffffffff],
which is much nicer to compute with. Say for example you are
jut doing a*b, and write D=80000000, then you instead compute
(a+D)*(b+D) which is a*b+(a+b+D)*D, so you get a*b by subtracting
the right side of that (which is cheaper than it looks!)
Nothing in there is dependent on sign, it works exactly the same for
positive and negative numbers, which is the point :)
You're doing Oxx, and then negating it; you can just do xOx
instead.
If you do things right, there is no difference whatsoever between
positive and negative numbers, which is the point. By adding the
offset, you're shifting the [80000000..7fffffff] range to [0..ffffffff],
which is much nicer to compute with. Say for example you are
jut doing a*b, and write D=80000000, then you instead compute
(a+D)*(b+D) which is a*b+(a+b+D)*D, so you get a*b by subtracting
the right side of that (which is cheaper than it looks!)
Nothing in there is dependent on sign, it works exactly the same for
positive and negative numbers, which is the point :)

 XCore Expert
 Posts: 956
 Joined: Fri Dec 11, 2009 3:53 am
 Location: Sweden, Eskilstuna
If you look at the expression above, "Oxx" is correct, the incorrect thing is the order of lsub together with the borrow.
I believe this has a chance of beeing correct, and it is "Oxx" all the way.
Thank's anyway
I believe this has a chance of beeing correct, and it is "Oxx" all the way.
Code: Select all
NEGloop:
add Yhi,Yhi,offset //add offset to insignal
lmul s0, s2, Ylo, A, zero, zero
lmul hi, mi, Yhi, A, zero, s0
lsub s0,lo,zero,s2,zero
lsub s0,mi,Omi,mi,s0
lsub s0,hi,Ohi,hi,s0

 XCore Expert
 Posts: 956
 Joined: Fri Dec 11, 2009 3:53 am
 Location: Sweden, Eskilstuna
The thing is that multiplication works exactly the same forsegher wrote:Your "negate" at the end is incorrect, it does not carry.
You're doing Oxx, and then negating it; you can just do xOx
instead.
If you do things right, there is no difference whatsoever between
positive and negative numbers, which is the point. By adding the
offset, you're shifting the [80000000..7fffffff] range to [0..ffffffff],
which is much nicer to compute with. Say for example you are
jut doing a*b, and write D=80000000, then you instead compute
(a+D)*(b+D) which is a*b+(a+b+D)*D, so you get a*b by subtracting
the right side of that (which is cheaper than it looks!)
Nothing in there is dependent on sign, it works exactly the same for
positive and negative numbers, which is the point :)
positive and negative numbers as well, as long as you sign extend the numbers.
The question is thus, when is it cheaper to add an offset and subtract it on the XMOS ISA, compared to just multiply direct?
Assume that both a and b are a(n) and b(n), (timedependent), is it better to use the bias method? Or is it only when one coefficient becomes static over a longer timewindow the total instruction count is reduced.