TI C281x Timer Configuration

Emmanuel January 20, 2011 Coded in C for the TI F28x
**********************************************************************/
#include "DSP281x_Device.h"
/**********************************************************************
* Function: InitTimer()
*
* Description: Initialize the CPU Timer 0 at a rate of 2 Hz
**********************************************************************/
void InitTimer(void)
{	
	//CpuTimer0Regs.TIM.all = 0x0;        //Timer0 Counter Register
	
	CpuTimer0Regs.PRD.all = 0x047868C0;       //Period Register
	
	CpuTimer0Regs.TCR.all = 0x4830;       //Control Register
/*
bit 15		0:		CPU-Timer Interupt Flag
bit 14		1:		Timer Interrupt Enable
bit 13-12   0's:	Reserved
bit 11-10	10:		CPU-Timer Emulation Modes
bit 9-6		0's:	Reserved
bit 5		0:		CPU-Timer Reload bit
bit 4		0:		CPU-Timer Status Bit
bit 3-0		0's:	Reserved
*/
	
	CpuTimer0Regs.TPR.all = 0x0000;       //Prescale Register
	CpuTimer0Regs.TPRH.all = 0x0000;       //Prescale Register High
	
	
	PieCtrlRegs.PIEIER1.bit.INTx7 = 1; 		//Interruption enabled
	IER |= 0x0001;							//PIE group enabled
	
	StartCpuTimer0();//Reset of the Timer
	
}

Fixed Point FIR Filter

Shawn Stevenson December 3, 20101 comment Coded in C
#include <stdio.h>
#include <stdint.h>

//////////////////////////////////////////////////////////////
//  Filter Code Definitions
//////////////////////////////////////////////////////////////

// maximum number of inputs that can be handled
// in one function call
#define MAX_INPUT_LEN   80
// maximum length of filter than can be handled
#define MAX_FLT_LEN     63
// buffer to hold all of the input samples
#define BUFFER_LEN      (MAX_FLT_LEN - 1 + MAX_INPUT_LEN)

// array to hold input samples
static int16_t insamp[ BUFFER_LEN ];

// FIR init
void firFixedInit( void )
{
    memset( insamp, 0, sizeof( insamp ) );
}

// store new input samples
int16_t *firStoreNewSamples( int16_t *inp, int length )
{
    // put the new samples at the high end of the buffer
    memcpy( &insamp[MAX_FLT_LEN - 1], inp,
            length * sizeof(int16_t) );
    // return the location at which to apply the filtering
    return &insamp[MAX_FLT_LEN - 1];
}

// move processed samples
void firMoveProcSamples( int length )
{
    // shift input samples back in time for next time
    memmove( &insamp[0], &insamp[length],
            (MAX_FLT_LEN - 1) * sizeof(int16_t) );
}

// the FIR filter function
void firFixed( int16_t *coeffs, int16_t *input, int16_t *output,
       int length, int filterLength )
{
    int32_t acc;     // accumulator for MACs
    int16_t *coeffp; // pointer to coefficients
    int16_t *inputp; // pointer to input samples
    int n;
    int k;

    // apply the filter to each input sample
    for ( n = 0; n < length; n++ ) {
        // calculate output n
        coeffp = coeffs;
        inputp = &input[n];
        // load rounding constant
        acc = 1 << 14;
        // perform the multiply-accumulate
        for ( k = 0; k < filterLength; k++ ) {
            acc += (int32_t)(*coeffp++) * (int32_t)(*inputp--);
        }
        // saturate the result
        if ( acc > 0x3fffffff ) {
            acc = 0x3fffffff;
        } else if ( acc < -0x40000000 ) {
            acc = -0x40000000;
        }
        // convert from Q30 to Q15
        output[n] = (int16_t)(acc >> 15);
    }
}

//////////////////////////////////////////////////////////////
//  Test program
//////////////////////////////////////////////////////////////

// bandpass filter centred around 1000 Hz
// sampling rate = 8000 Hz
// gain at 1000 Hz is about 1.13

#define FILTER_LEN  63
int16_t coeffs[ FILTER_LEN ] =
{
 -1468, 1058,   594,   287,    186,  284,   485,   613,
   495,   90,  -435,  -762,   -615,   21,   821,  1269,
   982,    9, -1132, -1721,  -1296,    1,  1445,  2136,
  1570,    0, -1666, -2413,  -1735,   -2,  1770,  2512,
  1770,   -2, -1735, -2413,  -1666,    0,  1570,  2136,
  1445,    1, -1296, -1721,  -1132,    9,   982,  1269,
   821,   21,  -615,  -762,   -435,   90,   495,   613,
   485,  284,   186,   287,    594, 1058, -1468
};

// Moving average (lowpass) filter of length 8
// There is a null in the spectrum at 1000 Hz

#define FILTER_LEN_MA   8
int16_t coeffsMa[ FILTER_LEN_MA ] =
{
    32768/8, 32768/8, 32768/8, 32768/8,
    32768/8, 32768/8, 32768/8, 32768/8
};

// number of samples to read per loop
#define SAMPLES   80

