cancel
Showing results for 
Search instead for 
Did you mean: 

Saturating arithmetic

ccowdery9
Associate III
Posted on March 30, 2009 at 14:43

Saturating arithmetic

10 REPLIES 10
ccowdery9
Associate III
Posted on May 17, 2011 at 13:07

All,

I understand the Cortex M3 core has some saturated arithmetic instructions.

Is it possible to get GCC to use them, to avoid having to use constructions like this:

Code:

c=a-b;

if (c<0) c=0;

I'm going to be playing two audio streams simultaneously, and when I combine the source data I don't want any overflow. And it needs to be fast.

Any comments?

Thanks,

Chris.

brunoalltest
Associate II
Posted on May 17, 2011 at 13:07

I don´t know the answer, but once I´ve seen a

http://forum.sparkfun.com/viewtopic.php?t=12018&start=0&postdays=0&postorder=asc&highlight=instruction

. Hope it helps.

st3
Associate II
Posted on May 17, 2011 at 13:07

Quote:

I´ve seen a

http://forum.sparkfun.com/viewtopic.php?t=12018&start=0&postdays=0&postorder=asc&highlight=instruction

.

That just seems to be about detecting overflow?

In this case, surely, just making c unsigned will suffice - won't it? :-?

picguy
Associate II
Posted on May 17, 2011 at 13:07

Think this way: 0V =0x80, min (i.e. negative) volts = 0x00, max volts = 0xFF. Then c=(a-b)/2. Do the same trick with a+b. DC offset out of your DAC goes away with one capacitor. Thinking this way is better than saturating arithmetic. (Which I believe Cortex-M3 has but I am not looking at my ref material at the moment.)

Does anybody have any idea how to combine (conference call style) 3 to perhaps 10 digital channels? I’m thinking (a+b+c+d+e)/5 would work but with only one speaker the levels would be lower than desired.

ccowdery9
Associate III
Posted on May 17, 2011 at 13:07

Ta for comments so far.

It seems there isn't an easy way...

I could do c=a+b/2, but then as you say, a single channel would be 1/2 amplitude.

I think I'll just use 32bits for storing the 16bit results, then I haven't lost any accuracy, and can then use compares to limit the range. Probably slow, but it ought to work OK......

Chris.

picguy
Associate II
Posted on May 17, 2011 at 13:07

My 0x00 to0x80 to 0xFF might have been better stated with 3 hex digits to match the STM32 12-bit ADC and DAC.

But Chris, range limiting like saturating math clips waveforms. Think of two nice sine waves 400Hz and 410Hz. (It will sound bad to the ear.) Each goes +/- 1 volt. Out of phase you get a dozen milliseconds with very low amplitude. In phase you get +/- 2 volts. Clip the in phase signal and the dissonance will sound much worse.

Here is something I have been thinking about but have not implemented because the guy with the money had much of in AIG. Form c=a+b then map 0x0000 to 0x1FFF into 0x0800 to 0x17FF. Gradual range compression. Zero to small changes near 0x1000 with larger changes closer to the endpoints. (Table lookup & interpolation would work but I would recommend math. Something like sqrt might work. Cortex @72MHz is good at simple integer math.) Then subtract 0x0800 to get 0x000 to FFF. The distortion this makes may be small enough to sound much like the original 400Hz + 410Hz.

A major cord such as CEG and next C has frequency ratios 4:5:6:8. Try a 4:5 ratio if you test this with your ear. A above middle C is 440Hz The C# above that is 550Hz.

Unrelated but possibly useful is my FIFO page:

http://www.hmtown.com/fifo.htm

Dig around a bit and you may be able to let me know if my thoughts are useful.

obtronix
Associate II
Posted on May 17, 2011 at 13:07

Quote:

On 26-03-2009 at 13:55, Anonymous wrote:

All,

I understand the Cortex M3 core has some saturated arithmetic instructions.

Is it possible to get GCC to use them, to avoid having to use constructions like this:

Code:

c=a-b;

if (c<0) c=0;

I'm going to be playing two audio streams simultaneously, and when I combine the source data I don't want any overflow. And it needs to be fast.

Any comments?

Thanks,

Chris.

No cortex doesn't really support saturation logic, a real DSP with saturation logic usually has a extended range intermediate register (40 bits or so) so that intermediate calculations don't saturate, just the final result, you can turn it on or off with a bit so it's done automatically.

The cortex M3 has SSAT and USAT instructions that are capable of converting 32 bits values to smaller sizes with saturation, a sort of poor man's saturation logic. Cortex's bigger brothers, like ARM926, has the real thing, as does most TI DSP's and even microchip's dsPIC, I think.

andreas2
Associate II
Posted on May 17, 2011 at 13:07

Well, any 32-bit register would be an ''extended range intermediate register'' when the source data is no more than the 24 bits or so this guy probably needs for his audio stream...

ccowdery9
Associate III
Posted on May 17, 2011 at 13:07

My simple saturation code

Code:

if (samples[0]<DAC_MIN) samples[0]=DAC_MIN;

if (samples[0]>DAC_MAX) samples[0]=DAC_MAX;

dac_buffer[0]=(s16)samples[0];

where samples[] is 32bit signed and dac_buffer[] is 16bit signed.

I realise that two full-scale signals will sound awful, and it would be better to have a non-linear compression as the signal approaches full scale.

But this is an experimental board, which will never see production in its final form (or anywhere near), so if it sounds awful, then the volume level will have to be turned down on one channel!

Chris.