/************************************************
板子使用的RF板V0.1板
LMX2594作为第一本振使用，需要扫频功能
LO_LMX2581作为第二本振使用，默认是固定的3.3G定频，除非频率校准，否则无需调整
CAL_LMX2581作为测试的信号源使用，支持扫频功能
************************************************/
#include "sys.h"
#include "delay.h"
#include "usart.h"

#include "pll_config.h"
#include "LO_LMX2594_Freq_Config.h"
#include "LO_LMX2594_VCO_CAL.h"

// #include "LMX2594_CONFIG.h"
// #include "LO_LMX2581_CONFIG.h"
// #include "CAL_LMX2581_CONFIG.h"
//#include "FPGA_Driver.h"
//#include "ocsctl.h"
//#include "AGC_adjust.h"
#include "adc.h"
//#include "dac.h"

//#include "arm_math.h"  //M4核使用的

#include  <stdarg.h>
#include  <stdio.h>
#include  <stdlib.h>
#include  <math.h>

//-------------------------------------------------------------------------------------------------------//
//------------------------------------------检波方式-------------------------------------------------//
//-------------------------------------------------------------------------------------------------------//
//被测信号------------------检波------------平均处理方式------------VBW处理------------Trace_Avg---------//
//连续谱调制信号-------------RMS----------------Pwr--------------VBW >= 3* RBW---------Pwr(RMS)----------//
//CW信号和离散信号----------Peak----------------Log------------------Yes---------------Log-Pwr(video)----//
//GSM信号ORFS---------------Average-------------Log--------------VBW >= 3* RBW---------Log-Pwr(video)----//
//ACPR----------------------Average-------------Pwr--------------VBW >= 3* RBW---------Pwr(RMS)----------//
//信号包络，上/下沿时间-----Sample--------------Lin--------------VBW >= 3* RBW---------Voltage-----------//
//噪声测试------------------Sample--------------Pwr--------------VBW >= 3* RBW---------Pwr(RMS)----------//
//-------------------------------------------------------------------------------------------------------//

//检波方式
#define  RMS_PWR_DETECTOR     0
#define  PEAK_LOG_DETECTOR    1
#define  AVERAGE_LOG_DETECTOR 2
#define  AVERAGE_PWR_DETECTOR 3
#define  SAMPLE_LIN_DETECTOR  4
#define  SAMPLE_PWR_DETECTOR  5

#define  Pi  3.14159


//在自动模式下，RBW和VBW，SPAN和SWT都有相应公式。
//自动模式下，存在公式
//RBW = 10* VBW , 
//SPAN > 10 * RBW， 
//SWT = K * SPAN / RBW * RBW  , VBW >= RBW ; K为中频滤波器的形状因子
//SWT = K * SPAN / RBW * VBW  , RBW >= VBW ; K为中频滤波器的形状因子


//波形显示窗口是600 x 400

//为了便于计算，频率计算式使用 double 双精度计算
//因为使用定点数计算，小数点问题很麻烦
//浮点计算时，单位为GHz，即e9

//SPAN小于1MHz，自动进入定频模式，程序使用FFT

//外部RAM区，此版本为32M字节，可以尝试更换为64M的三星K4S511632C
//
//-----------------------------幅频表数组------------------------------------------------------//



//u16 testsram[250000] __attribute__((at(0XC0000000)));// 外部SDRAM数组范例

//double Spectrum_Freq_Table[19200] __attribute__((at(0XC0000000))); 		//输入频率表
//float  Spectrum_Amp_Table[19200] __attribute__((at(0XC0000000)));       //对应的幅度表，单精度足以

//分段存储，采样点 = SPAN / RBW ，采样点必须限制。
//通常情况下,RBW < SPAN/10，即SPAN/RBW >10，至少10个频率点步进，但是实际要保证至少600个点填充屏幕


//volatile float Spectrum_Amp_CAL_Table[3000];     //幅度校准表，单位为dB，单精度足以
                                                //校准数据每次开机从EEPROM里面读取，对应频率从1M到3000M，单位1M，3000个点											   
