⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 transmit.c

📁 DSP 5409 plc应用程序,调试通过,是用在电力线通讯上的演示程序.
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================================
// Filename:		transmit.c
//
// Description:		Functions related to the data transmition of a 	power line modem.
//
// Copyright (C) 2001 - 2003 Texas Instruments Incorporated
// Texas Instruments Proprietary Information
// Use subject to terms and conditions of TI Software License Agreement
//
// Revision History:
//==========================================================================================

#include "ofdm_modem.h"

#define WINDOW_SCALE	8


// When RAMP_TEST is defined, we replace the real preamble and data with a ramp
// waveform to make DMA debug easier
//#define		RAMP_TEST	

#if COMPILE_MODE == DSP_COMPILE
	#include "intr.h"		// Needed for interrupt enable/disable macros
#else						// MEX:  Fake macros for interrupt enable/disable
	#define	INTR_ENABLE(x)	 
	#define INTR_DISABLE(x)
#endif


// When PEAK_DEBUG is TRUE, we spit out trace messages with the peak amplitude in each transmit frame
#define	PEAK_DEBUG	TRUE
//#define	PEAK_DEBUG	FALSE

// When PEAK_DEBUG is TRUE, scale the transmitted waveform to have constant peaks, boosting average
#define	ADJUST_TX_PEAKS	TRUE
//#define	ADJUST_TX_PEAKS	FALSE


//==========================================================================================
// global var for this file
//==========================================================================================
	static const iCplx 	complexMap[4] = 
					{	1,  0,
						0,  1,
					   -1,  0,
						0, -1  };

//--- Matlab code to generate FrameWindow values: -----------------------
// wLen = 16; wScale=8; win = round((.5 - .5*cos([0:wLen-1]/wLen*pi))*2^wScale); sprintf('%5.0f,',win)
static const i16 FrameWindow[WINDOW_LEN] =
//		{ 256,	256,  256,  256,  256,  256,  256,  256,  256,  256,  256,  256,  256,  256,  256,  256 }; // Unity gain throughout. Zero postfix.
		{   0,    2,   10,   22,   37,   57,   79,  103,  128,  153,  177,  199,  219,  234,  246,  254 }; // Raised cosine window
//		{   0,    0,    0,    0,    0,    0,    0,    0,  256,  256,  256,  256,  256,  256,  256,  256 }; // Abrupt cutoff


//==========================================================================================
// Function:		initCRCtable()
//
// Description: 	Init CRC-16 table
//
// Revision History:
//==========================================================================================
void initCRCtable(u16 *CRCtable)
{
	u16			reg;		// working register
	i16			n, b;		// counters

	#if COMPILE_MODE == MEX_COMPILE
		mexPrintf("CRC table init.\n");
	#endif
	reg = 0;
    for( n = 0; n < 256; n++ )
	{
        reg = n << 8;
        for( b = 0; b < 8; b++ )
		{
            if( reg & CRC_TOPBIT )
				reg = (reg << 1) ^ CRC_POLYNOMIAL;
			else
				reg <<= 1;
        }
        *CRCtable++ = reg;
    }    
	return;
}


//==========================================================================================
// Function:		viterbiZero()
//
// Description: 	Force the end of the user data buffer to zero so that the receiving
//					trelis returnes to zero at the end of the message.
//
// Revision History:
//==========================================================================================
void viterbiZero(u16 *pUserData)
{						   // zeros for Viterbi	     zero rest of buffer
	i16			zeroBits =  (2*VITERBI_K + 1) + ( DATA_BUFFER_LEN*WORD_LEN - NUM_SYMBOLS);

	pUserData += (DATA_BUFFER_LEN - 1);			// point to last word in data buffer
	while( zeroBits >= WORD_LEN )
	{
		*pUserData = 0;							// zero this word
		pUserData--;							// point to previous word
		zeroBits -= WORD_LEN;
		//mexPrintf("zeroBits loop = %d\n", zeroBits);
	}

	*pUserData >>= zeroBits;					// zero final bits
	*pUserData <<= zeroBits;
	return;
}