int main( void )
{
    int size;
    int16_t input[SAMPLES];
    int16_t output[SAMPLES];
    int16_t *inp;
    FILE   *in_fid;
    FILE   *out_fid;
    FILE   *out_fid2;

    // open the input waveform file
    in_fid = fopen( "input.pcm", "rb" );
    if ( in_fid == 0 ) {
        printf("couldn't open input.pcm");
        return;
    }

    // open the output waveform files
    out_fid = fopen( "outputFixed.pcm", "wb" );
    if ( out_fid == 0 ) {
        printf("couldn't open outputFixed.pcm");
        return;
    }
    out_fid2 = fopen( "outputFixedMa.pcm", "wb" );
    if ( out_fid == 0 ) {
        printf("couldn't open outputFixedMa.pcm");
        return;
    }

    // initialize the filter
    firFixedInit();

    // process all of the samples
    do {
        // read samples from file
        size = fread( input, sizeof(int16_t), SAMPLES, in_fid );
        // store new samples in working array
        inp = firStoreNewSamples( input, size );

        // apply each filter
        firFixed( coeffs, inp, output, size, FILTER_LEN );
        fwrite( output, sizeof(int16_t), size, out_fid );

        firFixed( coeffsMa, inp, output, size, FILTER_LEN_MA );
        fwrite( output, sizeof(int16_t), size, out_fid2 );

        // move processed samples
        firMoveProcSamples( size );
    } while ( size != 0 );

    fclose( in_fid );
    fclose( out_fid );
    fclose( out_fid2 );

    return 0;
}

Fixed-point Math Library

Jordan November 30, 2010 Coded in C
/* **********************************************************************
 *
 * Fixed Point Math Library
 *
 * **********************************************************************
 *
 * qmath.h
 *
 * Alex Forencich
 * alex@alexelectronics.com
 *
 * Jordan Rhee
 * rhee.jordan@gmail.com
 *
 * IEEE UCSD
 * http://ieee.ucsd.edu
 *
 * **********************************************************************/

#ifndef _QMATH_H_
#define _QMATH_H_

