#include "htra_api.h"
#include "example.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
using namespace std;

#define IS_USB 1 //默认使用的是USB型设备，若使用的是网口型设备则将IS_USB定义为0。

//通过检查data_arr数据数组中的值是否超过噪声阈值noiseThreshold，查找并记录峰值的索引至peak_index。
void peak_seek(const vector<float>& data_arr, const float noiseThreshold, vector<int>& peak_index)
{
	bool flag = false; //用于标记当前是否在一个峰值区域内。
	int indexOfMax;    //用于保存当前峰值的索引。

	//遍历数据数组。
	for (int i = 0; i < data_arr.size(); i++)
	{
		//如果当前值大于噪声阈值，则可能是一个峰值的一部分。
		if (data_arr[i] > noiseThreshold)
		{
			//如果flag为false，表示之前没有进入峰值区域，现在开始进入。
			if (flag == false)
			{
				flag = true;    //设置flag为true，表示现在在一个峰值区域内。
				indexOfMax = i; //记录当前峰值的索引。
			}
			else
			{
				//如果已经在一个峰值区域内，并且当前值比之前记录的最大值大，则更新最大值的索引。
				if (data_arr[i] > data_arr[indexOfMax])
				{
					indexOfMax = i; //更新当前峰值的索引。
				}
			}
		}
		else
		{
			//如果当前值小于噪声阈值，且之前进入过峰值区域，则保存当前找到的最大峰值的索引。
			if (flag == true)
			{
				flag = false;                     //退出峰值区域，设置flag为false。
				peak_index.push_back(indexOfMax); //将当前找到的峰值的索引添加到结果列表中。
			}
		}
	}
}

//找出信号和杂散并把对应频率、功率、超出limit的功率大小添加到ssfreq、ssSpec、ssDelt。
void SigAndSpur(const vector<double>& Freq_Hz, const vector<float>& PowerSpec_dBm, const float limit, vector<double>& ssfreq, vector<float>& ssSpec, vector<float>& ssDelt)
{
	//定义一个存储峰值索引的列表。
	vector<int> peak_index_list(0);

	//调用 peak_seek 函数，寻找功率谱中大于阈值limit的峰值，返回峰值的索引列表。
	peak_seek(PowerSpec_dBm, limit, peak_index_list);

	// 遍历每个峰值的索引。
	for (int i = 0; i < peak_index_list.size(); i++)
	{
		// 将峰值对应的频率添加到ssfreq中。
		ssfreq.push_back(Freq_Hz[peak_index_list[i]]);

		// 将峰值对应的功率值添加到ssSpec中。
		ssSpec.push_back(PowerSpec_dBm[peak_index_list[i]]);

		// 计算当前峰值与给定阈值limit之间的差值，并将结果添加到ssDelt中。
		ssDelt.push_back(PowerSpec_dBm[peak_index_list[i]] - limit);
	}
}