//==========================================================================================
// Function:		appendParityCheckBytes()
//
// Description: 	Calculate parity check bytes for outer RS code and append.
//					Data come in as 16 bit words. Take each byte and calc parity bytes
//					Calc CRC on whole words.
//
// Revision History:
//==========================================================================================
void appendParityCheckBytes(u16 *pUserData, i16 numWords)
{
	i16				wordCount = 0;
	u16				dataByte;
	u16				reg;
	u16				*parity;

	//---- init parity table ----------------------
	if( CRCtableArray[1] == 0 )
		initCRCtable( CRCtableArray );

	//---- point to appended parity part of data buffer and zero out ---
	parity = pUserData + numWords;
	memset(parity, 0, (DATA_BUFFER_LEN-numWords)*sizeof(u16));	
	
	/*--------------------------------------------------------------
	Read through the data to generate the CRC word.
	Append the CRC word at the end of the user data in the data buffer
	--------------------------------------------------------------*/
	reg = CRC_REG_INIT;
	for( wordCount = 0; wordCount < (numWords+1); wordCount++ )
	{
		dataByte = (*pUserData) >> BYTE_LEN;// high data byte
		reg = (reg << BYTE_LEN) 
			^ CRCtableArray[ (reg >> (CRC_LEN-BYTE_LEN)) ] ^ dataByte;

		dataByte = (*pUserData++) & 0x00FF;	// low data byte
		reg = (reg << BYTE_LEN) 
			^ CRCtableArray[ (reg >> (CRC_LEN-BYTE_LEN)) ] ^ dataByte;
	}
	*parity = reg;	
	return;
}

//==========================================================================================
// Function:		scramble()
//
// Description: 	Scrambler using linear shift register with polynomial 	
//					S(x) x^7 + x^4 + 1
//					The default inital state is 127 (all ones).
//
//					                             input data |
//					                  |--------------|      |
//					                  |              V      V
//					  ->D-->D-->D-->D-.>D-->D-->D--> + -.-> + 
//					  |  1   2   3   4   5   6   7      |   |    
//					  |---------------------------------|   |
//					                            output data V
//
// Revision History:
//==========================================================================================
void scramble(u16 *pUserData, u16 userDataLen)
{
	i16				n;
	u16				wordCount = 0;

	while( wordCount < userDataLen )
		for( n = 0; n < SCRAMBLER_LEN; n++ )
		{	
			*pUserData++ ^= scramblerLookup[n];
			wordCount++;
			if( wordCount >= userDataLen )
				break;
		}
}

//==========================================================================================
// Function:		CalcTxStartAddr()
//
// Description: 	Calculate the starting address in the TxSignal array, given the
// 					present pointer position and the requested block size.
//
// Revision History:
//==========================================================================================
#if COMPILE_MODE == DSP_COMPILE
TXDATA* CalcTxStartAddr(TXDATA* uCurrAddr, u16 uCnt)
{
	TXDATA*	uStart;

	if ( (uCurrAddr + (uCnt * AFE_SIZE)) > (txSignalArray + TX_BUFFER_LEN))
	//if ( ((uCurrAddr-txSignalArray) + (uCnt * AFE_SIZE)) > TX_BUFFER_LEN )		// fishing here
	{
		uStart = txSignalArray;		// Too close to end; re-start at beginning
	}
	else
	{
		uStart = uCurrAddr;			// Plenty of room; start transfer from present pointer
	}

	return (uStart);
}
#else
	#define	CalcTxStartAddr(x,y)	x	// MEX: Make a fake function that returns its own argument
#endif


#define	TX_RAW_CLIP			(12000)			// 12000 = Crest factor of 3.59  (13.5 bits)
#define	TX_PEAK_SETPOINT	(32767L)		// Max values allowed by transmit DAC

