HydrogenAudio

Hydrogenaudio Forum => Scientific Discussion => Topic started by: aristotel on 2003-12-31 03:52:53

Title: Triangular Probability Density Function Dither
Post by: aristotel on 2003-12-31 03:52:53
Hello everybody,

THis is my first post on this site. NIce to find a forum for this field which I am interested in and studying.

So here is the problem...

I need to write in C, a program that will dither and truncate a 16 bit stereo file to a 14 bit stereo file. It is for an assignment for university basically. I more or less have the idea of how it works after having read several books and websites.

However here is the problem/question.

To go from 16 bit to 14 bit and add dither before truncating it is necessary to add 3 bits of noise to the 16 bit original signal.

3 bits can have the maximum value of 8. In audio Terms -4 to +4. Correct so far?

Now if i generate a random number between 0 and 8, I can't just add that number to the 16 bit stream right? Becuase I need to add a +4 to -4 range number. It that correct? and if it is, how can I generate a random number between +4 and -4 in C?

int a = rand() % 8;

this would give a random value between 0 and 8. BUt how do i set a lower and upper limit for the random number to be generated?

Well, at this point this is all i will ask. I have a feeling this is somehting really simple and for some reason I have been stuck on it for some time now. 

Thank you in advance for reading it and hopefully replying.

In the meantime, Happy New Year everybody! 


PS: Oops..i just realised it was moved from general audio to Scientific..Sorry..i am new ..i thought this was a simple question and thats why i put it in General audio.
Title: Triangular Probability Density Function Dither
Post by: kjoonlee on 2003-12-31 04:16:40
Hi,

I'm quite a newbie, so I can't offer you real help, but I just want to point out something small.

3 bits give you 8 choices, yes, but with unsigned integers you'll probably get from 0 to 7, and with signed integers you'll probably get from -4 to 3.

-4, -3, -2, -1, 0, 1, 2, 3. Which makes 8 choices.

If you use % 8, you'll get numbers ranging from 0 to 7. Subtract 4, and you can get -4 to 3.
Title: Triangular Probability Density Function Dither
Post by: tigre on 2003-12-31 10:23:02
AFAIK rectangular dither is equal to random noise (= same probability for every value, in your case between -4 and 3). Triangular dither means adding independant random noise (values 0-7) 2 times and substracting 7 resulting in a triangular distribution of values:
7 = 1 / 64
6 = 2 / 64
5 = 3 / 64
...
0 = 8 / 63
...
-6= 2 / 64
-7= 1 / 64

BTW: There might be something wrong with this as Cool Edit Pro behaves not exactly the same: The values are in [-8;7] range instead, I guess because it uses higher resolution to generate and apply dither noise before truncation to final resolution.

