This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AFE7950EVM: Assistance with Phase Extraction from AFE7950EVM I/Q Data

Part Number: AFE7950EVM
Other Parts Discussed in Thread: AFE7950

Tool/software:

I am currently working with the AFE7950EVM and am feeding two 1540MHz RF input signals to channels RxA and RxB. My primary objective is to accurately extract the phase data for both channels by acquiring their I/Q data and performing analysis in MATLAB.

My current setup involves the AFE7950EVM interconnected with a Zynq FPGA evaluation board. I am able to obtain raw I/Q data, which is saved as a CSV file. This data set contains approximately 1024 indices, and for each index, I observe 64 bits of data, which I interpret as four 16-bit I samples and four 16-bit Q samples (labeled as "0:3 samples"). I am assuming the raw data in the CSV is in hexadecimal format.

My current processing workflow involves:

  1. Converting these hexadecimal values to 2's complement binary.

  2. Performing both Real FFT and Complex FFT to extract frequency and phase information.

I would greatly appreciate your clarification and guidance on the following points:

  1. Data Interpretation and Complex Signal Formation:

  • Could you please confirm the correct method for interpreting the "64-bit (0:3) samples of I&Q of 16-bit data each" from the CSV? How should these multiple I and Q samples per index be correctly parsed to form complex I/Q pairs for spectral analysis?
  • Specifically, should I treat each of the four I samples (e.g., I[0], I[1], I[2], I[3]) and corresponding Q samples individually?

  • And to form the complex signal for FFT, is the correct approach to combine them as I + jQ (e.g., I[0] + jQ[0], I[1] + jQ[1], etc.), or am I misunderstanding how to combine the I and Q components if I was thinking of a direct sum like I[0] + Q[0]?
  1. ADC Time Interleaving:

    Given that the AFE7950's DDC outputs I/Q data at a specific sample rate, is time interleaving within the ADC a relevant consideration for data interpretation, and if so, what implications does it have?

  2. HSDC Pro GUI and Script Modification:

    Could you please provide assistance or specific guidance on how to effectively use the HSDC Pro GUI for extracting or verifying this I/Q data for phase analysis?

    Are there any recommended modifications or insights regarding the example scripts provided by Texas Instruments that would be beneficial for my objective?