#ifdef __cplusplus
extern "C" {
#endif

#ifndef INLINE
#ifdef _MSC_VER
#define INLINE __inline
#else
#define INLINE inline
#endif /* _MSC_VER */
#endif /* INLINE */

/*
 * Default fractional bits. This precision is used in the routines
 * and macros without a leading underscore. 
 * For example, if you are mostly working with values that come from
 * a 10-bit A/D converter, you may want to choose 21. This leaves 11
 * bits for the whole part, which will help avoid overflow in addition.
 * On ARM, bit shifts require a single cycle, so all fracbits 
 * require the same amount of time to compute and there is no advantage
 * to selecting fracbits that are a multiple of 8.
 */
#define	FIXED_FRACBITS 24

#define FIXED_RESOLUTION (1 << FIXED_FRACBITS)
#define FIXED_INT_MASK (0xffffffffL << FIXED_FRACBITS)
#define FIXED_FRAC_MASK (~FIXED_INT_MASK)

// square roots
#define FIXED_SQRT_ERR 1 << (FIXED_FRACBITS - 10)

// fixedp2a
#define FIXED_DECIMALDIGITS 6

typedef long fixedp;

// conversions for arbitrary fracbits
#define _short2q(x, fb)			((fixedp)((x) << (fb)))
#define _int2q(x, fb)			((fixedp)((x) << (fb)))
#define _long2q(x, fb)			((fixedp)((x) << (fb)))
#define _float2q(x, fb)			((fixedp)((x) * (1 << (fb))))
#define _double2q(x, fb)		((fixedp)((x) * (1 << (fb))))

// conversions for default fracbits
#define short2q(x)			_short2q(x, FIXED_FRACBITS)
#define int2q(x)			_int2q(x, FIXED_FRACBITS)
#define long2q(x)			_long2q(x, FIXED_FRACBITS)
#define float2q(x)			_float2q(x, FIXED_FRACBITS)
#define double2q(x)			_double2q(x, FIXED_FRACBITS)

// conversions for arbitrary fracbits
#define _q2short(x, fb)		((short)((x) >> (fb)))
#define _q2int(x, fb)		((int)((x) >> (fb)))
#define _q2long(x, fb)		((long)((x) >> (fb)))
#define _q2float(x, fb)		((float)(x) / (1 << (fb)))
#define _q2double(x, fb)	((double)(x) / (1 << (fb)))

// conversions for default fracbits
#define q2short(x)			_q2short(x, FIXED_FRACBITS)
#define q2int(x)			_q2int(x, FIXED_FRACBITS)
#define q2long(x)			_q2long(x, FIXED_FRACBITS)
#define q2float(x)			_q2float(x, FIXED_FRACBITS)
#define q2double(x)			_q2double(x, FIXED_FRACBITS)

// evaluates to the whole (integer) part of x
#define qipart(x)			q2long(x)

// evaluates to the fractional part of x
#define qfpart(x)			((x) & FIXED_FRAC_MASK)

/*
 * Constants
 */
#define _QPI      3.1415926535897932384626433832795
#define QPI      double2q(_QPI)
#define _Q2PI     6.283185307179586476925286766559
#define Q2PI     double2q(_Q2PI)
#define _QPIO2    1.5707963267948966192313216916398
#define QPIO2    double2q(_QPIO2)
#define _QPIO4    0.78539816339744830961566084581988
#define QPIO4    double2q(_QPIO4)
#define _QLN_E    2.71828182845904523536
#define QLN_E    double2q(_QLN_E)
#define _QLN_10   2.30258509299404568402
#define QLN_10   double2q(_QLN_10)
#define _Q1OLN_10 0.43429448190325182765
#define Q1OLN_10 double2q(_Q1OLN_10)

// Both operands in addition and subtraction must have the same fracbits.
// If you need to add or subtract fixed point numbers with different
// fracbits, then use q2q to convert each operand beforehand.
#define qadd(a, b) ((a) + (b))
#define qsub(a, b) ((a) - (b))

/**
 * q2q - convert one fixed point type to another
 * x - the fixed point number to convert
 * xFb - source fracbits
 * yFb - destination fracbits
 */
static INLINE fixedp q2q(fixedp x, int xFb, int yFb)
{
	if(xFb == yFb) {
		return x;
	} else if(xFb < yFb) {
		return x << (yFb - xFb);
	} else {
		return x >> (xFb - yFb);
	}
}

/**
 * Multiply two fixed point numbers with arbitrary fracbits
 * x - left operand
 * y - right operand
 * xFb - number of fracbits for X
 * yFb - number of fracbits for Y
 * resFb - number of fracbits for the result
 * 
 */
#define _qmul(x, y, xFb, yFb, resFb) ((fixedp)(((long long)(x) * (long long)(y)) >> ((xFb) + (yFb) - (resFb))))

/**
 * Fixed point multiply for default fracbits.
 */
#define qmul(x, y) _qmul(x, y, FIXED_FRACBITS, FIXED_FRACBITS, FIXED_FRACBITS)

/**
 * divide
 * shift into 64 bits and divide, then truncate
 */
#define _qdiv(x, y, xFb, yFb, resFb) ((fixedp)((((long long)x) << ((xFb) + (yFb) - (resFb))) / y))

/**
 * Fixed point divide for default fracbbits.
 */
#define qdiv(x, y) _qdiv(x, y, FIXED_FRACBITS, FIXED_FRACBITS, FIXED_FRACBITS)

/**
 * Invert a number (x^-1) for arbitrary fracbits
 */
#define _qinv(x, xFb, resFb) ((fixedp)((((long long)1) << (xFb + resFb)) / x))

/**
 * Invert a number with default fracbits.
 */
#define qinv(x) _qinv(x, FIXED_FRACBITS, FIXED_FRACBITS);

/**
 * Modulus. Modulus is only defined for two numbers of the same fracbits
 */
#define qmod(x, y) ((x) % (y))

/**
 * Absolute value. Works for any fracbits.
 */
#define qabs(x) (((x) < 0) ? (-x) : (x))

/**
 * Floor for arbitrary fracbits
 */
#define _qfloor(x, fb) ((x) & (0xffffffff << (fb)))

/**
 * Floor for default fracbits
 */
#define qfloor(x) _qfloor(x, FIXED_FRACBITS)

/**
 * ceil for arbitrary fracbits.
 */
static INLINE fixedp _qceil(fixedp x, int fb)
{
	// masks off fraction bits and adds one if there were some fractional bits
	fixedp f = _qfloor(x, fb);
	if (f != x) return qadd(f, _int2q(1, fb));
	return x;
}

/**
 * ceil for default fracbits
 */
#define qceil(x) _qceil(x, FIXED_FRACBITS)

/**
 * square root for default fracbits
 */
fixedp qsqrt(fixedp p_Square);

/**
 * log (base e) for default fracbits
 */
fixedp qlog( fixedp p_Base );

/**
 * log base 10 for default fracbits
 */
fixedp qlog10( fixedp p_Base );

/**
 * exp (e to the x) for default fracbits
 */
fixedp qexp(fixedp p_Base);

/**
 * pow for default fracbits
 */
fixedp qpow( fixedp p_Base, fixedp p_Power );

/**
 * sine for default fracbits
 */
fixedp qsin(fixedp theta);

/**
 * cosine for default fracbits
 */
fixedp qcos(fixedp theta);

/**
 * tangent for default fracbits
 */
fixedp qtan(fixedp theta);

/**
 * fixedp2a - converts a fixed point number with default fracbits to a string
 */
char *q2a(char *buf, fixedp n);

#ifdef __cplusplus
}	// extern C
#endif

#endif /* _QMATH_H_ */

/* **********************************************************************
 *
 * Fixed Point Math Library
 *
 * **********************************************************************
 *
 * qmath.c
 *
 * Alex Forencich
 * alex@alexelectronics.com
 *
 * Jordan Rhee
 * rhee.jordan@gmail.com
 *
 * IEEE UCSD
 * http://ieee.ucsd.edu
 *
 * **********************************************************************/

#include "qmath.h"

/**
 * square root
 */
fixedp qsqrt(fixedp p_Square)
{
	fixedp   res;
	fixedp   delta;
	fixedp   maxError;

	if ( p_Square <= 0 )
		return 0;

	/* start at half */
	res = (p_Square >> 1);

	/* determine allowable error */
	maxError =  qmul(p_Square, FIXED_SQRT_ERR);

	do
	{
		delta =  (qmul( res, res ) - p_Square);
		res -=  qdiv(delta, ( res << 1 ));
	}
	while ( delta > maxError || delta < -maxError );

	return res;
}

/**
 * log (base e)
 */