//uint16_t Spectrum_Freq_Amp_Table_
//-----------------------------幅频表数组------------------------------------------------------//


//volatile double Spectrum_Freq_Table[19200]; 		//输入频率表
//volatile float  Spectrum_Amp_Table[19200];          //对应的幅度表，单精度足以


 volatile float Spectrum_Amp_temp = 0;
//volatile float Spectrum_Amp_temp[1800];  //幅度表


volatile	double Freq_LO1_step;
volatile	double Freq_LMX2594_Set;
	
volatile	uint16_t i = 0; //循环计数用
volatile	uint16_t j = 0;
volatile	uint8_t temp = 0; //

volatile   float float_temp = 0;
volatile   float float_temp2 = 0;
	
volatile	uint16_t CAL_Amp_index = 0; //幅度校准值索引
	
volatile	double Freq_IF =  4.1357; 				//第一中频频率为4.1357GHz
	//double Freq_LO2 = 3.300000000; 				//第二本振频率为3.3GHz
	//double Freq_LO3 = 0.825000000; 				//第三本振频率为825MHz
	// double Freq_IF3 = 0.010700000; 			//第三中频频率为10.7MHz	
volatile	double Freq_LO1 =  4.2357;				//默认第一LO频率为4.2357G，即输入频率默认为100M
volatile	double Spectrum_Freq_span = 0.1; 	//SPAN值默认是100MHz


volatile float agc_gain_dB = 0;

volatile uint16_t temp_u16 = 0;

//-----------------------------外部变量------------------------------------------------------//
extern uint8_t _win_Hanning_start_flag ;
extern	float temp_float;