Any help or insights you can provide would be highly valued.

  • Hi Vamshi,

    For this testing are you using the TI JESD204c IP? 

    1. The format of the samples can be changed in the ILA from hexadecimal to unsigned or signed decimal. I would recommend you update here and export in the format that you would like to use. 
    2. Can you share more information on your AFE and FPGA configuration? Without this I cannot confirm how to interpret the data in the CSV file. 
    3. The ADCs in the AFE are non-interleaved so you do not have to worry about this.
    4. For using HSDC Pro to view the data we can provide a tool to help but we need to know your specific mode of operation. If you are using one of our TI JESD204c IP reference designs then this tool was already provided and we explain how to set it up.

    Regards,

    David Chaparro 

  • Hi David,

    Thank you for your response.

    1. I am currently interfacing the AFE7950 Evaluation Board with the ZU102 FPGA Evaluation Kit via the FMC connector, using the TI JESD204C IP, as you referenced earlier.

    2. I’ve attached the reference script from TI along with sample data captured using HSDC Pro. The exported CSV file appears to contain:

      • 4 samples of I[0:3] and 4 samples of Q[0:3], each 16 bits wide,

      • Resulting in 64 bits for I and 64 bits for Q per capture.

      I’m reading this data into the FPGA and importing it into MATLAB, but I'm unclear on the correct way to parse and align it for further processing.

    3. Could you please guide me on what changes need to be made to the reference script to ensure that the exported data is properly formatted, with clearly separated I/Q samples corresponding to each channel? My objective is to compute frequency and phase in MATLAB for a specific channel.

    4. Additionally, I would appreciate clarification on the following points:

      • What do the 1024 indices in the CSV file represent? Should I interpret them as time samples [0:1023] for each I[0:3] and Q[0:3]?

      • When computing frequency and phase, should all four I/Q sample groups over the 1024 indices be used, or only a specific one?

    5. Furthermore, I’ve observed that even when feeding input only to RxA, the captured data includes four channels of I/Q data (16-bit each). This leads me to suspect the presence of interleaving within the ADC structure. Could you please confirm if this is expected behavior, and how it should be interpreted during post-processing?

    Thank you in advance for your support and insights.

    ILA_Rx.zip

    '''
    Validation :  AFE79xx Library Version 
    				v1.67, v1.74
    Case			RX					TX						   FB						CLK					Notes
    ----	-----------------	  -----------------			-----------------			-----------			------------
    1		245.76Msps, 24410     491.52Msps, 44210			491.52Msps, 22210			FADC=2949.12M       DAC in interleaved mode
    		SerDes=9830.4Mbps     SerDes=9830.4Mbps			SerDes=9830.4Mbps			FDAC=8847.36M
    		PLL0, NCO=3500M		  PLL0, NCO=3500M			NCO=3500M                   REF=491.52M
    		
    2		245.76Msps, 24410     491.52Msps, 44210			491.52Msps, 22210			FADC=2949.12M       DAC in straight mode
    		SerDes=9830.4Mbps     SerDes=9830.4Mbps			SerDes=9830.4Mbps			FDAC=8847.36M
    		PLL0, NCO=3500M		  PLL0, NCO=3500M			NCO=3500M                   REF=491.52M
    '''
    setupParams.skipFpga 				= 1
    sysParams							=	AFE.systemParams
    setupParams.fpgaRefClk 				= 122.88#184.32#
    AFE.systemStatus.loadTrims			= 1
    
    sysParams.fbEnable 					= [False]*2
    sysParams.externalClockTx			= False
    sysParams.externalClockRx			= False
    sysParams.FRef                    	= 491.52
    sysParams.FadcRx                  	= 2949.12
    sysParams.FadcFb				  	= 2949.12
    sysParams.Fdac                    	= 2949.12*4
    
    sysParams.enableDacInterleavedMode	= False 					#DAC interleave mode to save power consumption. Fs/2 - Fin spur occurs
    
    sysParams.modeTdd 					= 0		
    										# 0- Single TDD Pin for all Channels
    										# 1- Separate Control for 2T/2R/1F
    										# 2- Separate Control for 1T/1R/1F			
    
    sysParams.RRFMode 					= 0   #4T4R2F FDD mode
    sysParams.jesdSystemMode			= [3,3]
    										#SystemMode 0:	2R1F-FDD						; rx1-rx2-fb-fb
    										#SystemMode 1:	1R1F-FDD						; rx1-rx1-fb-fb
    										#SystemMode 2:	2R-FDD							; rx1-rx1-rx2-rx2
    										#SystemMode 3:	1R								; rx1-rx1-rx1-rx1
    										#SystemMode 4:	1F								; fb-fb-fb-fb
    										#SystemMode 5:	1R1F-TDD						; rx1/fb-rx1/fb-rx1/fb-rx1/fb
    										#SystemMode 8:	1R1F-TDD 1R-FDD	(FB-2Lanes)(RX1 RX2 interchanged)		; rx2/fb-rx2/fb-rx1-rx1
    
    
    sysParams.jesdLoopbackEn			= 0 #Make it 1 to Enable the JESDTX to JESDRX internal loopback
    sysParams.LMFSHdRx                	= ["44210","44210","44210","44210"]	
    										# The 2nd and 4th are valid only for jesdSystemMode values in (2,6,7,8). For other modes, select 4 converter modes for 1st and 3rd.
    sysParams.LMFSHdFb                	= ["22210","22210"]
    sysParams.LMFSHdTx                	= ["44210","44210","44210","44210"]
    sysParams.jesdTxProtocol            = [0,0]
    sysParams.jesdRxProtocol            = [0,0]
    sysParams.serdesFirmware			= True 		# If you want to lead any firmware, please speify the path here. Otherwise it will not write any firmware
    sysParams.jesdTxLaneMux				= [0,1,2,3,4,5,6,7]	
    												# Enter which lanes you want in each location. 
    												# Note that across 2T Mux is not possible in 0.5.
    												# For example, if you want to exchange the first two lines of each 2T, this should be [[1,0,2,3],[5,4,6,7]]
    sysParams.serdesTxLanePolarity		= [False]*8
    sysParams.jesdRxLaneMux				= [0,1,2,3,4,5,6,7]	#[0,1,2,3,4,5,7,6]
    												# Enter which lanes you want in each location.
    												# Note that across 2R Mux is not possible in 0.5.
    												# For example, if you want to exchange the first two lines of each 2R, this should be [[1,0,2,3],[5,4,6,7]]
    sysParams.serdesRxLanePolarity	= [False]*8
    sysParams.jesdRxRbd					= [4, 4]
    
    sysParams.rxJesdTxScr				= [True]*4
    sysParams.fbJesdTxScr				= [True]*2
    sysParams.jesdRxScr					= [True]*4
    
    sysParams.rxJesdTxK					= [32]*4
    sysParams.fbJesdTxK					= [32]*2
    sysParams.jesdRxK					= [32]*4
    
    sysParams.ncoFreqMode 				= "1KHz"
    	
    sysParams.txNco0					= 	[[5400,1800],		#Band0, Band1 for TxA for NCO0
    										[500,1800],        #Band0, Band1 for TxB for NCO0
    										[2500,1800],        #Band0, Band1 for TxC for NCO0
    										[1800,1800]]        #Band0, Band1 for TxD for NCO0
    
    sysParams.rxNco0					= 	[[5400,1800],		#Band0, Band1 for RxA for NCO0
    										[500,1800],        #Band0, Band1 for RxB for NCO0
    										[2500,1800],        #Band0, Band1 for RxC for NCO0
    										[1800,1800]]        #Band0, Band1 for RxD for NCO0
    
    sysParams.fbNco0					= 	[1800,1800]			#FBA, FBC for NCO0
    sysParams.fbNco1					= 	[1800,1800]			#FBA, FBC for NCO1
    sysParams.fbNco2					= 	[1800,1800]			#FBA, FBC for NCO2
    sysParams.fbNco3					= 	[1800,1800]			#FBA, FBC for NCO3
    
    sysParams.numBandsRx				= [0]*4					# 0 for single, 1 for dual
    sysParams.numBandsFb				= [0,0]				
    sysParams.numBandsTx				= [0,0,0,0]
    
    sysParams.ddcFactorRx             	= [6]*4			# DDC decimation factor for RX A, B, C and D
    sysParams.ddcFactorFb             	= [6]*4
    sysParams.ducFactorTx             	= [24]*4
    
    
    ## The following parameters sets up the LMK04828 clocking schemes
    lmkParams.pllEn						=	True#False
    lmkParams.inputClk					=	1474.56#737.28
    lmkParams.sysrefFreq				=	2949.12/1024
    lmkParams.lmkFrefClk				=	True
    
    ## The following parameters sets up the register and macro dumps
    logDumpInst.setFileName(ASTERIX_DIR+DEVICES_DIR+r"\Afe79xxPg1.txt")
    logDumpInst.logFormat				= 0x00
    logDumpInst.rewriteFile				= 1
    logDumpInst.rewriteFileFormat4		= 1
    device.optimizeWrites				= 0
    device.rawWriteLogEn				= 1
    lmk.rawWriteLogEn					= 1
    
    ## The following parameters sets up the SYNCIN and SYNCOUT to interface with the TSW14J57
    sysParams.jesdABLvdsSync			= 0
    sysParams.jesdCDLvdsSync			= 0
    sysParams.rxJesdTxSyncMux			= [0,0,0,0]
    sysParams.fbJesdTxSyncMux			= [0,0]
    sysParams.jesdRxSyncMux				= [0,0,0,0]		#[0,0,1,1]
    sysParams.syncLoopBack				= True
    
    # ## The following parameters sets up the AGC
    # sysParams.agcParams[0].agcMode = 1 ##internal AGC
    # sysParams.agcParams[0].gpioRstEnable = 0 ##disable GPIO based reset to AGC detector 
    # sysParams.agcParams[0].atken = [0, 1, 0] ##enable big and small step attack
    # sysParams.agcParams[0].decayen = [0,1,0] ##enable big and small step decay
    # sysParams.agcParams[0].atksize = [2,1,0] ## bigs step = 2dB, small step = 1dB
    # sysParams.agcParams[0].decaysize = [2,1,0] ##big step = 2dB, small step = 1dB
    # sysParams.agcParams[0].atkthreshold = [-1, -2, -14] ##attack threshold
    # sysParams.agcParams[0].decaythreshold = [-14, -6, -20] ##decay threshold
    # sysParams.agcParams[0].atkwinlength = [170, 170] ## detector time constant expressed inn absolute time in ns. 
    # sysParams.agcParams[0].decaywinlength = 87380 ##detector time constant expressed in absolute time in ns. All detectors use the same value for decay time constant
    # sysParams.agcParams[0].atkNumHitsAbs = [8,8] ##absolute number of times signal crosses threshold. These crossing are with respect to the FADC/8 clock
    # sysParams.agcParams[0].decayNumHitsAbs = [100,100] ##absolute number of times signal crosses threshold. These crossing are with respect to the FADC/8 clock
    # sysParams.agcParams[0].minDsaAttn = 0 ##minimum DSA attenuation used by AGC
    # sysParams.agcParams[0].maxDsaAttn = 22 ##maximum DSA attenuation used by AGC
    # sysParams.agcParams[0].totalGainRange = 22 ##total gain range used by ALC for gain compensation
    # sysParams.agcParams[0].minAttnAlc = 0 ##minimum attenuation used by ALC for compensation when useMinAttnAgc = 0
    # sysParams.agcParams[0].useMinAttnAgc = 1 ##enable ALC to use minimum attenuation from AGC for which compensation is required.
    # sysParams.agcParams[0].alcEn = 1
    # sysParams.agcParams[0].alcMode = 0 ##floating point DGC
    # sysParams.agcParams[0].fltPtMode = 0 ##if exponent > 0, dont send MSB
    # sysParams.agcParams[0].fltPtFmt = 1 ##3 bit exponent
    
    
    ## The following parameters sets up the GPIOs
    sysParams.gpioMapping={
    		'H8': 'ADC_SYNC0',
    		'H7': 'DAC_SYNC0',
    		'N8': 'ADC_SYNC2',
    		'N7': 'ADC_SYNC3',
    		'H9': 'ADC_SYNC1',
    		'G9': 'DAC_SYNC1',
    		'N9': 'DAC_SYNC2',
    		'P9': 'DAC_SYNC3',
    		'P14': 'GLOBAL_PDN',
    		'K14': 'FBABTDD',
    		'R6': 'FBCDTDD',
    		'H15': ['TXATDD','TXBTDD'],
    		'V5': ['TXCTDD','TXDTDD'],
    		'E7': ['RXATDD','RXBTDD'],
    		'R15': ['RXCTDD','RXDTDD']}
    		
    #AFE.systemParams.papParams[0]['enable'] = True
    #AFE.systemParams.papParams[1]['enable'] = True
    #AFE.systemParams.papParams[2]['enable'] = True
    #AFE.systemParams.papParams[3]['enable'] = True
    setupParams.skipLmk	=	False
    
    AFE.initializeConfig()
    lmkParams.sysrefFreq = AFE.systemStatus.sysrefFreq
    lmkParams.lmkPulseSysrefMode = False
    AFE.LMK.lmkConfig()