fixedp qlog( fixedp p_Base )
{
    fixedp w = 0;
	fixedp y = 0;
	fixedp z = 0;
	fixedp num = int2q(1);
	fixedp dec = 0;

	if ( p_Base == int2q(1) )
		return 0;

	if ( p_Base == 0 )
		return 0xffffffff;

	for ( dec=0 ; qabs( p_Base ) >= int2q(2) ; dec += int2q(1) )
		p_Base = qdiv(p_Base, QLN_E);

	p_Base -= int2q(1);
	z = p_Base;
	y = p_Base;
	w = int2q(1);

	while ( y != y + w )
	{
		z = 0 - qmul( z , p_Base );
		num += int2q(1);
		w = qdiv( z , num );
		y += w;
	}

	return y + dec;
}

/**
 * log base 10
 */
fixedp qlog10( fixedp p_Base )
{
    // ln(p_Base)/ln(10)
    // more accurately, ln(p_Base) * (1/ln(10))
    return qmul(qlog(p_Base), Q1OLN_10);
}

/**
 * exp (e to the x)
 */
fixedp qexp(fixedp p_Base)
{
	fixedp w;
	fixedp y;
	fixedp num;

	for ( w=int2q(1), y=int2q(1), num=int2q(1) ; y != y+w ; num += int2q(1) )
	{
		w = qmul(w, qdiv(p_Base, num));
		y += w;
	}

	return y;
}

/**
 * pow
 */
fixedp qpow( fixedp p_Base, fixedp p_Power )
{
	if ( p_Base < 0 && qmod(p_Power, int2q(2)) != 0 )
		return - qexp( qmul(p_Power, qlog( -p_Base )) );
	else
		return qexp( qmul(p_Power, qlog(qabs( p_Base ))) );
}

/**
 * sinx, internal sine function
 */
static fixedp sinx(fixedp x)
{
	fixedp xpwr;
	long xftl;
	fixedp xresult;
	short positive;
	int i;

	xresult = 0;
	xpwr = x;
	xftl = 1;
	positive = -1;

	// Note: 12! largest for long
	for (i = 1; i < 7; i+=2)
	{
		if ( positive )
			xresult += qdiv(xpwr, long2q(xftl));
		else
			xresult -= qdiv(xpwr, long2q(xftl));

		xpwr = qmul(x, xpwr);
		xpwr = qmul(x, xpwr);
		xftl *= i+1;
		xftl *= i+2;
		positive = !positive;
	}

	return xresult;
}

/**
 * sine
 */
fixedp qsin(fixedp theta)
{
	fixedp xresult;
	short bBottom = 0;
	//static fixed xPI = XPI;
	//static fixed x2PI = X2PI;
	//static fixed xPIO2 = XPIO2;

	fixedp x = qmod(theta, Q2PI);
	if ( x < 0 )
		x += Q2PI;

	if ( x > QPI )
	{
		bBottom = -1;
		x -= QPI;
	}

	if ( x <= QPIO2 )
		xresult = sinx(x);
	else
		xresult = sinx(QPIO2-(x-QPIO2));

	if ( bBottom )
		return -xresult;

	return xresult;
}

/**
 * cosine
 */
fixedp qcos(fixedp theta)
{
	return qsin(theta + QPIO2);
}

/**
 * tangent
 */
fixedp qtan(fixedp theta)
{
	return qdiv(qsin(theta), qcos(theta));
}

/**
 * q2a - converts a fixed point number to a string
 */
char *q2a(char *buf, fixedp n)
{
	long ipart = qipart(n);
	long fpart = qfpart(n);
	long intdigits = 0;

	int i = 0;
	int j = 0;
	int d = 0;

	int offset = 0;

	long v;
	long t;
	long st = 0;

	if (n != 0)
	{
		intdigits = qipart(qceil(qlog10(qabs(n))));
	}

	if (intdigits < 1) intdigits = 1;

	offset = intdigits - 1;

	if (n < 0)
	{
		buf[0] = '-';
		offset++;
		n = -n;
		ipart = -ipart;
		fpart = -fpart;
	}

	// integer portion

	for (i = 0; i < intdigits; i++)
	{
		j = offset - i;
		d = ipart % 10;
		ipart = ipart / 10;
		buf[j] = '0' + d;
	}

	// decimal point

	buf[offset + 1] = '.';

	// fractional portion

	v = 5;
	t = FIXED_RESOLUTION >> 1;

	for (i = 0; i < FIXED_DECIMALDIGITS - 1; i++)
	{
		v = (v << 1) + (v << 3);
	}

	for (i = 0; i < FIXED_FRACBITS; i++)
	{
		if (fpart & t)
		{
			st += v;
		}
		v = v >> 1;
		t = t >> 1;
	}

	offset += FIXED_DECIMALDIGITS + 1;

	for (i = 0; i < FIXED_DECIMALDIGITS; i++)
	{
		j = offset - i;
		d = st % 10;
		st = st / 10;
		buf[j] = '0' + d;
	}

	// ending zero
	buf[offset + 1] = '\0';

	return buf;
}

Constant complexity rectangular QAM demodulator