I hope someone more knowledgable can help here soon. Maybe having a look at SSRC source (avail. here (http://rarewares.hydrogenaudio.org) will be helpful for you.
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2003-12-31 15:49:55
Hey..thanks for your replies.

I have come up with this code so far for Triangular Probability Density Function Dither from 16 bit to 14 bit. I declare two intigers and b. Two random numbers will be assigned to these intigers before they are added.

Since i need to add 3 bits of noice and as you already have explained that gives values between 0 to 7 unsigned or -4 to 3 for signed. In Rectangular Probability Densisty Function I would only use one random number generator for values 0 to 7 or -4 to 3 and add them to the signal as noise.

In Triangular Probability Function in order to achieve a highier number of values towards centre of the value range, I need to use two random number generators and add the sum for those two numbers to the signal as noise.

However, while the number generated for Rectangular Probability can be:

int a = rand() % 8;  and add the value to the signal,

In Triangular Probability I would be:

int a = rand() % 4;
int b = rand() % 4;

a = a + b; and add this sum to the signal.

QUESTION: Is this logic so far correct?

Bellow is the code I have so far. I haven't tried to compile it cause the system at the labs in the University is down and the administrator obviosuly is not working due to New Years Holiday. But for those who are more familiar with this type of work, does the code below make sense in theory?


Once again, thanx in advance and Happy New Year

PS:Sorry for the long post.

//Triangular Probability Density Function Dither

int a, b;                                                        //Declare two integer

while( (numberOfReadFrames = afReadFrames(afInputFileHandle, trackId, (void*) sampleBuffer, numberOfFramesPerBuffer) ) > 0 )
{

    for(j = 0; j < numberOfReadFrames; j++)
    {
        //Generate random noise between 0 and 3
        a = rand() % 4;
        //Generate random noise between 0 and 3
        b = rand() % 4;   

        a = a + b;                                          //Add random numbers
       
        //Add noise to Left Channel
        sampleBuffer[2*j] = (short) (sampleBuffer[2*j] + a);
        //Add noise to Right Channel
        sampleBuffer[2*j + 1] = (short) (sampleBuffer[2*j + 1] + a);

        //Trancate Left Channel
        sampleBuffer[2*j] = (short) (sampleBuffer[2*j] >> 2);
        //Trancate Right Channel
        sampleBuffer[2*j + 1] = (short) (sampleBuffer[2*j + 1] >> 2);
    }
 
    afWriteFrames( afOutputFileHandle, trackId, sampleBuffer, numberOfReadFrames );
}
Title: Triangular Probability Density Function Dither
Post by: Jasper on 2004-01-01 10:49:40
It seems correct, but wouldn't you just need to add (approximately) 2 bits of noise? Before truncating there would be values between 0 and 3 in the 2 last significant bits, so you'd only need to add a number between -2 and 1 (actually, shouldn't that be -2 and 2? or perhaps -1 and 2) to make it swing either way. Or am I missing something here.
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-01 15:57:18
Hey Jasper..thanks for your post.

The decision to add 3 bits of noise comes from the http://www.cadenzarecording.com/dither.html (http://www.cadenzarecording.com/dither.html) example. They go from 24 bit to 16 bit and add 9 bits of noise. So the formula for determining how many bit of noise to add is:

(original bit value - bit value to be lowered to) + 1 = bit length of noise to be added

Example: (24 - 16) + 1 = 9

At least thatis how I understood it 

According to their example.... to go from 16 bit to 14 i will need to add 3 bits of noise..that way...once its truncated to 14 bit..then only the first bit has noise?
Title: Triangular Probability Density Function Dither
Post by: cabbagerat on 2004-01-02 05:57:34
You might want to consider the fact that with most C libraries rand() % 8 will not give you high quality random numbers. The least significant bits returned by C lib PRNGs are notoriously unrandom. Whether or not this will be audible, I don't know - but you might want to think about it.
Also, I had assumed from what I have read that when dithering you would use different noise for each channel.

Based on tigre's post this is the code I would write (for one channel only) for each sample:
Code: [Select]
unsigned short ditherValue(unsigned short sample)
{
sample += hqRand(8) + hqRand(8) - 7;
sample >>= 2;
return sample;
}

This code is not perfect - samples close to clipping will cause brokenness.

The following will work acceptably well for hqRand(), but is not without it's problems. You will want to read up on better techniques:
Code: [Select]
unsigned short hqRand(int limit)
{
return (rand() >> 3) % limit;
}
Title: Triangular Probability Density Function Dither
Post by: Jasper on 2004-01-02 11:02:00
If you are looking for good random number generators, have a look at Boost (http://www.boost.org/), it's a C++ library, but you might be able to extract the code for a random number generator that suits your needs.

BTW, is there anyone that can explain why the +1 in the following formula is necessary?
Quote
(original bit value - bit value to be lowered to) + 1 = bit length of noise to be added

I gave dithering a try myself some time ago and it seemed to work alright without the +1.
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-03 19:15:33
Hello, Jasper..the way I understood it was that if you are to go from 16 to 14 bits, if u add only 2 bits of noise..those two bits of the noise will be gone as soon as u trancate it to 14 so the resulting signal would be the same as it would have if simply trancated without any noise, since the two last bits are errased.

So if you add three bits of noise..then when u remove 2 bits from the signal, then one bit of the remaining 14 bits will still contain the data from the noise.


I am getting a clearer idea on this dither the more i read all of your posts.

Cabbagerat, your code makes sense, and i will take your advice and add different noise to left and right channel. I have one more question though.

In the rectangular dither I will be adding random values in the range of -4 and 3(3 bits signed)

But in the triangular where I need to add two random numbers in order to come up with a highier chance of numbers in the middle of the range, you suggested the following code:

sample += hqRand(8) + hqRand(8) - 7;

However this would result in a range between -7 and 7. This would not be a 3 bit signed range right?

So i thought of changing it to:

sample += hqRand(4) + hqRand(4) - 3;

But each random would then generate a maximum number of 3. So the maximum number generated by adding those two randoms would be 6, subrtact the 3, and that  leaves 3. So the range would be -3 to 3. So this is not equal to the -4 to 3 range of the rectangular noise.

i could change it to :

sample += hqRand(4) + hqRand(4) - 4;

This would fix the lower range to match the one of the rectangular dither of -4, but it would also lower the maximum range to 2.

ANd so once again, I am stuck! Its probably something simple and Its not comming to me! I shall continue to try and find the answer to this, but if you have any suggestions that would as usual be great! 

Thanx in advance!
Title: Triangular Probability Density Function Dither
Post by: Jasper on 2004-01-04 10:28:53
Actually the information from those two bits of noise wouldn't be completely lost, as it would result in different rounding. Suppose you were going from 4 bits to 2 bits and the current value would be 3 (0011 in binary), now add some random number between -2 and 2 (actually this would result in 5 combinations, but in that article "Dithering Explained" they also use symmetrical values), the result would between 1 (0001) and 5 (0101). So why wouldn't this be enough to give at least a small amount of dither?

EDIT:
As for those random values, if you are determined to add 3 bits of noise, why not use:
sample += hqRand(5) + hqRand(5) - 4;
This would result in values in the range [-4,4], which is comparable to what they did in the article mentioned in one of the first posts (there they add 9 bits of noise by adding values in the range [-128,128]). Of course the term "n bits of noise" is a bit misplaced in this case, but it is less biased. As an example, consider the situation above (from 4 bits to 2 bits):

Original: 0100
Possible outcomes:
0010 -> 00
0011 -> 00
0100 -> 01
0101 -> 01
0110 -> 01 *

Original: 0101
Possible outcomes:
0011 -> 00
0100 -> 01
0101 -> 01
0110 -> 01
0111 -> 01 *

Original: 0110
Possible outcomes:
0100 -> 01
0101 -> 01
0110 -> 01
0111 -> 01
1000 -> 10 *

Original: 0111
Possible outcomes:
0101 -> 01
0110 -> 01
0111 -> 01
1000 -> 10
1001 -> 10 *

The outcomes with an asterisk (*) behind them wouldn't be generated if you added numbers in the range [-2,1] (which would be true 2 bits signed), which results in a signal that's biased towards negative infinity.
Title: Triangular Probability Density Function Dither
Post by: tigre on 2004-01-04 11:20:52
There must be a mathematical way to determine how much dither is necessary to avoid distortion and noise bumping totally, depending on dither flavour (rectangular, triangular). I don't know anything about this but I'm sure someone else does (KikeG?). You can always perform tests on this using CoolEdit / Audition (frequency analysis etc.)
Title: Triangular Probability Density Function Dither
Post by: Ariakis on 2004-01-04 11:33:59
http://www.hydrogenaudio.org/forums/index....indpost&p=71022 (http://www.hydrogenaudio.org/forums/index.php?showtopic=7133&view=findpost&p=71022)

This thread has tons of info... it's SSRC-specific, but hopefully useful nonetheless.

Just according to the first post, for triangular PDF: 0.9 bits are needed to avoid appreciable distortion (noise modulation remains), 1 bit needed to avoid noise modulation.
Title: Triangular Probability Density Function Dither
Post by: Diocletian on 2004-01-04 11:56:01
Quote
There must be a mathematical way to determine how much dither is necessary to avoid distortion and noise bumping totally, depending on dither flavour (rectangular, triangular).

... Totally ...

What does this mean?
- inaudible?
- a certain level below audibility?
- not existing in any way?
Title: Triangular Probability Density Function Dither
Post by: tigre on 2004-01-04 12:06:15
totally = not mesurable.

e.g. distortion: If you create a low volume sine wave, add dither and truncate, besides the original tone, no peaks must be visible in frequency analysis.
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-04 18:16:48
Hello everybody...lots of replies i see...lots of information and as usual more questions...   

Ok..Jasper your post regarding adding 2 bits of noise and then loosing 2 bits that it is still have an effect on the remainng bits makes perfect sense. What i will do for my assignment is do both 2 bits and 3 bits of noise and explain in the documentation why i tested both of them and compare the audio with frequency analysis diagrams.

Secondly, your suggestion to use sample += hqRand(5) + hqRand(5) - 4; also makes sense, giving me a range of -4 to 4. As a range of -4 to 3 would be more negative value biased.(I had actualy scribled on a piece of paper rand() %5 + rand() % 5 -4 and calculated the range it would give me...and i had written down -4 to 6 becuase i was tired and forgot that rand() % 5 can give u a maximum of 4 and not 5. Silly me)

However, That has confused my understanding of digital audio theory. See I always thought that, a 16 bit signed short has a range of -38,768 to 32,767. According to that, ZERO is not half way between the minimum and maximum range right? So is ZERO actually more positive based? Does zero correspond to -1? and is -0.5 the actual halfway between the range? 

Thirdly, a range of -4 to 4 in the triangular code makes sense. But, in my rectangular dither i use rand() % 8 - 4  to generate the random number, giving me a range of -4 to 3. This suffers from being more negative value biased. I must make the the range to be from -4 to 4 also.  So i will change it to rand() % 9 - 4. This will give me a range of -4 to 4.

Tigre I have downloaded a 30 days trial of Adobe Audition and have been trying out the Frequency analysis feature. THanks for the suggestion

Ariakis, thanks for the link. I tried to read that and got confused (again). It talks about 0.5, 0.9 and 1.0 bits of noise! How do you get a portion of a bit noise? I thought one bit was the smallest value of noise one could add.. How does this work?

Once again, thanks to all of you, you are truly LOTs of help!!! 
Title: Triangular Probability Density Function Dither
Post by: tigre on 2004-01-04 18:58:47
Quote
It talks about 0.5, 0.9 and 1.0 bits of noise! How do you get a portion of a bit noise? I thought one bit was the smallest value of noise one could add.. How does this work?

Do processing at higher resolution (e.g. 32bit float), including noise generating.
Title: Triangular Probability Density Function Dither
Post by: 2Bdecided on 2004-01-05 15:07:47
I've only just seen this thread.

At the risk of doing your research for you...


Using your example of reducing from 16 to 14 bits. A and B are both sequences of random numbers, such that, for any given sample

A = 00 or 01 or 10 or 11
B = 00 or 01 or 10 or 11

Rectangular dither is added by adding A (only) to a signal, and removing the last two bits. Rectangular dither is sub-optimal because, though harmonic distortion is removed, noise modulation remains.

Triangular dither is added by adding A and B to a signal, or adding A and subtracting B.


To prevent DC shift or bias, you must think carefully about what kind of rounding, truncation, or quantisation you are using, and adjust accordingly. Consider the last bit you will keep as representing the least significant bit of a whole number (1), and the less significant bits (which you will remove) as representing a fractional part.

The rectangular dither will not introduce a DC shift if a round-down quantiser is used. Simple truncation (throwing away the fractional bits) acts as a round down quantiser, so simply adding A and truncating works well.

The triangular dither will not introduce a DC shift if we add A minus B, and use a "centre (center, if you're American) rise" quansier. This is the typical "rounding" function we use everyday with decimal numbers - if the fractional part is under 0.5: round down, 0.5 or above: round up.

Truncation is not the same as rounding, and does not give a centre rise quantiser. However, if you simply add 0.5, and then truncate, the result will be the same as rounding.

So, for triangular dither without DC bias, just use
A-B+0.5
or
A+B-0.5
whichever is easier.


All IIRC - it's been 6 years since I studied this.

You really should search out some good paper references. The original 1984 AES paper from Vanderkooy and Lipshitz, "Resolution Below the Least Significant Bit in Digital Audio Systems with Dither" (volume 32, issue 3, pp106-112 if the page Google found is to be believed) is well worth reading carefully.

Cheers,
David.
Title: Triangular Probability Density Function Dither
Post by: KikeG on 2004-01-06 15:49:12
Quote
There must be a mathematical way to determine how much dither is necessary to avoid distortion and noise bumping totally, depending on dither flavour (rectangular, triangular). I don't know anything about this but I'm sure someone else does (KikeG?). You can always perform tests on this using CoolEdit / Audition (frequency analysis etc.)

If I'm not wrong (2Bdecided probably knows better than me), mathematically, with rectangular dither, 1 bit amplitude is enough to totally remove distortion, but noise modulation remains. With triangular dither, 1 bit is enough to totally remove both, distortion and noise modulation. With noiseshaping dither, the amount depends on the shaping of the noise floor, but is usually below 1 bit. I don't know of a way of calculating this, but maybe the mentioned paper does. At the tests I did on the mentioned thread I used subjective listening tests for the noise modulation issue, using a critical test signal, amplified several tenths of dBs to make dither failure audible, and also frequency analysis (FFT) to detect distortion.
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-06 17:21:18
Quote
Do processing at higher resolution (e.g. 32bit float), including noise generating.

I heard of audio software doing the internal processing at 32 bit float resolution..but here comes the dummy question...how?

I have never done this...this is what I have come up with..does it make sense?

Code: [Select]
for(all the samples in the audio file)
{
    float sampleFloat = (float) sampleBuffer[i];   // Change the sample into float?
    float randomNumber = (rand() % n) -n;  //This wouldn't even work would it?Generating random FLOAT?
    sampleFloat += randomNumber;
    sampleFloat >> n;   //Truncate by however many bits needed to the right
    sampleFloat << n;   //Truncate by however many bits needed to the left
    sampleBuffer = (short) sampleFloat;  //Store new sample value back to buffer array      as short data type?
}


Is my idea even close to reallity or 32 bit processing.

One last question on this matter. If we can process with 32 bit float for precision..what stops us going to the extreme and processing in something of highier precision than that even? say..64 bit??? 

Got more questions comming...just asking them as seperate posts to kep things organized..

thanx people!
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-06 18:04:19
Hello 2bDecided..your post is helpful and thank you lots for your it. I have the following questions so i can finnaly get my head around this.


For two bits of triangular probability noise i could use:

(rand() % 3) + (rand() % 3) - 2;

This will give me a range of -2 to 2. The possible values are -2,-1,0,1,2. THat is five of them with 0 being the absolute centre. Does this not result in a dither without DC bias?

On your example, you generate a true 2 bit noise range of 4 values. There is no clear MIDDLE value. It this the case where the use of +0.5 or -0.5 is necessary?

Also, I assume that in order to add or subtract the 0.5, i need to be processing the samples in 32 bit float precision, so hopefully i can find some information on how to do that if my earlier guess in this post is wrong.

U mentioned the addition of 2 bits worth of noise inthe example of going from 16 to 14 bit. Does this mean you belive that the amount of bit of noise to add is equal to the amount of bits you are about to loose by truncating?

I hope this makes sense...There are too many loose questions in my head which I am not sure if they are related or not, or how to ask them appropriately...
THe feeling of learning and understanding somethng new i suppose. 

I am on my way to the library now to look up that AES journal entry you recommended.

thanks a lot for your patience!
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-06 18:16:28
Quote
if I'm not wrong (2Bdecided probably knows better than me), mathematically, with rectangular dither, 1 bit amplitude is enough to totally remove distortion, but noise modulation remains. With triangular dither, 1 bit is enough to totally remove both, distortion and noise modulation. With noiseshaping dither, the amount depends on the shaping of the noise floor, but is usually below 1 bit.

Hello,

these recommended values of noise, are you suggesting them on the basis of the 16 to 14 bit scenario or in general?

At first I thought that if you are going to loose n bits of the signal then add n+1 bits of noise, so that after truncating the signal you still have 1 bit of noise in the signal.

As it was explained by Jasper,

Quote

Actually the information from those two bits of noise wouldn't be completely lost, as it would result in different rounding. Suppose you were going from 4 bits to 2 bits and the current value would be 3 (0011 in binary), now add some random number between -2 and 2 (actually this would result in 5 combinations, but in that article "Dithering Explained" they also use symetrical values), the result would between 1 (0001) and 5 (0101). So why wouldn't this be enough to give at least a small amount of dither?
[\quote]

It makes perfect sense. But how about when going from 16 bits to 8 bits. The chances of the value changing due to rounding gets smaller if adding a small size of noise.

So surely there must be some way of calculating and determining how many bits of noise are necessary/recommended depending on 2 factors: 1) the number of bits you will be truncating the signal by, and 2) the type of noise you will be adding as it seems different probabilities and noise shaping can require diferent amount of noise.


Thanx!
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-06 18:20:53
Quote
However, That has confused my understanding of digital audio theory. See I always thought that, a 16 bit signed short has a range of -38,768 to 32,767. According to that, ZERO is not half way between the minimum and maximum range right? So is ZERO actually more positive based? Does zero correspond to -1? and is -0.5 the actual halfway between the range?

Last question for some time (hopefully!)

This hasn't been discussed..Does anybody have an understanding on this?

Is digital audio always a bit negatively biased as the value of the negatives(-38,768) is greater than that of the positives(32,767)?

I know this value difference is tiny..but curious in the theory behind this.

Title: Triangular Probability Density Function Dither
Post by: 2Bdecided on 2004-01-07 12:46:31
Quote
Hello 2bDecided..your post is helpful and thank you lots for your it. I have the following questions so i can finnaly get my head around this.


For two bits of triangular probability noise i could use:

(rand() % 3) + (rand() % 3) - 2;

This will give me a range of -2 to 2. The possible values are -2,-1,0,1,2. THat is five of them with 0 being the absolute centre. Does this not result in a dither without DC bias?

On your example, you generate a true 2 bit noise range of 4 values. There is no clear MIDDLE value. It this the case where the use of +0.5 or -0.5 is necessary?

Also, I assume that in order to add or subtract the 0.5, i need to be processing the samples in 32 bit float precision, so hopefully i can find some information on how to do that if my earlier guess in this post is wrong.

You're getting confused between the value before and after truncation. It's helpful if you think in binary about what you're doing before truncation. It's also convention to quote values in decimal relative to the last remaining bit being 1 after truncation.


So, thinking in binary, (rand() %3) apparently gives you 0, 1, or 2 i.e. 00, 01, or 10. What happened to 11?! So that's the wrong amplitude to start with.

If the last remaining bit after truncation has a value of 1, then the bit that was to its right before truncation has a relative value of 0.5. So, just like you, I was simply subtracting 2 before truncation - no floating point necessary.


Quote
U mentioned the addition of 2 bits worth of noise in the example of going from 16 to 14 bit. Does this mean you believe that the amount of bit of noise to add is equal to the amount of bits you are about to loose by truncating?


An easy rule is that the rectangular dither should exactly fill the bits you remove (no more, no less), and that triangular dither can be created by adding two independent rectangular dither sources. This makes things very easy.

so 16 to 8 bits conversion is
xxxxxxxxyyyyyyyy > xxxxxxxx
you need two rectangular dither generators (i.e. two pseudo random number generators) ranging from 00000000 to 11111111 i.e. 0 to 255. You don't want 256 (100000000) because that gives you an amplitude of 1 too many.

(Think about it with a decimal example: it's just like 0,1,2,3,4,5,6,7,8,9 gives you ten possible values, but 0,1,2,3,4,5,6,7,8,9,10 gives you eleven. So unless you want a range of eleven, then if you include the number 0, you don't include the number 10. It's the same here, but in binary)


Finally, digital audio isn't DC biased one way or the other - it's just that it can go one more value negative than positive. When CDs were introduced, "good" converters had DC offsets of, say, 40 or 50 (measured in units of 1 LSB at 16-bit) so it was probably never even considered.

Hope this helps. I think the contributors to this thread deserve a credit and/or reference in your project, and a drink!

Cheers,
David.
Title: Triangular Probability Density Function Dither
Post by: aristotel on 2004-01-09 02:22:47
Quote
Hope this helps. I think the contributors to this thread deserve a credit and/or reference in your project, and a drink!

It sure has helped! thanx a lot..and you are absolutely right all the contributors deserve mention and great thanks in my project!

Please email me at ad167@york.ac.uk with your username of this forum and your real name so that I can give you all the appropriate credit you all deserve. You can post the information on this forum but i figured some might not want to post their real names on a forum. If I Dont receve your real names I can still go ahead and refere to you by your forum username 

As far as drinks!!! Absolutely! Anybody live in York UK? If yes email me at the above address 

Thank you everybody!
Title: Triangular Probability Density Function Dither
Post by: Ariakis on 2004-01-09 08:04:53
Just a note on what David said about a triangular generator being a combination of two rectangular generators...

He said that to get 8 bits of triangualr pseudorands, you'd need to combine two rectangular generators with ranges of [0, 255].  This, however, would allow a total range of [0, 510], which is more than 8 bits.

So to get 8 bits of triangular dither, you'd need to combine [0, 127] and [0, 128] rectangular generators to get a [0, 255] triangular generator.  At least, I think.

So, in your case, you'd want 3 bits of noise, which is [0, 7]... so you'd want to combine [0, 3] and [0, 4] rectangular generators, I think.

Someone correct me if I'm wrong, please. =)
Title: Triangular Probability Density Function Dither
Post by: Jasper on 2004-01-09 12:06:27
Actually I think you'd want something symmetrical, so as not to create a DC bias, which is done perfectly when adding two independent rectangular generators with the same range.
As for the number of bits used, a few posts earlier someone said that a range of 1 bit (peak-to-peak?) would be enough for triangular dither, but I have also heard of 2 bits being best (Principles of Digital Audio, Ken C. Pohlmann, and this also seems to be what 2Bdecided is suggesting). Perhaps someone can clear this up.
Title: Triangular Probability Density Function Dither
Post by: 2Bdecided on 2004-01-09 12:29:24
Quote
Just a note on what David said about a triangular generator being a combination of two rectangular generators...

He said that to get 8 bits of triangualr pseudorands, you'd need to combine two rectangular generators with ranges of [0, 255].  This, however, would allow a total range of [0, 510], which is more than 8 bits.

So to get 8 bits of triangular dither, you'd need to combine [0, 127] and [0, 128] rectangular generators to get a [0, 255] triangular generator.  At least, I think.

So, in your case, you'd want 3 bits of noise, which is [0, 7]... so you'd want to combine [0, 3] and [0, 4] rectangular generators, I think.

Someone correct me if I'm wrong, please. =)

Triangular dither must be two bits peak to peak, so I'm affraid you're not right!

Correct triangular dither removes noise modulation - that means that the resulting noise (after truncation) from adding dither will be independent of the level of the original signal.

Rectangular dither doesn't so this properly. If the original signal lies exactly half way between two steps in the least significant bit of the truncated signal, then it can be bumped up or down by 0.5 bits - therefore the resulting noise (noise=final-original) will always have a magnitude of 0.5 bits. Whereas if the original signal is elsewhere, the magnitude of the noise (i.e. the rounding error) will be different, and signal dependent.

Triangular dither solves this by always giving the rounded signal the chance of being the same number of "bits" (or fractions of one bit) away from its original value. Without scanning a picture in, I can't explain this any better.

If you only have 1 bit peak to peak triangular dither (that's called 0.5 bits in Cool Edit for some reason), then it will cause even worse noise modulation than recntangular dither, and won't even remove harmonic distortion.

So it must always be 2 bits peak to peak.

Cheers,
David.
(That's "Dr David Robinson" for your credits aristotel! I nearly did an MSc at York, and I've stayed there a time or two (once at the uni) - I won't hold you to that drink though! - I'm a long way away now.)
Title: Triangular Probability Density Function Dither
Post by: goli on 2005-05-29 19:02:42
Hi everybody,  I just visited this page and i was wondering if anybody can help me with a question about dithering. 
I want to reduce the # of bits from 8 to 4 and i want to use rectangular dither . So, i have to add a 4-bit random signal to the original one before quantizing.  I just  don't know what to do with boundries . For example , if the original value is 255 evey positive dither will make the total value to have 9 bits  and i am not sure what to do with it.

Thanks in advance,
Title: Triangular Probability Density Function Dither
Post by: spoon on 2005-06-15 10:11:30
To quote shibatch "Dithered 8bit files contains strong supersonic, and listening to these files for long hours may damage your hearing. Dithered 16bit files are no
problem since the power of the supersonic of dither is 1/65536 of those of
dithered 8bit files."

4 bit would be even worse...
Title: Triangular Probability Density Function Dither
Post by: KikeG on 2005-06-15 13:13:23
That depends largely on the sample rate.
Title: Triangular Probability Density Function Dither
Post by: 2Bdecided on 2005-06-16 11:37:11
Quote
Hi everybody,  I just visited this page and i was wondering if anybody can help me with a question about dithering. 
I want to reduce the # of bits from 8 to 4 and i want to use rectangular dither . So, i have to add a 4-bit random signal to the original one before quantizing.  I just  don't know what to do with boundries . For example , if the original value is 255 evey positive dither will make the total value to have 9 bits  and i am not sure what to do with it.
[a href="index.php?act=findpost&pid=301515"][{POST_SNAPBACK}][/a]


Clip it - if you already have a full scale sample, then dither can send this 1 bit (or 2 bit, with triangular dither) over full scale. Check for it in the code, and ensure values over 255 are clipped to 255. Also ensure you don't go below 0.

If you're not careful, you'll overflow 255 to 0 or 0 to 255, and that will sound terrible!

4-bit audio will sound terrible anyway - what project are you working on? Is it interesting, or experimental?

Cheers,
David.
Title: Triangular Probability Density Function Dither
Post by: Nika on 2005-06-16 14:50:51
Sorry, guys, I've only just seen the thread and haven't read all the way through it.  The bit depth of the dither is not "2 bits" but rather "2 quantization steps" (of the remaining quanta).  2 bits implies the options of 00, 01, 10, and 11.  2 quanta implies 00, 01 and 10.  The dither must be of triangular probability within this range.  The way to generate the dither is to generate one bit's worth of random values twice, so:

Random value between 0000 (bits 13 through 16) and 0100.  Do this twice and add them together. 

You now have TPDF dither of 2 quanta in amplitude (not 2 bits).  The result will be some value between 0000 and 1000 with the greatest likelihood that the number will be 0100.

To the person that asked, this is precisely the amount and type of dither needed in order to completely remove quantization distortion (or rather turn it into noise).  This has been mathematically proven and you can find these proofs in the writings of Lipshitz and Vanderkooy.

I hope this helps?

Nika
Title: Triangular Probability Density Function Dither
Post by: Nika on 2005-06-16 14:55:30
Quote
Hi everybody,  I just visited this page and i was wondering if anybody can help me with a question about dithering. 
I want to reduce the # of bits from 8 to 4 and i want to use rectangular dither . So, i have to add a 4-bit random signal to the original one before quantizing.  I just  don't know what to do with boundries . For example , if the original value is 255 evey positive dither will make the total value to have 9 bits  and i am not sure what to do with it.

Thanks in advance,
[a href="index.php?act=findpost&pid=301515"][{POST_SNAPBACK}][/a]


First, don't use rectangular dither.  Second, dither is a signal added to the original.  If you have no headroom you will assuredly clip when adding this signal.  Either gain adjust the original ahead of time or acknowledge that you are going to clip.  Third, if this is really audio you may want to try noiseshaping instead of dithering if you're going to 4 bits.  That's a very low dynamic range and you can steal some additional dynamic range by noiseshaping it appropriately.

Nika
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-08-27 15:47:46
Sorry, guys, I've only just seen the thread and haven't read all the way through it.  The bit depth of the dither is not "2 bits" but rather "2 quantization steps" (of the remaining quanta).  2 bits implies the options of 00, 01, 10, and 11.  2 quanta implies 00, 01 and 10.  The dither must be of triangular probability within this range.  The way to generate the dither is to generate one bit's worth of random values twice, so:

Random value between 0000 (bits 13 through 16) and 0100.  Do this twice and add them together. 

You now have TPDF dither of 2 quanta in amplitude (not 2 bits).  The result will be some value between 0000 and 1000 with the greatest likelihood that the number will be 0100.

To the person that asked, this is precisely the amount and type of dither needed in order to completely remove quantization distortion (or rather turn it into noise).  This has been mathematically proven and you can find these proofs in the writings of Lipshitz and Vanderkooy.

Sorry for bringing up an old thread. I'm trying to reduce a signed 24bit PCM track to 20bit. As far as I understand this is what I have to do:

(1) Add a random value of the range [-32..+32].
(2) Add another random value of the range [-32..+32].
(3) Round the resulting PCM sample to 20bit.

Is that correct? Thanks much!!
Title: Triangular Probability Density Function Dither
Post by: Nick.C on 2007-08-27 17:01:02
Is it not simply:

new_value = round(old_value/(2^4)+random-random)

?
Title: Triangular Probability Density Function Dither
Post by: SebastianG on 2007-08-27 17:53:44
Sorry for bringing up an old thread. I'm trying to reduce a signed 24bit PCM track to 20bit. As far as I understand this is what I have to do:

(1) Add a random value of the range [-32..+32].
(2) Add another random value of the range [-32..+32].
(3) Round the resulting PCM sample to 20bit.

Is that correct? Thanks much!!


That's too much dither (12 dB more than necessary).

It's as simple as Nick.C pointed out:
new_int20 = round( old_int24 / 16.0 + rnd() - rnd() );
where rnd() returns independently and idendically-distributed values between 0.0 and 1.0

A full TPF dither signal only carries samples values between -d...d where d is the quantizer step size.

A full rectangular dither would be:
new_int20 = round( old_int24 / 16.0 + rnd() - 0.5 );

You can even morph between both distributions:
new_int20 = round( old_int24 / 16.0 + rnd() - 0.5*rnd() - 0.25 );

The choice is really a trade-off between dither noise power and the degree of noise modulation you are willing to accept. For example I prefer the last variant which is as safe as rectangular dither and usually enough to avoid noise modulation -- especially when coupled with noise shaping filters.

Cheers!
SG
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-08-28 08:23:01
That's too much dither (12 dB more than necessary).

It's as simple as Nick.C pointed out:
new_int20 = round( old_int24 / 16.0 + rnd() - rnd() );
where rnd() returns independently and idendically-distributed values between 0.0 and 1.0

I'm trying to avoid floating point math to speed things up. So is this correct for doing TPF?

(1) add a random value of [0..16]
(2) substract a random value of [0..16]
(3) round down to 20bit

I could do it this way without using floating point math.

Thanks much!

P.S: Osterode grüßt Göttingen!! 
Title: Triangular Probability Density Function Dither
Post by: Nick.C on 2007-08-28 08:31:34
Surely, to round you will have to use FP maths? ...or maybe not....

Pascal:

new_value:=(old_value + random(16) - random(16));

if (new_value and 15)>7 then
  new_value:= new_value shr 4 + 1
else
  new_value:= new_value shr 4;
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-08-28 09:02:24
Surely, to round you will have to use FP maths? ...or maybe not....

Pascal:

new_value:=(old_value + random(16) - random(16));

if (new_value and 15)>7 then
  new_value:= new_value shr 4 + 1
else
  new_value:= new_value shr 4;

Heh, yes, I was planning something like that. I still need to check if that works correctly for negative samples, too. Furthermore I still need to add checks for overflow/clipping.

Anyway, the dither/random range is correct now? According to this pdf:

http://www.users.qwest.net/%7Evolt42/caden...erExplained.pdf (http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf)

... it should be random(17) instead of random(16), or am I wrong?
Title: Triangular Probability Density Function Dither
Post by: SebastianG on 2007-08-28 09:13:35
(1) add a random value of [0..16]
(2) substract a random value of [0..16]
(3) round down to 20bit

Then you won't get an exact triangular distribution -- only an approximation.
But it'll be okay in your case, I guess. You could however improve it by doing:
new_sample20 = ( (old_sample24 << 4) + rand(256) - rand(256) + 128 ) >> 8;
where rand(int x) returns equally distributed values from 0 (inclusive) to x (exclusive)
and (>>) is a sign-extending right shift.

Quote
P.S: Osterode grüßt Göttingen!! 

Yay!

Cheers!
SG

new_value:= new_value shr 4

You have to be careful with the operator 'shr' in Pascal. 'shr' is an extension of the Borland compiler which fills the upper bits always with zeros (no sign-extension).

Cheers!
SG
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-08-28 09:23:18
Then you won't get an exact triangular distribution -- only an approximation.

Why is that?

And shouldn't it be rand(257)?

Thanks much!
Title: Triangular Probability Density Function Dither
Post by: SebastianG on 2007-08-28 14:10:02
Then you won't get an exact triangular distribution -- only an approximation.

Why is that?

Because you add already discrete quantized values. You end up with a discrete probability distribution = finite amount of possible dither sample values.

And shouldn't it be rand(257)?

No, it was supposed to be 256. This'll lead to the best approximation to the TPDF.
Sketch of proof:
The best approximation of a rectangular PDF for values 0..256 can be done via rand(256)+0.5. This should be obvious. If we substitute the RNG in the formular for a TPDF dither we get:
Code: [Select]
new_value20 = ( old_value24 << 4 + (rand(256)+0.5) - (rand(256)+0.5) + 128) >> 8;
            = ( old_value24 << 4 +  rand(256)      -  rand(256)      + 128) >> 8;

Note: (x+128) >> 8  is equivalent to  round(x/256.0)

The 0.5 and -0.5 cancel each other.


Cheers!
SG
Title: Triangular Probability Density Function Dither
Post by: 2Bdecided on 2007-08-28 14:18:05
It's probably worth mentioning a simple trick that's widely used.

Don't generate two random numbers per sample, and subtract them.

Instead, generate one random number per sample, and subtract the previous random number.

So

output = round(scale * input + this_random_number - previous_random_number)

This is still perfectly valid TPF dither, but has the effect of high pass filtering the dither, which is generally a desirable thing for audio (and many other applications).

Cheers,
David.
Title: Triangular Probability Density Function Dither
Post by: Nick.C on 2007-08-28 14:33:26
Don't generate two random numbers per sample, and subtract them.
Instead, generate one random number per sample, and subtract the previous random number.
Sneaky, damned sneaky
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-08-28 14:50:45
Because you add already discrete quantized values. You end up with a discrete probability distribution = finite amount of possible dither sample values.

Ok, I think I understand, thank you. One final question: If I use your idea to use "value24 << 4" I've no room left in 32bit processing for detecting overflow, or am I wrong? What do you think about this?

new_sample20 = ( (old_sample24 << 3) + rand(128) - rand(128) + 64 ) >> 7;

This way I'd leave one bit space for potential overflows. What do you think?

P.S: The problem you have with my rand(16) is that the random range is too small, right? Wouldn't it be mathematically equivalent to do this?

new_sample20 = ( old_sample24 + ((rand(256) - rand(256)) >> 4) + 8 ) >> 4;

Quote
probably worth mentioning a simple trick that's widely used.

Don't generate two random numbers per sample, and subtract them.

Instead, generate one random number per sample, and subtract the previous random number.



Ouch, I'm stupid!!      24 + 4 are only 28. I think I need some sleep... 
Title: Triangular Probability Density Function Dither
Post by: SebastianG on 2007-08-28 14:59:30
P.S: The problem you have with my rand(16) is that the random range is too small, right? Wouldn't it be mathematically equivalent to do this?

Equivalent? No, this ditherer only generates 31 possible values.
But I suppose it's good enough.

Cheers!
SG
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-08-28 16:23:45
Equivalent? No, this ditherer only generates 31 possible values.
But I suppose it's good enough.

I don't understand why your solution is different mathematically.

Code: [Select]
Your original suggestion:
new_sample20 = ( (old_sample24 << 4) + rand(256) - rand(256) + 128 ) >> 8;

My modified suggestion:
new_sample20 = ( old_sample24 + ((rand(256) - rand(256)) >> 4) + 8 ) >> 4;


Now let me write them a bit differently:

Code: [Select]
Your original suggestion:
new_sample20 = ( ((old_sample24 << 4) >> 0) + (TPF(0x100) >> 0) + ((0x8 << 4) >> 0) ) >> 8;

My modified suggestion:
new_sample20 = ( ((old_sample24 << 4) >> 4) + (TPF(0x100) >> 4) + ((0x8 << 4) >> 4) ) >> 4;


Shouldn't that be mathematically identical?

In both your suggestion and my modified suggestion we have the three following values:

(1) "old_sample24 << 4" - bottom 4 bits are 0
(2) "TPF(0x100)" - bottom 4 bits contain data
(3) "0x8 << 4" - bottom 4 bits are 0

Of course I'm cutting off the bottom 4 bits of the TPF value before adding the three values, while you're doing the cutting off after the addition. But in the end IMO it doesn't matter because two of the three values have zeroed out bottom 4 bits. Only TPF has information in the bottom 4 bits. So those bottom 4 bits can never result in any other bits being impacted by "addition overflow". So basically the bottom 4 bits are useless and are being cut off by the final right shift, anyway. What am I missing?

Thanks much for your help!! 
Title: Triangular Probability Density Function Dither
Post by: kwwong on 2007-09-04 02:59:44
It's probably worth mentioning a simple trick that's widely used.

Don't generate two random numbers per sample, and subtract them.

Instead, generate one random number per sample, and subtract the previous random number.

So

output = round(scale * input + this_random_number - previous_random_number)

This is still perfectly valid TPF dither, but has the effect of high pass filtering the dither, which is generally a desirable thing for audio (and many other applications).

Cheers,
David.


As I understand it that the random number generated is from a pseudo-random number generator function RAND(). I was wondering if it is necessary that the random source be white? In this case it make perfect sense that you can use the previous random number generated in the subtraction.

What is the effect of a non-white random source in dithering?
Title: Triangular Probability Density Function Dither
Post by: SebastianG on 2007-09-05 10:27:45
It's probably worth mentioning a simple trick that's widely used.
(...)
Instead, generate one random number per sample, and subtract the previous random number.
(...)
This is still perfectly valid TPF dither, but has the effect of high pass filtering the dither, which is generally a desirable thing for audio (and many other applications).

Honestly, I still need to wrap my head around this. Do you think that the quantization error's auto-correlation (the noise's colour) will be independent of the input-signal? I have my doubts but I'm not sure.
The difference to "real noise shaping" is that this trick you mentioned kind of uses "filtering before quantization" whereas proper noise shaping operates on the quantized unfiltered noise which is guaranteed to be white due to "normal" dithering.

Cheers!
SG
Title: Triangular Probability Density Function Dither
Post by: jlohl on 2007-09-06 11:02:29
Quote
What is the effect of a non-white random source in dithering?

I did a small and free software to show/hear the effect of dither. The dither itself can be noise but also a sine wave. So you can try and listen to the result.
Get it here (http://www.ohl.to/about-audio/audio-softwares/ditherer/)
Title: Triangular Probability Density Function Dither
Post by: ilo on 2007-09-27 22:57:22
TPDF dither should have a peak amplitude twice that of RPDF-dither, if not it won't work according to the theory (remove harmonics and noise-power modulation caused by quantizing).

Denote the quantizer step size Q. If the quantizer re-quantizes from 16 to 8 bits, Q is 255 lsb's referred to the quantizer's 16-bit input.

It can be proved mathematically that if dither is used with an RPDF-distribution of width Q, i.e. +/-0.5*Q, the first statistical moment of the error (error mean) is rendered conditionally independent of the input signal. Since the error mean is rendered input independent => no harmonic distortion.

It can further be proved that TPDF dither will render the first and second error moments conditionally independent of the input (mean and variance), but only if the PDF has a triangular distribution of width +/-Q. Since the error variance is also rendered input independent => no noise power modulation.

Using RPDF dither of less width than +/-0.5*Q will not make the first error moment conditionally input-independent. It will reduce distortion, but not eliminate it.

Using TPDF dither of width +/-0.5*Q will render neither the first nor the second error moment conditionally input-independent. TPDF dither of width +/-0.5*Q will in all likelyhood perform worse than RPDF dither of width +/-0.5*Q. I have not looked at the math for this case, but I'm quite sure one is better off using the right amount of RPDF than the wrong amount of TPDF.

It's much easier to get the right levels if the scaling is consistently referred to the quantizer step size. Then there is only one reference "size" to deal with. RPDF: +/-0.5*Q, TPDF: +/-Q. IIRC, if N RPDF sources of +/-0.5Q are added, the first N error moments are rendered conditionally independent of the input. But the added noise power increases and Wannamaker did listening tests showing that only the first and second error moments, mean and variance, are audible. The third and fourth statistical moments of a PDF are skew and kurtosis.
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-09-28 09:12:38
@ilo,

that sounds quite interesting, but honestly, it's a bit over the top of my head. Especially the phrase "Q is 255 lsb's referred to the quantizer's 16-bit input" just makes me confused. Would you mind posting a line of source code (doesn't matter which programming language) which does proper TPDF, so that those of us who are not mathematical masterminds can still understand how to do it correctly?

Thanks much!!! 
Title: Triangular Probability Density Function Dither
Post by: SebastianG on 2007-09-28 10:51:52
Equivalent? No, this ditherer only generates 31 possible values.
But I suppose it's good enough.

I don't understand why your solution is different mathematically.

In this case it isn't. It was not clear from your post what you were comparing. I thought you were comparing
  " (rand(256)-rand(256)) >> 4 "  versus  " rand(16)-rand(16) "
Their distributions differ.

Code: [Select]
Your original suggestion:
new_sample20 = ( (old_sample24 << 4) + rand(256) - rand(256) + 128 ) >> 8;

My modified suggestion:
new_sample20 = ( old_sample24 + ((rand(256) - rand(256)) >> 4) + 8 ) >> 4;

You're right. They are mathmatically equivalent. Pick your favorite.

Cheers!
SG
Title: Triangular Probability Density Function Dither
Post by: ilo on 2007-09-28 14:16:09
@ madshi:

I think the stuff already posted will do the trick, although the rand functions are probably only so-so PRNG's (most material on PRNG quality seems to be found in the computer security literature). I don't have any code readily available, I just tried to clarify what appears to be an issue of confusion without going much into the maths.

What I meant with the confusing (?) sentence is that one quantizer step, that is one LSB at the quantizer's (8-bit) output, equals 255 LSB's at the quantizer's (16-bit) input. And that the quantizer step size is what matters WRT to dither PDF width.
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-09-28 21:58:09
You're right. They are mathmatically equivalent. Pick your favorite.

Thanks!

I think the stuff already posted will do the trick

Ok. The bit of your post where I'm stumbling is how to correctly translate the "LSB" stuff into the right random range. Could you please check if the following is correct?

If I want to reduce bitdepth of an audio track from 24bit to 20bit, I'm doing this:

(1) add a random value of [0..15]  (where 0 and 15 are possible random values)
(2) substract a random value of [0..15]
(3) round down to 20bit

Are these the correct random ranges? Right now I'm not totally sure whether it should be 0..15 or 0..16.

although the rand functions are probably only so-so PRNG's (most material on PRNG quality seems to be found in the computer security literature).

I have some random functions from security related code, so that should be fine.
Title: Triangular Probability Density Function Dither
Post by: Nick.C on 2007-09-28 22:11:53
It should be 0..16 as that is (0.0 .. 1.0) x 2^4. If you use 15 then your amplitude is only 15/16.
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-09-28 22:18:08
Sorry, as I remember, I think you're working in Integers..... Please disregard.

Well, I could switch to floating point, but IIRC the random function I'm planning to use (which is better than the usual RTL function) is based on integer, too.
Title: Triangular Probability Density Function Dither
Post by: Nick.C on 2007-09-28 22:21:33
If you're really wanting to use integers, why not shift your 24 bit sample left 8 bits and add a random number (0.. 2^12) then subtract another? This would give 4096 x 4096 possible outcomes rather than 16 x 16. Then shift right 12 bits.
Title: Triangular Probability Density Function Dither
Post by: madshi on 2007-09-28 22:29:39
If you're really wanting to use integers, why not shift your 24 bit sample left 8 bits and add a random number (0.. 2^12) then subtract another? This would give 4096 x 4096 possible outcomes rather than 16 x 16. Then shift right 12 bits.

Yes, I was planning to do something like that (haven't decided on the details yet). I've written about [0..15] just to make things easier to understand.