//-----------------------------扫频通用函数------------------------------------------------------//
//设置频率扫描
//程序内部会更新检波数组
//-----------------------------扫频通用函数------------------------------------------------------//
void Spectrum_Freq_set( double   Spectrum_Freq_start,             //设置频谱仪的起始频率，单位为GHz
						double   Spectrum_Freq_stop ,             //设置频谱仪的结束频率，单位为GHz
						uint16_t Spectrum_Freq_Sampling_point ,   //RBW设置才对
 						uint16_t Spectrum_Scan_delay,             //扫频延迟时间，单位为100us，						
																  //每增加1个数值，即频点停留时间增加100us
																  //最快是0，即系统配置到锁相环锁相环锁定时间
																  //最长延迟不得超过100us x 1000 = 100ms
						uint8_t  Spectrum_Detector                //检波方式设置										 
																)   																 																 																					
{
	//-------------------------------------变量定义-------------------------------------------------//

	//--------------------------------------变量定义------------------------------------------------//

	
	//-------------------------------------------------------------------------------------------//	
    //判断输入参数是否正确，用于测试输入值
    temp = Spectrum_Freq_set_value_judge_result(  Spectrum_Freq_start ,         
												  Spectrum_Freq_stop ,         
												  Spectrum_Freq_Sampling_point, 
												  Spectrum_Scan_delay ,        
												  Spectrum_Detector
																				);

    //-------------------------------------------------------------------------------------------//
		
	if(temp == 0xAA) //出错
	{
//		printf("\r\n  Spectrum Set ERROR!!! Set default value! \r\n");	
		
		//设置出错，设置为默认频率
		Spectrum_Freq_start = 0.1; 		//默认为100M起始
		Spectrum_Freq_stop = 3; 		//默认3G结束 
		Spectrum_Freq_Sampling_point = 2400; 	//默认2400个点 
		Spectrum_Scan_delay = 0; 				//默认最快速度 
 		Spectrum_Detector = 1; 					//默认峰值，对数检波
	}
	else if(temp == 0x55)//正确，开始配置
	{
//		printf("\r\n  Spectrum Set OK!!! \r\n");		
		Spectrum_Freq_start = Spectrum_Freq_start; 
		Spectrum_Freq_stop = Spectrum_Freq_stop; 
		Spectrum_Freq_Sampling_point = Spectrum_Freq_Sampling_point; 
		Spectrum_Scan_delay = Spectrum_Scan_delay; 			
		
	}
	else//莫名其妙错误
	{
		__nop();		
	}


	//判断SPAN的值，这里限定最小值1M
	Spectrum_Freq_span = Spectrum_Freq_stop - Spectrum_Freq_start;	
	
//	//如果SPAN小于1M，进入FFT模式，必须定频
//	//这是强制更改输入参数，将起始频率和结束频率改成相同
//	//定频进入分两种途径，一种是Zero Span进入，一种是FFT模式
//	if(Spectrum_Freq_span < 0.001000000)//SPAN太小，依靠FFT来分辨
//	{
//		Spectrum_Freq_start = Spectrum_Freq_stop;
//		Spectrum_Freq_span = 0; //强制SPAN为零
//	}
//	else//SPAN大于1M，进入扫频模式
//	{
//		__nop();	
//	}	
	
//-------------------------------------------------------------------------------------------//
	//第一本振的频率的频率和频谱仪设置的频率不同，需要换算
	//Fin = LO1 - (LO2 + L03 + IF3)
	//LO1 = Fin + Freq_IF ;
	Freq_LO1 =  Spectrum_Freq_start + Freq_IF; //得到本振的配置频率
		
	//计算频率步进点 = SPAN / 采样点
	//得到本振的步进频率
	Freq_LO1_step = Spectrum_Freq_span / Spectrum_Freq_Sampling_point ;
	
	//取得校准值索引，用于校准值查找
	CAL_Amp_index = (uint16_t)(Spectrum_Freq_start * 1000);	
//-------------------------------------------------------------------------------------------//		


//--------------------------------------配置第二、三本振相关--------------------------------------//
// LO_LMX2581_CONFIG_Freq(Freq_LO2, Freq_LO3); //不在这里配置，没有必要重复配置		
//--------------------------------------配置第二、三本振相关--------------------------------------//	

	
	//因为定频和扫频的配置不同，需要分开处理
	if(Freq_LO1_step == 0)//步进为零，定频
	{
		//配置为定频，只需一次配置即可
		LMX2594_Config_Freq(Freq_LO1);
		Freq_LMX2594_Set = Freq_LO1;
		float_temp = FPGA_Communication(    FPGA_CTR_READ_RMS_PWR_AMP,  //    		
											1,  	   //
											RBW_10KHz,       		
											VBW_1K        								 
										);
		 __nop();
//		printf("\r\n Detector value = %5.2f dBm.   Freq = %10.9f GHz \r\n" , float_temp , Freq_LO1 );		
			if(float_temp < -50)//小于-50dBm，读数有误。
			{
				float_temp = -50;
			}
			
			
			//读取AGC的增益值
			//agc增益，正号表示增益，负号表示衰减
			float_temp2 = AGC_Gain_dB(ADC_CHANNEL_2,  4 , 0);
			agc_gain_dB = float_temp2;
			float_temp2  = AGC_Gain_dB(ADC_CHANNEL_3, 4,  1); //
			agc_gain_dB = agc_gain_dB + float_temp2;
			__nop();
			

			
			//ADC读取值和AGC的增益统一计算
			Spectrum_Amp_temp = float_temp - agc_gain_dB + 10;
	
			temp_float = Spectrum_Amp_temp; //不加窗

	
//	        OCS_displayData(Spectrum_Amp_temp, 100.0, 255.0, 1000.9);

/**************************************串口幅度打印输出*************************************/			
			printf("\r\n Detector value = %5.2f dBm.   Freq = %10.9f GHz " , 
			                       Spectrum_Amp_temp , Freq_LMX2594_Set );
/*******************************************************************************************/			
			temp_u16 = 2850 + temp_float * 20 ;	//输出电压单位是mV		
			DAC1_Set_Vol(temp_u16); 	

	
	}	
	else//LO扫频模式，注意！这里操作的是LO的频率了！！！
	{
		
		//----------------------------------------------------------------------------------------------//
		//-------------------------------------配置第一本振相关-----------------------------------------//			
		//第一本振的频率
		//扫频循环为，频率开始点 + 步进点，循环次数为采样点数
		for(i = 0  ; i <= Spectrum_Freq_Sampling_point ; i++)
		{
			Freq_LMX2594_Set = Freq_LO1 + (Freq_LO1_step * i); //配置为LO起始频率 + 步进频率x步进数
			LMX2594_Config_Freq(Freq_LMX2594_Set);  					//配置第一本振
			//根据扫描延迟进行简单延迟
			for(j = 0; j <= Spectrum_Scan_delay; j++)
			{
				delay_us(100); //每个扫描延迟的单位100us										
			}
			//--------------------------------------配置第一本振相关----------------------------------------//
			//----------------------------------------------------------------------------------------------//				
			
			
			//----------------------------------------------------------------------------------------------//					
			//--------------------------------------幅频表--------------------------------------------------//			
			//将频率和对应幅度 一一对应存入数组
//			Spectrum_Freq_Table[i] = Freq_LMX2594_Set;

			__nop();
			//发送读取幅度的指令，返回幅度值  
			float_temp = FPGA_Communication(	FPGA_CTR_READ_RMS_PWR_AMP,  //RMS检波，这里是假的    		
												1,  	   //读取检波值，0是配置FPGA设置
												RBW_10KHz, //RBW设置为10k，暂不启用     		
												VBW_1K     //VBW设置为1k，暂不启用					 
											);						
//			Spectrum_Amp_Table[i] = float_temp;
			
			__nop();
			
			if(float_temp < -50)//小于-50dBm，读数有误。
			{
				float_temp = -50;
			}
			
			
			//读取AGC的增益值
			//agc增益，正号表示增益，负号表示衰减
			float_temp2 = AGC_Gain_dB(ADC_CHANNEL_2,  4 , 0); //0表示MODE = L ,AGC斜率不同
			agc_gain_dB = float_temp2;
			float_temp2  = AGC_Gain_dB(ADC_CHANNEL_3, 4,  1); //
			agc_gain_dB = agc_gain_dB + float_temp2;
			__nop();
//			printf("\r\n AGC Gain = %5.2f dB. \r\n" , agc_gain_dB );

            //固定增益补偿
			

		
			//ADC读取值和AGC的增益统一计算
			//单点输出
			// Spectrum_Amp_temp = float_temp - agc_gain_dB + 10;// AGC放大自带10dB插损，很是奇怪
			//数组存储
			Spectrum_Amp_temp = float_temp - agc_gain_dB + 10;// AGC放大自带10dB插损，很是奇怪

/*************************对FPGA返回的检波数据进行加窗************************************************************/		
//			temp_float = Han_Win(i ,Spectrum_Amp_temp);//
//			temp_float = Gaosi_Win(i ,Spectrum_Amp_temp);//			
			temp_float = Spectrum_Amp_temp; //不加窗
/***************************************************************************************************/		
			
//			Spectrum_Amp_temp = float_temp;
//			printf("\r\n Detector value = %5.2f dBm. \r\n" , Spectrum_Amp_temp );
			//补偿幅度值，链路插损会随着输入频率变化而变化
			//Spectrum_Amp_Table[i] =  float_temp +  Spectrum_Amp_CAL_Table[CAL_Amp_index];   
						
		
/**************************************串口幅度打印输出*************************************/			
			//printf("\r\n Detector value = %5.2f dBm.   Freq = %10.9f GHz " , 
//			                       Spectrum_Amp_temp , Freq_LMX2594_Set );
/*******************************************************************************************/			
			
/**************************************串口波形软件输出*************************************/			
			OCS_displayData(temp_float, 100.0, 255.0, 1000.9);
/*******************************************************************************************/

/**************************************幅度模拟输出*****************************************/			
			//按20mV/dBm计算，起始点为50mV，对应-140dBm。
			//那么dBm = (DACmV - 50mv)/20 - 140
  
//			temp_u16 = 65535 - (temp_float * 20 + 2850) + 1;//输出电压单位是mV，这里还是有疑问？
			temp_u16 = 2850 + temp_float * 20 ;	//输出电压单位是mV		
			DAC1_Set_Vol(temp_u16); 
//			__nop();

			//也可以把频率按照一定的电压输出来，可以安装一定比例
			//如果如果SPAN = 1G~3G，则1mV = 1MHz，              从300mV到3000mV
			//如果SPAN = 100M~1G，则3mV = 1MHz，                从300mV到3000mV
			//如果SPAN = 10M~100M，则30mV = 1MHz，3mV = 100KHz，从300mV到3000mV
			//如果SPAN = 1M~10M，则300mV = 1MHz，3mV = 10KHz，  从300mV到3000mV
			//如果SPAN = 100k~1M，则3000mV = 1MHz，3mV = 1KHz， 从300mV到3000mV
			//如果SPAN = 10k~100k，则30mV = 1KHz，3mV = 100Hz， 从300mV到3000mV		
            //如果SPAN = 1k~10k	， 则30mV = 100Hz，3mV = 10Hz，从300mV到3000mV		
/*******************************************************************************************/
			
		}		
	}		
}