Vashishth November 14, 2010 Coded in C for the TI C67x
% N is the size of the constellation.
% v is the input data.
% For details email me.
void function_qam()
{

co=0;
 m=0;

for(q=0; q<N; q++)

        {

 a=v[m];// a holds the real part
 b=v[m+1];// b holds the imaginary part

 d=a-onern[max];  %onern stores the negative real axis points and onein stores the negative imag axis points. eg for 256 QAM, each will store 0 to -8 as an array.
 l=d;         //l stores the distance
 s=(d-l);
 if(l<max-1) % max is the maximum value that the 1-d coordinate can take.
       {

if(d>0){
 if(s<=.5)
       {
 hi=max-l;
 flagtwo=1;
       }
 else
 {
 hi=max-l-1;
 flagtwo=1;
 }
      }
	  else
	  {
	  hi=max;
	  flagtwo=1;
	  }
        
      }

 if(l==max-1)
 {
 hi=1;
 flagtwo=1;
 }
 if(l==max)//
 {
 flagone=1;
 hi=1;
 } 

 if(l>max)
        {
		if(d<2*max)
		{

 if(s<=.5)
 {
 hi=l-max;
 flagone=1;
 }
 else
 {
 hi=l-max+1;
 flagone=1;
 }
        }
		else
		{
		hi=max;
		flagone=1;
		}
       
          
        }

 de=b-onein[max];
 le=de;         //l stores the distance
 se=(de-le);

 if(le<max-1)
      {

	  if(de>0)
	  {
 if(se<=.5)
 {
 hm=max-le;
 flagfour=1;
 }
 else
 {
 hm=max-le-1;
 flagfour=1;
 }
      
      }
	  else
	  {
	  hm=max;
	  flagfour=1;
      }
      
      
      }

 if(le==max-1)
 {
 hm=1;
 flagfour=1;
 }
 if(le==max)
 {
 flagthree=1;
 hm=1;
 }

 if(le>max)
     {

if(de<2*max){

 if(se<=.5)
 {
 hm=le-max;
 flagthree=1;
 }
 else
 {
 hm=le-max+1;
 flagthree=1;
 }
    }
	else
	{
	hm=max;
	flagthree=1;
	}
    
       
    
    }

 if(flagone==1)
 {
  vv[m]=hi;  // now v[m] holds one x coordinate of the qam mapping and v[m+1] holds the y coordinate
 }
 
 else
 {
 vv[m]= 100-hi;
 }

 
 if(flagthree==1)
  {
 vv[m+1]=hm;  
  }
		else
		{
 vv[m+1]= 100-hm;
        }

flagone=0;
flagtwo=0;
flagthree=0;
flagfour=0;
        r=0;
        
        
          
           output[co]= valuetable[ vv[m] ][ vv[m+1] ] ;
       
       
          
          
                        
      m = m+ 2;
	  
	  co = co+ 1;
                
                
                 }

  for(t=0;t<(N/2);t++)
  {
   p[t] = (output[t]);
 
  }

 

}

Heuristic multiuser waterfilling algorithm

Markus Nentwig November 4, 2010 Coded in C
/* **********************************************************
 * Purpose::
 * heuristic multi-user waterfilling algorithm implementation
 * example invocation included; compile and run with
 * gcc -Wall (thisFile.c); ./a.out
 *
 * PLEASE NOTE:
 * This is a quick rewrite that hasn't been extensively tested.
 * Please verify independently that the code does what it says.
 */

/* **********************************************************
 * Header file
 * **********************************************************/

#ifndef WATERFILL_H
#define WATERFILL_H
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

/* **********************************************************
 * Waterfilling algorithm data structure
 * In C++ this would become an object. 
 * Usage:
 * wfalg_new(...); 
 * while (need to invoke it multiple times on changing data){
 *   wfalg_run(...);
 *   (process results)
 * }
 * wfalg_free(...); now the results become invalid  
 * **********************************************************/
typedef struct wfalg_t_ wfalg_t;

/* Purpose: 
 * Create data structure for multiuser waterfiller "object"
 * Use for multiple invocations on varying data
 * 
 * Parameters:
 * nRB: Number of "resource blocks" (frequency bins)
 * 
 * nUser: number of simultaneous transmissions to allocate
 * 
 * pmode: 0 conventional multi-user waterfilling: Per-resource power based on 
 * channel quality estimate
 *        otherwise: select resources based on channel quality, but distribute the
 * per-user power evenly
 */
wfalg_t* wfalg_new(int /*nRB*/, int /*nUser*/, int /*mode*/);

/* Purpose:
 * Invoke multi-user waterfilling for the following parameters:
 * Rmax: maximum number of RBs that may be allocated to each individual user.
 *    in "ideal" waterfilling, a single user with a very good channel hogs up
 *    most of the resources. While this (ideally) maximizes sum throughput, there are
 *    usually other criteria that are equally or more important.
 *    The caller can limit the number of resources for a particular user, and thus
 *    control the "fairness" of allocation.
 *    Set Rmax >= nRB for each user to disable this limitation.
 * 
 * SNR_threshold: Do not allocate a resource if the signal-to-noise ratio falls below the
 *    threshold. For example, even heavily coded QPSK doesn't lead to any meaningful
 *    throughput when the signal-to-noise ratio is below -3 dB
 *    if so, choose SNR_threshold=10*log10(-3/10) = 0.5
 * 
 * Tinv: inverse of channel quality, noise-to-signal ratio N/S where "signal" includes
 *    the channel |H(f)| with f the frequency of a resource.
 *    Matrix: first user resource 0..nRB-1, second user resources 0..nRB-1, last user
 * 
 * porder: Process users in the given order (array of user indices 0..nUser-1 with length nUser)
 *    The order is important in pathological cases, such as "more users than RBs."
 *    If so, the scheduling decision is effectively made by the caller, via the processing order:
 *    first come, first served, and the later ones get nothing. 
 * 
 * After execution, 
 *   - resultAlloc points to a size-nRB array containing the index of the allocated user for each resource block.
     - resultPower points to a size-nRB array with the power allocated to a resource.
 * All powers for user j sum up to pUser[j] 
 * The number of resources where resultAlloc==j is <= Rmax[j].
 * There is only one storage space per wfalg_t "object". Earlier results become invalid with
 * the next invocation. 
 */