int SWP_GetSpectrum_SigAndSpur(void)
{
	int Status = 0;      //函数的返回。
	void* Device = NULL; //当前设备的内存地址。
	int DevNum = 0;      //指定设备号。

	BootProfile_TypeDef BootProfile; //启动配置结构体，包括物理接口、供电方式等。
	BootInfo_TypeDef BootInfo;       //启动信息结构体，包括设备信息、USB速率等。

	BootProfile.DevicePowerSupply = USBPortAndPowerPort; //使用USB数据端口及独立电源端口双供电。

#if IS_USB==1
	//配置USB接口。
	BootProfile.PhysicalInterface = USB;
#else 
	//配置ETH接口。
	BootProfile.PhysicalInterface = ETH;
	BootProfile.ETH_IPVersion = IPv4;
	BootProfile.ETH_RemotePort = 5000;
	BootProfile.ETH_ReadTimeOut = 5000;
	BootProfile.ETH_IPAddress[0] = 192;
	BootProfile.ETH_IPAddress[1] = 168;
	BootProfile.ETH_IPAddress[2] = 1;
	BootProfile.ETH_IPAddress[3] = 100;
#endif

	Status = Device_Open(&Device, DevNum, &BootProfile, &BootInfo); //打开设备。

	Device_Open_ErrorHandling(Status, &Device, DevNum, &BootProfile, &BootInfo); //当Status不为0时，根据Status的返回值进行相对应的错误处理。

	SWP_Profile_TypeDef SWP_ProfileIn;  //SWP输入配置，包括起始频率、终止频率、RBW、参考电平等。
	SWP_Profile_TypeDef SWP_ProfileOut; //SWP输出配置。
	SWP_TraceInfo_TypeDef TraceInfo;    //当前配置下的迹线信息，包括迹线点数、跳频点数等。

	SWP_ProfileDeInit(&Device, &SWP_ProfileIn); //初始化SWP模式的相关参数。

	SWP_ProfileIn.StartFreq_Hz = 9e3;   //配置起始频率。
	SWP_ProfileIn.StopFreq_Hz = 6.35e9; //配置终止频率。
	SWP_ProfileIn.RBW_Hz = 300e3;       //配置RBW。

	Status = SWP_Configuration(&Device, &SWP_ProfileIn, &SWP_ProfileOut, &TraceInfo); //下发SWP模式的相关配置。

	SWP_Configuration_ErrorHandling(Status, &Device, DevNum, &BootProfile, &BootInfo, &SWP_ProfileIn, &SWP_ProfileOut, &TraceInfo); //当Status不为0时，根据Status的返回值进行相对应的错误处理。

	vector<double> Frequency(TraceInfo.FullsweepTracePoints);    //创建频率数组。
	vector<float> PowerSpec_dBm(TraceInfo.FullsweepTracePoints); //创建功率数组。
	MeasAuxInfo_TypeDef MeasAuxInfo;                             //测量数据的辅助信息，包括：功率最大值索引、功率最大值、设备温度、经纬度、绝对时间戳等。

	SWP_GetFullSweep(&Device, Frequency.data(), PowerSpec_dBm.data(), &MeasAuxInfo); //获取频谱数据。

	SWP_ErrorHandlingExceptOpenAndConfiguration(Status, &Device, DevNum, &BootProfile, &BootInfo, &SWP_ProfileIn, &SWP_ProfileOut, &TraceInfo); //当Status不为0时，根据Status的返回值进行相对应的错误处理。

	vector<double> ssfreq(0); //存储峰值对应的频率 (单位: Hz)。
	vector<float> ssSpec(0);  //存储峰值对应的功率值 (单位: dBm)。
	vector<float> ssDelt(0);  //存储峰值功率与阈值之间的差值 (单位: dB)。

	SigAndSpur(Frequency, PowerSpec_dBm, -76.0f, ssfreq, ssSpec, ssDelt); //获取功率谱中大于阈值 -76.0 dBm 的峰值信息。

	int sigIndex = distance(ssDelt.begin(), max_element(ssDelt.begin(), ssDelt.end())); //找到差值最大的峰值的索引（即与阈值差距最大的峰值）。

	cout << "index\t" << "frequency\t" << "power\t\t" << "Δlimit" << endl; //打印表头，显示各列的名称：索引、频率、功率、差值。

	for (int i = 0; i < ssDelt.size(); i++) //遍历 ssDelt 中的每个元素，打印每个峰值的信息。
	{
		if (i == sigIndex) //如果当前峰值是差值最大的那个（sigIndex），则使用黄色高亮显示。
		{
			cout << "\033[1;33m"; //设置字体颜色为黄色。
			cout << i << "\t";    //打印当前峰值的索引

			cout.setf(ios::fixed);                                         //设置输出格式为固定小数位。
			cout << fixed << setprecision(9) << ssfreq[i] / 1e9 << "GHz\t";
			cout.unsetf(ios::fixed);                                       //取消固定小数位格式。

			cout << fixed << setprecision(2) << ssSpec[i] << "dBm\t";      //打印当前峰值的功率（单位为 dBm，输出精度为 2 位小数）。

			cout << fixed << setprecision(2) << ssDelt[i] << "dB" << endl; //打印当前峰值与阈值之间的差值（单位为 dB，输出精度为 2 位小数）。
			cout << "\033[m";  // 恢复默认字体颜色。
		}
		else
		{
			cout << i << "\t"; // 如果当前峰值不是差值最大的那个，按普通格式打印。

			cout.setf(ios::fixed);                                          //打印当前峰值的频率（单位为 GHz，输出精度为 9 位小数）。
			cout << fixed << setprecision(9) << ssfreq[i] / 1e9 << "GHz\t";
			cout.unsetf(ios::fixed);                                        //取消固定小数位格式。

			cout << fixed << setprecision(2) << ssSpec[i] << "dBm\t";       //打印当前峰值的功率（单位为 dBm，输出精度为 2 位小数）。

			cout << fixed << setprecision(2) << ssDelt[i] << "dB" << endl;  //打印当前峰值与阈值之间的差值（单位为 dB，输出精度为 2 位小数）
		}
	}

	Device_Close(&Device); //关闭设备。

	return 0;
}