//加汉宁窗
float Han_Win(uint16_t i ,float _Win_Hanning_Data_in)
{
    float Wn;
	
    // Wn = 0.5 - 0.5 * cos((2 * Pi * (i - 1)) / (N - 1)); //w = .5*(1 - cos(2*pi*(1:m)'/(n+1))); 
	//这里写死，N = 1800个数据
	Wn = 0.5 - 0.5 * cos((2 * Pi * (i)) / (31)); //w = .5*(1 - cos(2*pi*(1:m)'/(n+1))); 
    Wn = Wn * _Win_Hanning_Data_in; 	
    return Wn;
}	

//加高斯窗
//float Gaosi_Win(uint16_t i ,float _Win_Gaosi_Data_in)
//{
//    float Wn;
//	double temp_double;
//	uint16_t temp_u16; 
//	uint16_t alpha = 4; //	
//	uint16_t N = 64;
//	double stdev;
//	
//	int16_t j = 0;
//	
//	stdev = (N - 1) / (2 * alpha);
//	temp_double  = -(((i * i) / (stdev * stdev))* 0.5);	
//	Wn = exp(temp_double);	

////  temp_u16 = floor((N + 1) / 2);
////	temp_double = -(((temp_u16 - i) * (temp_u16 - i)) / (2 * alpha * alpha));
////	Wn = exp(temp_double);	
//	
//    Wn = Wn * _Win_Gaosi_Data_in; 		
//    return Wn;