void wfalg_run(wfalg_t* /*obj*/, const double* /*pUser*/, const int* /*Rmax*/, const int* /*porder*/, const double* /*TinvMatrix*/, double /*SNR_threshold*/, int** /*resultAlloc*/, double** /*resultPower*/);

/* Purpose: 
 * Release allocated memory. 
 * obj becomes invalid. 
 * any space provided by wfalg_run becomes invalid.
 */
void wfalg_free(wfalg_t* /* obj */);
#endif

/* **********************************************************
 * .c file
 * **********************************************************/

/* Data structure for multiple invocations without unnecessary malloc / free */
struct wfalg_t_ {
  /* parameters */
  int nRB; 
  int nUser;
  
  /* Storage space for results */
  int* RB_alloc;
  double* RB_power;
  
  /* Internal temporary storage space
   * all Tinv values for the single user that is
   * processed by waterfill() */
  double* temp_singleUserTinv;
  
  /* internal temporary storage: How many resources are allocated per user? */
  int* temp_userNResources;
  int* order;
  
  /* Mode switch parameter */
  int mode;  
};

wfalg_t* wfalg_new(int nRB, int nUser, int mode){

  wfalg_t* obj=(wfalg_t*)malloc(sizeof(wfalg_t)); assert(obj);  
  obj->nUser=nUser;
  obj->nRB=nRB;
  obj->mode=mode;

  obj->RB_alloc=(int*)malloc(sizeof(int) * nRB); assert(obj->RB_alloc);
  obj->RB_power=(double*)malloc(sizeof(double) * nRB); assert(obj->RB_power);
  obj->temp_singleUserTinv=(double*)malloc(sizeof(double) * nRB); assert(obj->temp_singleUserTinv);
  obj->temp_userNResources=(int*)malloc(sizeof(int) * nUser); assert(obj->temp_userNResources);
  memset((void*)obj->RB_power, 0, nRB * sizeof(double));
  
  return obj;
}

void wfalg_free(wfalg_t* obj){
  free(obj->RB_alloc);
  free(obj->RB_power);
  free(obj->temp_singleUserTinv);
  free(obj->temp_userNResources);
  free(obj);
}

/* ************************************************************************************
 * Conventional multi-user waterfilling on the set of resources where 
 * RB_alloc[]==userindex
 * expects temp_singleUserTinv to be filled with the Tinv for the allocating user!
 * ************************************************************************************/
static void waterfill(wfalg_t* obj, int userindex, double pUser){
  const int nRB=obj->nRB;

  const double E0=pUser;
  const double threshold=1e-12* E0;
  
  /* ************************************************************************************
   * Count resource allocated to this user
   * ************************************************************************************/
  int nRB_user=0;
  int j_RB;
  for(j_RB=0; j_RB < nRB; ++j_RB){
    if (*(obj->RB_alloc+j_RB)==userindex){
      ++nRB_user;
    }
  }
  if (nRB_user == 0){
    /* no resources allocated - can't waterfill */
    return;
  }
  
  double E=E0;
  double waterlevel=0;       
  while (E > threshold){
    /* ************************************************************************************
     * Distribute remaining energy evenly over all RBs
     * since some of them have greater-than-zero Tinv, this approximation will always stay
     * below target (standard waterfilling algorithm)
     * ************************************************************************************/
    E *= 0.999;
    waterlevel += E/(double)nRB_user;
    
    /* ************************************************************************************
     * Determine energy that remains with current allocation
     * ************************************************************************************/
    E=E0;

    /* Note: temp_singleUserTinv contains the Tinv for the user who allocates the RB.
     * This avoids many repeated table lookups from the nUser*nRB Tinv matrix. */
    double* pTinv=obj->temp_singleUserTinv;

    double* pRB_power=obj->RB_power;
    int* palloc=obj->RB_alloc;

    int j_RB;
    for(j_RB=0; j_RB < nRB; ++j_RB){     
      int alloc=*(palloc++);
      double Tinv=*(pTinv++);
      
      /* resource is allocated to current user */
      if (alloc==userindex){
	
	/* determine actual per-resource energy */
	double d=waterlevel - Tinv;
	d=(d > 0.0 ? d : 0.0);
	E -= d;
	*(pRB_power)=d;
      } /* if allocated */
      
      ++pRB_power;

    } /* for RB */
  } /* while energy remains */

  assert(E >= 0.0);
}