#define	TX_GAIN_SCALE		11				// that is: 2048
#define	TX_GAIN		 		2400			// (i16)(1.17 * (1<<TXGAIN_SCALE) )
#define	TX_PEAK_CLIP		(12000L)		// Truncate at this level digitally
		 									// instead of saturating the driver
//==========================================================================================
// Function:		setTxPower()
//
// Description: 	Adjust the gain of the transmitted signal to get the desired power
//					out of the codec.
//
//	This function provides fine control of the amplitude of the signal generated by the IFFT.
//	It also clips the signal at the level set by TX_PEAK_CLIP.  This is useful in preventing the
//	analog line driver from going into saturation since it takes the line driver amplifier a while
//	to come out of saturation.  That is, it's better to saturate the digital signal then the 
//	analog signal.
//
// Revision History:
//==========================================================================================
void setTxPower(iCplx* ifftBuf)
{
#if (ADJUST_TX_PEAKS == TRUE)
	u16			n;				   	// loop counter
	i16			sample;
	u16 		uSample;
	u16			magMax = 0;			
	u16			magMaxCnt = 0;			

	for(n=0; n<FFT_LEN; n++)
	{
		#if COMPILE_MODE == MEX_COMPILE
			sample = (i16)(((i32)ifftBuf->re * TX_GAIN)>>TX_GAIN_SCALE);
		#else			//  DSP_COMPILE
			sample = (ifftBuf->re * TX_GAIN)>>TX_GAIN_SCALE; 
		#endif
		
		uSample = abs(sample);
		if( uSample > TX_PEAK_CLIP )   
		{
			magMaxCnt++;
			if( uSample > magMax )
			{
				magMax = uSample;
			}
			ifftBuf->re = (i16)Saturate( (i32)sample, -TX_PEAK_CLIP, TX_PEAK_CLIP); 	
		}
		else
		{
			ifftBuf->re = sample;
		}
		ifftBuf++;
	}

	#if SAVETRACE == TRUE
		if( magMax > 0 )
		{
			PostErrorCode(0xBAE1, "setTxPower", "transmit.c", "Clipped transmit waveform");
			SaveTraceData(0xDF00);	
			SaveTraceData(magMax);	 
			SaveTraceData(magMaxCnt); 
		}
		DebugDelay();
	#endif

#endif
	return;
}