//}


//加高斯窗
//入口参数：样本编号、样本值
//返回参数：加窗后的样本值
float Gaosi_Win(uint16_t i ,float _Win_Gaosi_Data_in)
{
    float Wn;
	double temp_double;
	uint16_t temp_u16; 
	uint16_t alpha = 4; //形状调整
	uint16_t N = 64;    //窗采样数
	double stdev;
	
	int16_t a = 0;
	int16_t b = 0;
	
//	a = (int16_t)i; //强制转换为有符号
	a = i; //强制转换为有符号
	b = a - 2048; //窗中心点移动，2048是总扫描点为4096
	
	stdev = (N - 1) / (2 * alpha);
	temp_double  = -(((b * b) / (stdev * stdev))* 0.5);	
	Wn = exp(temp_double);	                //解幂函数
//    Wn = Wn * _Win_Gaosi_Data_in * 2.396; 	//幅度恢复系数
	 Wn = Wn * _Win_Gaosi_Data_in ; 	
    return Wn;

}



//-----------------------------判断输入的值是否有效------------------------------------------------------//
//用于判断频率相关设定是否正确
uint8_t Spectrum_Freq_set_value_judge_result( double   Spectrum_Freq_start_judge ,         
											  double   Spectrum_Freq_stop_judge ,         
											  uint16_t Spectrum_Freq_Sampling_point_judge, 
											  uint16_t Spectrum_Scan_delay_judge,         
											  uint8_t  Spectrum_Detector_judge
																							)        
{  

//-----------------------------变量定义------------------------------------------------------//                                  
	uint8_t value_result = 0; 
//-----------------------------变量定义------------------------------------------------------//


     //输入起始频率判断
	if(Spectrum_Freq_start_judge < 0.001)//频率必须大于1M
	{
//		printf("\r\n Freq_start value < 0 ERROR!!! \r\n");  		
		value_result = 0XAA; //出错置0XAA
	}
	else if(Spectrum_Freq_start_judge > 3.00000000)//不得超过3G频率输入
	{	   
//		printf("\r\n Freq_start value > 3GHz ERROR!!! \r\n");  
		value_result = 0XAA; //出错置0XAA		
	}
	else //频率在0Hz ~ 3GHz之间 ，正常，接下来判断输入结束频率
	{
//		printf("\r\n Freq_start value OK !!! \r\n"); 	
		
		//输入结束频率判断  
		if(Spectrum_Freq_stop_judge < Spectrum_Freq_start_judge) //结束频率小于起始频率，出错
		{
//			printf("\r\n Freq_stop value < Freq_start ERROR!!! \r\n"); 	
			value_result = 0XAA; //出错置0XAA
			
		}
		else if(Spectrum_Freq_stop_judge < 0)//频率必须为正频率
		{
//			printf("\r\n Freq_stop value < 0 ERROR!!! \r\n");  		   	
			value_result = 0XAA; //出错置0XAA		
		}

		else if(Spectrum_Freq_stop_judge > 3.00000000) //不得超过3G频率输入
		{
//			printf("\r\n Freq_stop value > 3GHz ERROR!!! \r\n");  	   
			value_result = 0XAA; //出错置0XAA
		}
		else //正常值，接下来判断采样点数
		{
//			printf("\r\n Freq_stop value OK!!! \r\n"); 	
		   
			//这里是设定，采样点至少600个，满足显示波形窗的像素
			//最大不要超过600 x 32 ，19200个点
			if(Spectrum_Freq_Sampling_point_judge < 600 )//扫描点太小
			{
//				printf("\r\n Freq_Sampling_point value < 600 ERROR!!! \r\n"); 	
				value_result = 0XAA; //出错置0XAA			
			}
			else if(Spectrum_Freq_Sampling_point_judge > 50000)//扫描点太多
			{
//				printf("\r\n Freq_Sampling_point value > 19200 ERROR!!! \r\n"); 	
				value_result = 0XAA; //出错置0XAA			
			}
			else//正常值，接下来判断扫描延迟时间
			{
//				printf("\r\n Freq_Sampling_point value OK !!! \r\n");	

				//这里延迟时间最低设置为0，
				if(Spectrum_Scan_delay_judge > 1000) //最长延迟不得超过100us x 1000 = 100ms
				{
//					printf("\r\n Freq_Scan_delay value > 1000 ERROR!!! \r\n"); 					
					value_result = 0XAA; //出错置0XAA
				}
				else //正常值，输入值设定正常
				{
//					printf("\r\n Freq_Scan_delay value OK !!! \r\n");                    					
					
					if(Spectrum_Detector_judge > 5)//检波方式设置无效
					{
//						printf("\r\n Spectrum_Detector value ERROR !!! \r\n"); 						
						value_result = 0XAA; //出错置0XAA						
					}
					else
					{
						//参数全部值正常，返回0
						value_result = 0x55; //正常为0x55													
					}
															
				}
				
			}
		   
		}
	}
   
    return  value_result; //检查结果返回
	                                	
}