/* picks the best unallocated RB for the given user */
static int find_best_RB(wfalg_t* obj, int userindex, const double* thisUserTinv){
  /* find RB with lowest Tinv for this user */
  int i_RB;
  int bestRB_index=-1;
  double bestRB_Tinv=9e99;
  int valid=0;
  const double* pTinv=thisUserTinv;
  for (i_RB=0; i_RB < obj->nRB; ++i_RB){
    double Tinv=*(pTinv++);
    int alloc=*(obj->RB_alloc+i_RB);
    if ((alloc < 0) && (Tinv < bestRB_Tinv)){
      bestRB_index=i_RB;
      bestRB_Tinv=Tinv;
      valid=1;
    }    
  }
  
  if (!valid){
    bestRB_index=-1;
  }

  return bestRB_index; /* -1 means: none */
}

static int try_alloc_one_RB(wfalg_t* obj, int userindex, double pThisUser, const double* thisUserTinv, double SNR_threshold){
  int RBindex=find_best_RB(obj, userindex, thisUserTinv);
  if (RBindex >= 0){
    
    /* channel quality on resource RBindex */
    double Tinv=*(thisUserTinv+RBindex);
    
    /* allocate RB, at least temporarily */
    *(obj->RB_alloc+RBindex)=userindex;

    double Tinv2=Tinv;
    if (obj->mode){
      /* Equal power allocation - disregard "floor" level in waterfilling 
       * We'll use the original Tinv for the SNR check later */
      Tinv2=0.0;
    }
    
    *(obj->temp_singleUserTinv+RBindex) = Tinv2;

    waterfill(obj, userindex, pThisUser);

    /* check SNR of last RB */
    double P=*(obj->RB_power + RBindex);
    double SNR=P/Tinv;
    if (SNR >= SNR_threshold){
      return 1; /* success */
    } else {
      /* too low power to be useful. 
       * undo allocation. */
      *(obj->RB_alloc+RBindex)=-1;      
    }
  }
  return 0; /* failure */
}

static void zero_unallocated_RBs(const wfalg_t* obj){
  int* ap=obj->RB_alloc;  
  double* pp=obj->RB_power;
  int iRB;
  for (iRB=0; iRB < obj->nRB; ++iRB){
    *pp=(*ap >= 0 ? *pp : 0.0);
    ++pp; 
    ++ap;
  }
}

void wfalg_run(wfalg_t* obj, const double* pUser, const int* Rmax, const int* porder, const double* TinvMatrix, double SNR_threshold, int** resultAlloc, double** resultPower){

  /* Deallocate all RBs */
  int* p=obj->RB_alloc;
  int i_RB;  
  for (i_RB=0; i_RB < obj->nRB; ++i_RB){
    *(p++) = -1;
  }
  memset((void*)obj->temp_userNResources, 0, obj->nUser * sizeof(int));

  int nAllocResourcesThisRound=-1; /* any nonzero value to enter the loop */

  /* Repeat until we fail to allocate another resource */
  while (nAllocResourcesThisRound != 0){
    nAllocResourcesThisRound=0;

    /* Iterate over all users ... */
    int jj_user;
    for (jj_user=0; jj_user < obj->nUser; ++jj_user){
      /* ... in the specified order */
      int j_user=*(porder+jj_user);

      /* power budget of current user */
      double p_jUser=*(pUser+j_user);
      
      /* Are we allowed to add another resource to this user? (Rmax constraint) */
      if (*(obj->temp_userNResources+j_user) < *(Rmax+j_user)){
	
	/* Look up the channel quality array for j_user */
	const double* thisUserTinv=TinvMatrix + j_user * obj->nRB;
	
	/* Try to allocate one more resource to this user */
	if (try_alloc_one_RB(obj, j_user, p_jUser, thisUserTinv, SNR_threshold)){
	  /* Successfully allocated */
	  ++ *(obj->temp_userNResources+j_user); /* count resources allocated to this user */
	  ++nAllocResourcesThisRound; /* continue iterating */
	} else {
	  /* this user can't allocate any more resources
	   * There is no need to try again in future iterations, 
	   * disregard this user by making the Rmax test fail 
	   *
	   * note, power allocation is not valid at this point */
	  *(obj->temp_userNResources+j_user) = *(Rmax+j_user);
	}
      }      
    } /* for j_user */
  } /* while allocations succeed */
  
  /* The previous step fails exactly once per user, making the 
   * power allocation invalid. 
   *
   * Recalculate.
   * This is single-user waterfilling without any interaction, therefore order does not matter 
   * Note that waterfill() requires a valid temp_singleUserTinv (which is the case at this point): 
   * For each resource, it contains the Tinv of the allocating user
   */
  int j_user;
  for (j_user=0; j_user < obj->nUser; ++j_user){
    double p_jUser=*(pUser+j_user);    
    waterfill(obj, j_user, p_jUser);
  }
  
  /* Set zero power allocation for resources that aren't allocated to any user */
  zero_unallocated_RBs(obj);
  
  *resultAlloc=obj->RB_alloc;
  *resultPower=obj->RB_power;
}

/* **********************************************************
 * Example use (still .c file)
 * **********************************************************/
#if 1
int main(void){
  const int nUser=5;
  const int nRB=40;

  /* allocate and create random multi-user channel data */
  double* Tinv=(double*)malloc(nUser*nRB*sizeof(double));
  int i; int j;
  double* p=Tinv;
  for (i=0; i < nUser; ++i){
    for (j=0; j < nRB; ++j){
      *(p++)=(double)random() / (double)RAND_MAX;
    }
  }

  /* power per user */
  double pUser[]={1, 2, 3, 4, 5};
   
  /* processing order */
  int order[]={0, 1, 2, 3, 4};
  
  /* maximum number of resources per user */
  const int RMax[]={nRB, nRB, nRB, nRB, nRB};

  /* create waterfiller "object" */
  wfalg_t* wfalg=wfalg_new(nRB, nUser, /* mode */0);

  /* Invoke waterfilling */
  int* RB_alloc;
  double* RB_power;  
  wfalg_run(wfalg, pUser, RMax, order, Tinv, /* SNR_threshold */1.0, &RB_alloc, &RB_power);
  
  /* print result */
  int j_user; int i_RB;
  for (j_user=0; j_user  < nUser; ++j_user){
    printf("user %i ", j_user);
    double sum=0;
    for (i_RB=0; i_RB < nRB; ++i_RB){
      if (*(RB_alloc+i_RB)==j_user){
	double p=*(RB_power+i_RB);
	printf("%i=%lf ", i_RB, p);
	sum += p;
      }
    }
    printf("sum=%lf\n", sum);
  }
  
  /* clean up */
  wfalg_free(wfalg);
  free(Tinv);

  return EXIT_SUCCESS;
}
#endif

Using EMIF expansion port as digital output

David Valencia October 27, 20107 comments Coded in C for the TI C67x
/*      David Valencia at DSPRelated.com

        This example shows how to use the External Memory Interface
        expansion port of Spectrum Digital DSK6713 card as
        a set of digital imputs
        The use of buffer ICs is mandatory, as these pins can't deliver
        too much current        */

#define OUTPUT 0xA0000000  // EMIF ADDRESS (updated 3/11/2010)

int *output = (int*)OUTPUT; // Declare a pointer to EMIF's address

void main()
{
        // To see how the value is written to the EMIF pins,
        // you may prefer to run the program step-by-step

        // Write a 32-bit digital value to the pins
        *output = 0x48120A00; // Test value
}

Taylor-Weighted Window Generator

Eric Jacobsen October 27, 20104 comments Coded in C
/*

	11/8/89		Eric Jacobsen

	Generates Taylor weighting coefficients for a vector
	of arbitrary length n. The user supplies n' (nprime),
	the number of terms used in the calculations, and A,
	the peak sidelobe ratio in db. N must also be supplied
	by the user.

	This version (HTaylor) scales the output data by a
	user supplied integer. The output is rounded to the
	nearest integer.

*/
#include <stdio.h>
#include <math.h>

void main(argc,argv)

int argc;
char *argv[];

{

 char outfile[30],
  *help="\n USE: Taylor outfile N A n' s\n\n © 11/89 Eric Jacobsen\n\n N = # pts, A = PSLR, n' = # terms, s = integer scale factor.\n\n";

 float Fm,k,sigma,x,A,dprod,nprod,scl;
 int i,m,N,nprime,p,scale,*w,*h;
 extern double cos(),log(),pow();
 FILE *fopen(),*fp;

 if(argv[1][0]=='?'){
  puts(help);
  exit(0);
  }

 if(argc<2){
  printf("\n Enter name of output file: ");
  scanf("%s",outfile);
  }
 else strcpy(outfile,argv[1]);

 if(argc<3){
  printf("\n Enter the number of points: ");
  scanf("%d",&N);
  }
 else N=atoi(argv[2]);

 if(argc<4){
  printf("\n Enter PSLR (A) in db: ");
  scanf("%f",&A);
  }
 else A=atof(argv[3]);

 A=abs(A);

 if(argc<5){
  printf("\n Enter the number of terms (n'): ");
  scanf("%d",&nprime);
  }
 else nprime=atoi(argv[4]);

 if(argc<6){
  printf("\n Enter the scale factor: ");
  scanf("%d",&scale);
  }
 else scale=atoi(argv[5]);

 if(!(fp=fopen(outfile,"w"))){
  printf("\n\n Can't open %s.\n\n",outfile);
  exit(2);
  }

 k=0.885*(1.0+((A-13.0)/65.0));
 x=pow(10.0,A/20.0);
 A=log(x+sqrt((x*x)-1))/PI;

 sigma=(float)nprime/sqrt((A*A)+(((float)nprime)-0.5)*(((float)nprime)-0.5));

 printf("\n Sigma = %f, k = %f\n\n Calculating...",sigma,k);

 Fm=0.0;

 for(m=1;m<nprime;m++){
  dprod=nprod=1.0;
  for(p=1;p<nprime;p++){
   if(p!=m)dprod*=1.0-((float)(m*m)/(float)(p*p));
   nprod*=1.0-(float)(m*m)/(((A*A)+(((float)p)-0.5)*(((float)p)-0.5))*sigma*sigma);
   }
  Fm+=(float)(m % 2 ? 1:-1)*nprod/dprod;
  }

 if(!(w=h=(int *)AllocMem(4*N,0))){
  puts("\n\n ** Insufficient Memory **\n\n");
  exit(12);
  }

 scl=(float)scale;

 for(i=0;i<N;i++)
  *w++=(int)(scl*(1.0+(Fm*(-cos(2.0*PI*(float)i/(float)N))))+0.5);

 printf("done.\n");
 printf("\n Writing output file...");

 w=h;

 for(i=0;i<N;i++)fprintf(fp,"	DC.W	%d\n",*w++);

 printf("done.\n\n");

 FreeMem(h,4*N);
 fclose(fp);

}