//==========================================================================================
// Function:		AdjustTxPeaks()
//
// Description: 	Adjust the gain of the transmitted signal to maintain constant peaks.
//
//	---------- CALCULATION OF RMS POWER AND CREST FACTOR ----------------------------------
//	RMS value for each entire frame (except cyclic prefix) is 
//		RMSideal = FFT_LEN * sqrt(2 * CARRIER_LEN)  =  256 * sqrt( 2 * 60)	= 2804
//	Because the cyclic prefix repeats just a portion of the frame, the actual RMS could be 
//	as little as 
//	  RMSmin = (FFT_LEN / (FFT_LEN + CYCLIC_PREFIX_LEN)) = (256/(256+26)) = 0.91 * RMSideal
//	or as high as 
//	  RMSmax = 2 * RMSideal.
//	However, for most waveforms, the RMS of the packet with cyclic prefix will be pretty 
//	close to RMSideal. 
//
//	The crest factor is defined as the ratio of the peak value divided by the RMS value.
//	A sine wave has a crest factor of sqrt(2) = 1.414.  An OFDM waveform could have a crest 
//	factor as high as CARRIER_LEN*sqrt(2) = 60*1.414 = 84 worst case.  In general, however
//	the crest factor looks like a gaussian distributed variable, with crest factors above 3.5
//	occurring only about once per 1000 frames.
//
//	In this function, we want to boost the RMS as high as possible without truncating the 
//	peak values.  On the occassional rare frame with a huge crest factor that exceeds the 
//	limit, we will adjust the RMS gain as if the crest factor were right at the upper limit
//	and then clip the peak that exceeds that limit.
//
//
// Revision History:
//==========================================================================================
void AdjustTxPeaks(iCplx* ifftBuf, u16 block, u16 frame)
{
	u16		n;				   	// loop counter
	u16		magSample;			// magnitude (abs) of waveform sample
	u16		magMax = 0;			// Peak magnitude
	i16		txGain;				// Gain to multiply tx signal
	iCplx* 	fftBuf;				// fft buffer pointer

	//---- Find biggest sample.  Its index indicates offset from beginning of frame --------
	fftBuf = ifftBuf;
	for(n=0; n<FFT_LEN; n++)
	{
		magSample = abs((fftBuf++)->re);
		if( magSample > magMax )	// find the max real sample
		{
			magMax = magSample;
		}
	}
	DebugDelay();

	//----------------------------------------------------------------------------
	// Calculate the gain that we will use to multiply the entire signal.
	// The saturate term in the denominator limits the range of gains.
	// Lower limit sets upper limit of gain to keep it from rolling over.
	// Upper limit keeps us from squelching frames with really large peaks; 
	// on those, we will clip the peaks.
	//----------------------------------------------------------------------------
	txGain = (TX_PEAK_SETPOINT<<TX_GAIN_SCALE) / Saturate(magMax, 1<<TX_GAIN_SCALE, TX_RAW_CLIP);
	//mexPrintf("  %d   %8.4f\n", magMax, ((double)txGain)/((double)(1<<TX_GAIN_SCALE)) );
	DebugDelay();

#if (ADJUST_TX_PEAKS == TRUE)
	fftBuf = ifftBuf;
	if (magMax < TX_RAW_CLIP)
	{	// Reasonable input signal (common).  No saturation needed, so just multiply gain.
		for(n=0; n<FFT_LEN; n++)
		{
			#if COMPILE_MODE == MEX_COMPILE
				(fftBuf++)->re = (i16)( ((i32)(fftBuf)->re * (i32)txGain)>>TX_GAIN_SCALE );
			#else			//  DSP_COMPILE
				(fftBuf++)->re = ((fftBuf)->re * txGain)>>TX_GAIN_SCALE; 	// Takes 1802 ticks. Uses MPY instruction.
				//(fftBuf++)->re = ((i32)(fftBuf)->re * (i32)txGain)>>13; 	// Takes 10003 ticks. Uses L$$MPY function.
			#endif
		}
	}
	else	// Big input signal (rare).  Saturate each entry.  Use 32-bit for intermediate results.
	{
		//mexPrintf("saturating..." );
		for(n=0; n<FFT_LEN; n++)
		{
			(fftBuf++)->re = (i16)Saturate( ((i32)(fftBuf)->re * (i32)txGain)>>TX_GAIN_SCALE,
			                                -TX_PEAK_SETPOINT, 
			                                 TX_PEAK_SETPOINT); 	
		}

		// Keep track of every time we need to clip a frame
		PostErrorCode(0xBAE1, "AdjustTxPeaks", "transmit.c", "Clipped transmit waveform");
		#if SAVETRACE == TRUE
			SaveTraceData(0xDF00 + (block<<4) + frame);	//!!!DEBUG  Put a marker in the trace buffer
			SaveTraceData((u16)magMax);					//!!!DEBUG  Put a marker in the trace buffer
			SaveTraceData((u16)txGain);					//!!!DEBUG  Put a marker in the trace buffer
		#endif
		DebugDelay();
	}
#endif

#if (PEAK_DEBUG==TRUE)
	#if SAVETRACE == TRUE
		SaveTraceData(0xDE00 + (block<<4) + frame);	//!!!DEBUG  Put a marker in the trace buffer
		SaveTraceData((u16)magMax);				//!!!DEBUG  Put a marker in the trace buffer
		SaveTraceData((u16)txGain);					//!!!DEBUG  Put a marker in the trace buffer
	#endif
#endif

	DebugDelay();
	return;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -