关于2022年TI省赛--F题信号调制度测量装置

  • 赛题分析
  • 理论分析
    • AM信号处理方案
      • 方案一:
      • 方案二:
    • FM信号处理方案
      • 方案一:
      • 方案二:
    • FFT快速傅里叶变换与逆变换算法
    • 带通抽样定律采样算法
  • 电路设计
  • 程序设计
    • AD9910
    • ADS8885
    • 加窗函数
    • 卡尔曼滤波
    • 主要程序
  • 结语

赛题分析


该装置测量并显示信号源输出的被测信号调制度等参数,识别并显示被测信号的调制方式,并且输出解调信号。该装置能实现频率为10MHz到30MHz正弦波为载波的普通单音调幅波、调频波以及载波的识别,测量对应的调幅度以及调频度输出无明显失真的解调信号。
我们采用抽样峰值检测的方法实现AM波的包络还原再重现对应的解调信号,采用带通抽样定律实现FM波的带宽计算调频度,给示波器显示输出部分采用AD9910DDS直接输出。
第三点有些难度,但不至于做不了,不过限于FM解调模块问题,不能实现全带宽的解调(因为需要有电位器微调,而在复测过程中是不允许的,这点也是坑,尽管我们小组已经使用了两块解调模块进行微调:一块店铺购买,一块自制,还是做不全)

理论分析

AM信号处理方案

方案一:

制作峰值采样电路
优点:即使载波的频率在大范围变化改电路采到的峰值任然为包络线,基本不受载波影响adc采集方便控制简单实现方便。
缺点:需要使用模拟开关以及二极管实现峰值采样,需要控制两个模拟开关交替开启,若同时打开电流较大,稍有不慎会烧毁芯片。

方案二:

使用包络检波电路
优点:电路实现简单,元器件少。
缺点:采样时容易受载波频率的影响,在载波增加时幅值会产生较大的衰减。

FM信号处理方案

方案一:

使用NE564模块,将FM波经过放大之后直接使用锁相环解调
优点: 模块适用带宽范围较大,解调后输出波形平滑不失真。
缺点: 若外部输入信号峰峰值太小会导致NE564模块的解调失败或严重自激。

方案二:

采用FPGA数字解调
优点:处理数据能力快,精度高,能够直接获取信号所有信息,对输入信号的峰峰值要求不高。
缺点:解调算法操作难度大,与外部通信实现度差。

FFT快速傅里叶变换与逆变换算法

为了较快检测到输入波形的谐波分量和失真度,本设计采用了FFT快速傅里叶变换算法。
将输入信号分解为泰勒展开式,对信号的奇偶性成两半:

再令:


式(2.4)只有一个常数项不同,相比普通傅里叶算法,整个计算量缩小了一半。
在实现FFT时,对于输入频率的分辨率可以表示为采样频率与采样点数之比,如式(2.5)。

由式(2.5)可知,输入信号基波频率不是分辨率的整数倍,某一频率的能量将会扩散到相邻频率点上,现频谱泄露的问题,既无法检测到基波频率,也无法准确测到幅值。在测量时要先对原信号频率进行测量,然后选择合适的采样频率和采样点进行计算,以此解决频谱泄露的问题。
在FFT结束并相乘后,得到多项式的点值表示,将点表示转化为系数表示,即可完成离散傅里叶逆变换。该过程可以封装表达为式(2.6)。

其中A意义为多项式的系数表示法;B意义为多项式的点值表示法。
在显示单周期波形时,利用快速傅里叶逆变换,用频率信息还原信号,可以突破对ADC采样点与电压值一一对应的依赖,拟合出多点曲线,使显示波形更加平滑。

带通抽样定律采样算法

根据奈奎斯特采样定理,为了能够完整地重建波形,采样至少应为最高频率的2倍。对于信号频率非常高的情况下,一般ADC达不到如此高的速度,所以带通采样能够节省采样频率,频谱将以采样频率为周期向左右两侧进行周期性延拓。


为了使带通采样的信号不发生混叠,因此平移的时候不能原信号发生混叠:

通过确定采样频率经过FFT计算,将带宽求出,利用带宽与调频度和最后频偏的关系式计算出来。

电路设计

程序设计

本题由于要用到大量的数字信号处理以及FFT计算,因此先引入DSP库准没错

注意:不要忘记在Cube界面中Software Packs中将DSP库勾选上,另外要在生成代码界面中勾选导入所有的 .c/ .h文件,以免DSP库导入不全。
其他的Cube配置没什么好说的,开启ADC+TIM+DMA,做到采样率能精准把控,使能DAC(DAC根据方案才使能,由于电路需求一个偏置电压),使能两串口,一个用于调试,一个用于与串口屏通信,另外需要把串口中断开启。

AD9910

/******************************************************************************** @file     ad9910.h* @brief    ad9910驱动程序* @version  V2.0* @date     2022-7-23** @note*******************************************************************************/
#ifndef __AD9910_H__
#define __AD9910_H__#include "main.h"
#include "usart.h"
#include "ad9910_RegMap.h"#define ulong unsigned long intextern uint8_t cfr2[4]; //cfr2控制字
extern uint8_t cfr1[4]; //cfr1控制字#define REEST(x)                       x?HAL_GPIO_WritePin(RST_GPIO_Port,RST_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(RST_GPIO_Port,RST_Pin,GPIO_PIN_RESET)             //RST
#define AD9910_PWR(x)           x?HAL_GPIO_WritePin(PWR_GPIO_Port,PWR_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PWR_GPIO_Port,PWR_Pin,GPIO_PIN_RESET)             //PWR#define PROFILE2(x)                x?HAL_GPIO_WritePin(PF2_GPIO_Port,PF2_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PF2_GPIO_Port,PF2_Pin,GPIO_PIN_RESET)             //PF2
#define PROFILE1(x)                 x?HAL_GPIO_WritePin(PF1_GPIO_Port,PF1_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PF1_GPIO_Port,PF1_Pin,GPIO_PIN_RESET)             //PF1
#define PROFILE0(x)                 x?HAL_GPIO_WritePin(PF0_GPIO_Port,PF0_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PF0_GPIO_Port,PF0_Pin,GPIO_PIN_RESET)             //PF0
#define IOUP(x)                         x?HAL_GPIO_WritePin(IOUP_GPIO_Port,IOUP_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(IOUP_GPIO_Port,IOUP_Pin,GPIO_PIN_RESET)             //IOUP
#define OSK(x)                          x?HAL_GPIO_WritePin(OSK_GPIO_Port,OSK_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(OSK_GPIO_Port,OSK_Pin,GPIO_PIN_RESET)             //OSK#define DROVER(x)                  x?HAL_GPIO_WritePin(DRO_GPIO_Port,DRO_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(DRO_GPIO_Port,DRO_Pin,GPIO_PIN_RESET)             //DRO
#define DRCTL(x)                        x?HAL_GPIO_WritePin(DRC_GPIO_Port,DRC_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(DRC_GPIO_Port,DRC_Pin,GPIO_PIN_RESET)             //DRC
#define DRHOLD(x)                   x?HAL_GPIO_WritePin(DRH_GPIO_Port,DRH_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(DRH_GPIO_Port,DRH_Pin,GPIO_PIN_RESET)             //DPH
#define AD9910_SDIO(x)          x?HAL_GPIO_WritePin(SDIO_GPIO_Port,SDIO_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(SDIO_GPIO_Port,SDIO_Pin,GPIO_PIN_RESET)             //SDIO#define SCLK(x)                       x?HAL_GPIO_WritePin(SCK_GPIO_Port,SCK_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(SCK_GPIO_Port,SCK_Pin,GPIO_PIN_RESET)         //SCK
#define CSB(x)                          x?HAL_GPIO_WritePin(CSB_GPIO_Port,CSB_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(CSB_GPIO_Port,CSB_Pin,GPIO_PIN_RESET)             //CSBvoid Init_AD9910(void);void Freq_convert(ulong Freq);            //写频率
void Amp_convert(uint32_t Amplitude);       //写幅度
void Set_cfr(void);
void Set_RAMprofile(void);
void Set_RAMdata(uint8_t wave_num);void SweepFre(ulong Fre_L, ulong Fre_H, ulong StepFre, ulong SweepTime); //扫频
void Square_wave(uint32_t Sample_interval);     //方波;
void Sawtooth_wave(uint32_t Sample_interval);   //三角波void AD9910_Init(void);void Txd_8bit(uint8_t txData);              //ad9910写入的8位数据
void Txd_16bit(uint16_t txData);            //ad9910写入的16位数据
void Txd_32bit(uint32_t txData);            //ad9910写入的32位数据
void Txd_64bit(uint64_t txData);            //ad9910写入的64位数据void TxCfr(void);                                           //ad9910发送频率值程序
void TxDRG(void);                                           //ad9910发送DRG参数程序
void Freq_convert_firm(uint64_t Freq);          //ad9910计算频偏字、频率字和发送程序
void write_Amplitude(uint32_t Amp);     //ad9910计算幅度字和发送程序
void SweepFre_firm(uint64_t SweepMinFre, uint64_t SweepMaxFre, uint64_t SweepStepFre, uint64_t SweepTime);      //ad9910设置扫频信号#endif
/******************************************************************************** @file     ad9910.h* @brief    ad9910驱动程序* @version  V2.0* @date     2022-7-23** @note*******************************************************************************/#include "ad9910.h"uint8_t cfr1[] = {0x00, 0x40, 0x00, 0x00};                       //cfr1控制字
uint8_t cfr2[] = {0x01, 0x00, 0x00, 0x00};                       //cfr2控制字
uint8_t cfr3[] = {0x05, 0x0F, 0x41, 0x32};                       //cfr3控制字  40M输入  25倍频  VC0=101   ICP=001;
uint8_t profile11[] = {0x3f, 0xff, 0x00, 0x00, 0x25, 0x09, 0x7b, 0x42}; //profile1控制字 0x25,0x09,0x7b,0x42//01振幅控制 23相位控制 4567频率调谐字uint8_t ramprofile0[8] = {0x00};    //ramprofile0控制字
uint8_t drgparameter[20]={0x00};//高14位幅度控制
const uint8_t ramdata_Square[4096] =
{
//方波0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
};//高14位幅度控制
const uint8_t ramdata_Sawtooth[4096] =
{//锯齿波0x00,0x00,0x00,0x00, 0x03,0xfc,0x00,0x00, 0x07,0xf8,0x00,0x00, 0x0b,0xf4,0x00,0x00, 0x0f,0xf0,0x00,0x00, 0x13,0xec,0x00,0x00, 0x17,0xe8,0x00,0x00, 0x1b,0xe4,0x00,0x00, 0x1f,0xe0,0x00,0x00, 0x23,0xdc,0x00,0x00, 0x27,0xd8,0x00,0x00, 0x2b,0xd4,0x00,0x00, 0x2f,0xd0,0x00,0x00, 0x33,0xcc,0x00,0x00, 0x37,0xc8,0x00,0x00, 0x3b,0xc4,0x00,0x00, 0x3f,0xc0,0x00,0x00, 0x43,0xbc,0x00,0x00, 0x47,0xb8,0x00,0x00, 0x4b,0xb4,0x00,0x00, 0x4f,0xb0,0x00,0x00, 0x53,0xac,0x00,0x00, 0x57,0xa8,0x00,0x00, 0x5b,0xa4,0x00,0x00, 0x5f,0xa0,0x00,0x00, 0x63,0x9c,0x00,0x00, 0x67,0x98,0x00,0x00, 0x6b,0x94,0x00,0x00, 0x6f,0x90,0x00,0x00, 0x73,0x8c,0x00,0x00, 0x77,0x88,0x00,0x00, 0x7b,0x84,0x00,0x00,    0x7f,0x80,0x00,0x00, 0x83,0x7c,0x00,0x00, 0x87,0x78,0x00,0x00, 0x8b,0x74,0x00,0x00, 0x8f,0x70,0x00,0x00, 0x93,0x6c,0x00,0x00, 0x97,0x68,0x00,0x00, 0x9b,0x64,0x00,0x00, 0x9f,0x60,0x00,0x00, 0xa3,0x5c,0x00,0x00, 0xa7,0x58,0x00,0x00, 0xab,0x54,0x00,0x00, 0xaf,0x50,0x00,0x00, 0xb3,0x4c,0x00,0x00, 0xb7,0x48,0x00,0x00, 0xbb,0x44,0x00,0x00, 0xbf,0x40,0x00,0x00, 0xc3,0x3c,0x00,0x00, 0xc7,0x38,0x00,0x00, 0xcb,0x34,0x00,0x00, 0xcf,0x30,0x00,0x00, 0xd3,0x2c,0x00,0x00, 0xd7,0x28,0x00,0x00, 0xdb,0x24,0x00,0x00, 0xdf,0x20,0x00,0x00, 0xe3,0x1c,0x00,0x00, 0xe7,0x18,0x00,0x00, 0xeb,0x14,0x00,0x00, 0xef,0x10,0x00,0x00, 0xf3,0x0c,0x00,0x00, 0xf7,0x08,0x00,0x00, 0xfb,0x04,0x00,0x00,
};/********************************************************************
* 函数: Set_bit(uint8_t dat)
* 参数: dat: 要发送的数据
* 说明: 发送数据到AD9910
********************************************************************/
static void Set_bit(uint8_t dat)
{uint8_t i, sbt;sbt = 0x80;SCLK(0);for (i = 0; i < 8; i++){if((dat & sbt) == 0)AD9910_SDIO(0);elseAD9910_SDIO(1);SCLK(1);sbt = sbt >> 1;SCLK(0);}
}/********************************************************************
* 函数: Set_Control_word(uint16_t Addr, uint8_t *Str)
* 参数: Addr: CFRx控制地址*Str: CFRx控制字num:    要发送的控制字数量,即数组长度
* 说明: 写控制字到AD9910寄存器
********************************************************************/
static void Set_Control_word(uint16_t Addr, uint8_t *Str, uint16_t num)
{uint8_t i = 0;CSB(0);Set_bit(Addr);for(i=0; i<num; i++)Set_bit( *(Str + i) );CSB(1);HAL_Delay_us(10);
}/********************************************************************
* 函数: Set_cfr(void)
* 参数: 无
* 说明: 发送CFRx控制字
********************************************************************/
void Set_cfr(void)
{Set_Control_word(0x00, cfr1, 4);//写CFRSet_Control_word(0x01, cfr2, 4);Set_Control_word(0x02, cfr3, 4);IOUP(1);HAL_Delay_us(10);IOUP(0);HAL_Delay(1);
}/********************************************************************
* 函数: Init_AD9910(void)
* 参数: 无
* 说明: AD9910 初始化
********************************************************************/
void Init_AD9910(void)
{AD9910_PWR(0);          //软件拉低PROFILE0(0);PROFILE1(0);PROFILE2(0);DRCTL(0);DRHOLD(0);REEST(1);HAL_Delay(5);REEST(0);}/********************************************************************
* 函数: Set_prodile0(void)
* 参数: 无
* 说明: AD9910 发送profile0控制字
********************************************************************/
static void Set_prodile0(void)
{Set_Control_word(0x0e, profile11, 8);//写profile0控制字IOUP(1);IOUP(0);
}/********************************************************************
* 函数: Freq_convert(ulong Freq)
* 参数: Freq: 频率
* 说明: 计算频偏字、频率字
********************************************************************/
void Freq_convert(ulong Freq)
{ulong Temp;Temp = (ulong)Freq * 4.294967296 * 1.4285714286; //将输入频率因子分为四个字节  4.294967296=(2^32)/1000000000profile11[7] = (uint8_t)Temp;profile11[6] = (uint8_t)(Temp >> 8);profile11[5] = (uint8_t)(Temp >> 16);profile11[4] = (uint8_t)(Temp >> 24);Set_prodile0();
}/********************************************************************
* 函数: Amp_convert(uint32_t Amp)
* 参数: Amp: 幅值
* 说明: 计算幅值
********************************************************************/
void Amp_convert(uint32_t Amp)
{ulong Temp;Temp = (ulong)(Amp * 21.84533); //将输入幅度因子分为两个字节  21.84533=(2^14)/750if (Temp > 0x3fff)Temp = 0x3fff;Temp &= 0x3fff;profile11[1] = (uint8_t)Temp;profile11[0] = (uint8_t)(Temp >> 8);Set_prodile0();
}/********************************************************************
* 函数: Set_DRG(void)
* 参数: 无
* 说明: 发送DRG参数
********************************************************************/
static void Set_DRG(void)
{Set_Control_word(0x0b, drgparameter,8);Set_Control_word(0x0c, drgparameter+8,8);Set_Control_word(0x0c, drgparameter+16,4);IOUP(1);HAL_Delay_us(10);IOUP(0);HAL_Delay(1);
}/********************************************************************
* 函数: SweepFre(ulong Fre_L, ulong Fre_H, ulong StepFre, ulong SweepTime)
* 参数: Fre_L:         扫频最低频率       HzFre_H:       设置扫频上限频率 HzStepFre:     设置步进频率       HzSweepTime:   设置步进时间间隔 us
* 说明: 扫频参数设置
********************************************************************/
void SweepFre(ulong Fre_L, ulong Fre_H, ulong StepFre, ulong SweepTime)
{ulong Temp1, Temp2, ITemp3, DTemp3, ITemp4, DTemp4;Temp1 = (ulong)Fre_L*4.294967296;if(Fre_H > 400000000)Fre_H = 400000000;Temp2 = (ulong)Fre_H*4.294967296;if(StepFre > 400000000)StepFre = 400000000;ITemp3 = (ulong)StepFre*4.294967296;DTemp3 = ITemp3;ITemp4 = (ulong)SweepTime/4;             //1GHz/4, 单位:nsif(ITemp4 > 0xffff)ITemp4 = 0xffff;DTemp4 = ITemp4;//扫频上下限drgparameter[7]=(uint8_t)Temp1;drgparameter[6]=(uint8_t)(Temp1>>8);drgparameter[5]=(uint8_t)(Temp1>>16);drgparameter[4]=(uint8_t)(Temp1>>24);drgparameter[3]=(uint8_t)Temp2;drgparameter[2]=(uint8_t)(Temp2>>8);drgparameter[1]=(uint8_t)(Temp2>>16);drgparameter[0]=(uint8_t)(Temp2>>24);//频率步进(单位:Hz)drgparameter[15]=(uint8_t)ITemp3;drgparameter[14]=(uint8_t)(ITemp3>>8);drgparameter[13]=(uint8_t)(ITemp3>>16);drgparameter[12]=(uint8_t)(ITemp3>>24);drgparameter[11]=(uint8_t)DTemp3;drgparameter[10]=(uint8_t)(DTemp3>>8);drgparameter[9]=(uint8_t)(DTemp3>>16);drgparameter[8]=(uint8_t)(DTemp3>>24);//步进时间间隔(单位:us)drgparameter[19]=(uint8_t)ITemp4;drgparameter[18]=(uint8_t)(ITemp4>>8);drgparameter[17]=(uint8_t)DTemp4;drgparameter[16]=(uint8_t)(DTemp4>>8);//发送DRG参数Set_DRG();cfr1[0] = 0x00; //RAM 失能cfr2[1] = 0x0e; //DRG 使能Set_cfr();            //发送cfrx控制字
}/********************************************************************
* 函数: Set_RAMprofile(void)
* 参数: 无
* 说明: 发送RAM profile0控制字
********************************************************************/
void Set_RAMprofile(void)
{Set_Control_word(0x0e, ramprofile0, 8);//发送RAM profile0控制字IOUP(1);HAL_Delay_us(10);IOUP(0);HAL_Delay(1);
}/********************************************************************
* 函数: Set_RAMdata(int wave_num)
* 参数: wave_num: 输出选择,1方波,0锯齿波
* 说明: 发送RAM控制字
********************************************************************/
void Set_RAMdata(uint8_t wave_num)
{        if(wave_num==1){     uint16_t m = 0;CSB(0);Set_bit(0x16);                      //发送ram控制字地址for (m=0; m<4096; m++)Set_bit(ramdata_Square[m]); CSB(1);HAL_Delay_us(10);IOUP(1);HAL_Delay_us(10);IOUP(0);HAL_Delay(1);}else{uint16_t m = 0;CSB(0);Set_bit(0x16);                      //发送ram控制字地址for (m=0; m<4096; m++)Set_bit(ramdata_Sawtooth[m]); CSB(1);HAL_Delay_us(10);IOUP(1);HAL_Delay_us(10);IOUP(0);HAL_Delay(1);}
}/********************************************************************
* 函数: Square_wave(uint32_t Sample_interval)
* 参数: Sample_interval:  采样频率
* 说明: 产生方波
********************************************************************/
void Square_wave(uint32_t Sample_interval)
{ulong Temp;//1GHz/4, 采样间隔范围:4*(1~65536)nsTemp = ((1000000000/(unsigned long int)(Sample_interval)/64/4)); if(Temp > 0xffff)Temp = 0xffff;ramprofile0[7] = 0x24;ramprofile0[6] = 0x00;ramprofile0[5] = 0x00;ramprofile0[4] = 0xc0;ramprofile0[3] = 0x0f;ramprofile0[2] = (uint8_t)Temp;ramprofile0[1] = (uint8_t)(Temp>>8);ramprofile0[0] = 0x00;Set_RAMprofile();Set_RAMdata(1); cfr1[0] = 0xc0;        //RAM 使能,幅度控制cfr2[1] = 0x00;        //DRG 失能Set_cfr();             //发送cfrx控制字
}/********************************************************************
* 函数: Sawtooth_wave(uint32_t Sample_interval)
* 参数: Sample_interval:  采样频率
* 说明: 产生锯齿波
********************************************************************/
void Sawtooth_wave(uint32_t Sample_interval)
{ulong Temp;//1GHz/4, 采样间隔范围:4*(1~65536)nsTemp = ((1000000000/(unsigned long int)(Sample_interval)/64/4));if(Temp > 0xffff)Temp = 0xffff;ramprofile0[7] = 0x24;ramprofile0[6] = 0x00;ramprofile0[5] = 0x00;ramprofile0[4] = 0xc0;ramprofile0[3] = 0x0f;ramprofile0[2] = (uint8_t)Temp;ramprofile0[1] = (uint8_t)(Temp>>8);ramprofile0[0] = 0x00;Set_RAMprofile();Set_RAMdata(0); cfr1[0] = 0xc0;                          //RAM 使能,幅度控制cfr2[1] = 0x00;                          //DRG 失能Set_cfr();                               //发送cfrx控制字
}/* ======================================================================================================================================= *//*** @brief  ad9910写入的8位数据(地址)* @param  txData   写入的8位数据(地址)* @return none* @note      寄存器地址,单个字节操作*/
void Txd_8bit(uint8_t txData)
{uint8_t i,dat;dat=0x80;SCLK(0);for(i=0;i<8;i++){if((txData&dat)==0)AD9910_SDIO(0);elseAD9910_SDIO(1);SCLK(1);dat>>=1;SCLK(0);}
}/*** @brief  ad9910发送频率值程序* @param  none* @return none* @note      */
void TxCfr(void)
{uint8_t i;CSB(0);Txd_8bit(regControlSFMProfile0);for(i=0;i<8;i++)Txd_8bit(profile11[i]);CSB(1);IOUP(1);HAL_Delay(1);IOUP(0);
}/*** @brief  ad9910计算频偏字、频率字和发送程序* @param  Freq  填入的频率值* @return none* @note       */
void Freq_convert_firm(uint64_t Freq)
{uint64_t Temp;Temp=(uint64_t)Freq*4.294967296;       //将输入频率因子分为四个字节  4.294967296=(2^32)/1000000000Temp=Temp*1.44;profile11[7]=(uint8_t)Temp;profile11[6]=(uint8_t)(Temp>>8);profile11[5]=(uint8_t)(Temp>>16);profile11[4]=(uint8_t)(Temp>>24);TxCfr();
}/*** @brief  ad9910计算幅度字和发送程序* @param  Amp   幅度字* @return none* @note      */
void write_Amplitude(uint32_t Amp)
{uint64_t temp;temp = (uint64_t)Amp * 25.20615385;//将输入幅度因子分为两个字节,25.20615385 = 2^14/650;if(temp > 0x3fff)temp = 0x3fff;temp &= 0x3fff;profile11[1] = (uint8_t)temp;profile11[0] = (uint8_t)(temp >> 8);TxCfr();
}/*** @brief  ad9910设置扫频信号* @param  Amp   幅度字* @return none* @note      */
void SweepFre_firm(uint64_t SweepMinFre, uint64_t SweepMaxFre, uint64_t SweepStepFre, uint64_t SweepTime)
{uint64_t Temp1, Temp2, ITemp3, DTemp3, ITemp4, DTemp4;Temp1 = (uint64_t)SweepMinFre*4.294967296;if(SweepMaxFre > 400000000)SweepMaxFre = 400000000;Temp2 = (uint64_t)SweepMaxFre*4.294967296;if(SweepStepFre > 400000000)SweepStepFre = 400000000;ITemp3 = (uint64_t)SweepStepFre*4.294967296;DTemp3 = ITemp3;ITemp4 = (uint64_t)SweepTime/4; //1GHz/4, 单位:nsif(ITemp4 > 0xffff)ITemp4 = 0xffff;DTemp4 = ITemp4;//扫频上下限drgparameter[7]=(uint8_t)Temp1;drgparameter[6]=(uint8_t)(Temp1>>8);drgparameter[5]=(uint8_t)(Temp1>>16);drgparameter[4]=(uint8_t)(Temp1>>24);drgparameter[3]=(uint8_t)Temp2;drgparameter[2]=(uint8_t)(Temp2>>8);drgparameter[1]=(uint8_t)(Temp2>>16);drgparameter[0]=(uint8_t)(Temp2>>24);//频率步进(单位:Hz)drgparameter[15]=(uint8_t)ITemp3;drgparameter[14]=(uint8_t)(ITemp3>>8);drgparameter[13]=(uint8_t)(ITemp3>>16);drgparameter[12]=(uint8_t)(ITemp3>>24);drgparameter[11]=(uint8_t)DTemp3;drgparameter[10]=(uint8_t)(DTemp3>>8);drgparameter[9]=(uint8_t)(DTemp3>>16);drgparameter[8]=(uint8_t)(DTemp3>>24);//步进时间间隔(单位:us)drgparameter[19]=(uint8_t)ITemp4;drgparameter[18]=(uint8_t)(ITemp4>>8);drgparameter[17]=(uint8_t)DTemp4;drgparameter[16]=(uint8_t)(DTemp4>>8);//发送DRG参数TxDRG();
}/*** @brief  ad9910发送DRG参数程序* @param  none* @return none* @note        */
void TxDRG(void)
{uint8_t m,k;CSB(0);Txd_8bit(0x0b);    //发送数字斜坡限制地址0x0bfor (m=0;m<8;m++)Txd_8bit(drgparameter[m]); CSB(1);for(k=0;k<10;k++);CSB(0);Txd_8bit(0x0c);    //发送数字斜坡步长地址0x0cfor (m=8;m<16;m++)Txd_8bit(drgparameter[m]); CSB(1);for(k=0;k<10;k++);CSB(0);Txd_8bit(0x0d);    //发送数字斜坡速率地址0x0dfor (m=16;m<20;m++)Txd_8bit(drgparameter[m]); CSB(1);for(k=0;k<10;k++);IOUP(1);for(k=0;k<10;k++);IOUP(0);HAL_Delay(1);
}static void AD9910_GPIO_Config(void)
{REEST(0);
}static void AD9910_CFR_Config(void)
{uint8_t k,m;AD9910_GPIO_Config();          //IO口初始化AD9910_PWR(0);PROFILE0(0);  PROFILE1(0);    PROFILE2(0);DRHOLD(0);  DRCTL(0);REEST(1);  HAL_Delay(5);   REEST(0);CSB(0);Txd_8bit(regControlCFR1);for(m=0;m<4;m++)Txd_8bit(cfr1[m]);CSB(1);for (k=0;k<10;k++);CSB(0);Txd_8bit(regControlCFR2);for(m=0;m<4;m++)Txd_8bit(cfr2[m]);CSB(1);for (k=0;k<10;k++);CSB(0);Txd_8bit(regControlCFR3);for(m=0;m<4;m++)Txd_8bit(cfr3[m]);CSB(1);for (k=0;k<10;k++);IOUP(1);for(k=0;k<10;k++);IOUP(0);HAL_Delay(1);
}void AD9910_Init(void)
{AD9910_CFR_Config();
}/*** @brief  ad9910写入的16位数据* @param  txData  写入的16位数据* @return none* @note     POW寄存器操作,双位字节操作*/
void Txd_16bit(uint16_t txData)
{uint8_t i;uint16_t dat;dat=0x8000;SCLK(0);for(i=0;i<16;i++){if((txData&dat)==0)AD9910_SDIO(0);elseAD9910_SDIO(1);SCLK(1);dat>>=1;SCLK(0);}
}/*** @brief  ad9910写入的32位数据* @param  txData  写入的32位数据* @return none* @note     对CFR1~3、DAC、IO更新速率、FTW、ASF、多芯片同步、斜坡速率、RAM操作*/
void Txd_32bit(uint32_t txData)
{uint8_t i;uint32_t dat;dat=0x80000000;SCLK(0);for(i=0;i<32;i++){if((txData&dat)==0)AD9910_SDIO(0);elseAD9910_SDIO(1);SCLK(1);dat>>=1;SCLK(0);}
}/*** @brief  ad9910写入的64位数据* @param  txData  写入的64位数据* @return none* @note     对斜坡限值、斜坡步长、Profile0~7(单频调制、RAM)操作*/
void Txd_64bit(uint64_t txData)
{uint8_t i;uint64_t dat;dat=0x8000000000000000;SCLK(0);for(i=0;i<64;i++){if((txData&dat)==0)AD9910_SDIO(0);elseAD9910_SDIO(1);SCLK(1);dat>>=1;SCLK(0);}
}

ADS8885

/******************************************************************************** @file     ads8885.h* @brief    ads8885驱动头文件* @version  V1.0* @date     2021-10-27** @note*******************************************************************************/
#ifndef __ADS_8885_H
#define __ADS_8885_H#include "main.h"
//#include "spi.h"
#include "soft_spi.h"
#include "gpio.h"
#include "usart.h"extern enum {   Wire3Soft_1=0,Wire3Soft_2,Wire4Soft_1,Wire4Soft_2} mode;#define CTL_H              HAL_GPIO_WritePin(CTL_GPIO_Port, CTL_Pin, GPIO_PIN_SET)
#define CTL_L           HAL_GPIO_WritePin(CTL_GPIO_Port, CTL_Pin, GPIO_PIN_RESET)
//#define DIN_H         HAL_GPIO_WritePin(DIN_GPIO_Port, DIN_Pin, GPIO_PIN_SET)
//#define DIN_L         HAL_GPIO_WritePin(DIN_GPIO_Port, DIN_Pin, GPIO_PIN_RESET)
#define CONVST_H    HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_SET)
#define CONVST_L    HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_RESET)//uint32_t getData_3Wire(void);
uint32_t getData_3WireSoft(void);
uint32_t getData_4WireSoft(void);double TansformData(uint8_t mode);void getRData(float *data, int Avg);/*                           第二块ADS8885                          */
#define CTL2_H              HAL_GPIO_WritePin(CTL2_GPIO_Port, CTL2_Pin, GPIO_PIN_SET)
#define CTL2_L              HAL_GPIO_WritePin(CTL2_GPIO_Port, CTL2_Pin, GPIO_PIN_RESET)
#define CVST2_H         HAL_GPIO_WritePin(CVST2_GPIO_Port, CVST2_Pin, GPIO_PIN_SET)
#define CVST2_L         HAL_GPIO_WritePin(CVST2_GPIO_Port, CVST2_Pin, GPIO_PIN_RESET)           uint32_t getData2_3WireSoft(void);
double TansformData_2ADS(uint8_t mode);
void getRData_2ADS(float *data, int Avg);#endif
#ifndef __SOFT_SPI_H
#define __SOFT_SPI_H#include "main.h"
#include "gpio.h"
#include "usart.h"#define MOSI_H  HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET)
#define MOSI_L  HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET)
#define SCLK_H   HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET)
#define SCLK_L   HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_RESET)
#define MISO    HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin)/* CPOL = 0, CPHA = 0, MSB first MODE0*/
uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat );
uint8_t SPI_Receiver_MODE0(void);
/* CPOL=0,CPHA=1, MSB first MODE1*/
uint8_t SOFT_SPI_RW_MODE1(uint8_t byte) ;
uint8_t SPI_Receiver_MODE1(void);
uint32_t SPI_Re_18Data(void);
/* CPOL=1,CPHA=0, MSB first MODE2*/
uint8_t SOFT_SPI_RW_MODE2(uint8_t byte) ;
uint8_t SPI_Receiver_MODE2(void);
/* CPOL = 1, CPHA = 1, MSB first MODE3*/
uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat );
uint8_t SPI_Receiver_MODE3(void);/*                           第二块ADS8885                          */
#define MOSI2_H     HAL_GPIO_WritePin(MOSI2_GPIO_Port, MOSI2_Pin, GPIO_PIN_SET)
#define MOSI2_L     HAL_GPIO_WritePin(MOSI2_GPIO_Port, MOSI2_Pin, GPIO_PIN_RESET)
#define SCLK2_H   HAL_GPIO_WritePin(SCLK2_GPIO_Port, SCLK2_Pin, GPIO_PIN_SET)
#define SCLK2_L   HAL_GPIO_WritePin(SCLK2_GPIO_Port, SCLK2_Pin, GPIO_PIN_RESET)
#define MISO2       HAL_GPIO_ReadPin(MISO2_GPIO_Port, MISO2_Pin)uint32_t SPI2_Re_18Data(void);#endif
/******************************************************************************** @file     ads8885.c* @brief    ads8885* @version  V1.0* @date     2021-10-27** @note*******************************************************************************/
#include "ads8885.h"/*ADS8885 三线操作*/
uint32_t getData_3WireSoft(void)
{uint32_t data;CTL_L;CONVST_H;HAL_Delay_us(1);CONVST_L;data = SPI_Re_18Data();CONVST_H;CTL_H;return data;
}uint32_t getData2_3WireSoft(void)
{uint32_t data;CTL2_L;CVST2_H;HAL_Delay_us(1);CVST2_L;data = SPI2_Re_18Data();CVST2_H;CTL2_H;return data;
}/*ADS8885 四线操作*/
/*
uint32_t getData_4WireSoft(void)
{uint32_t data;CTL_L;DIN_H;CONVST_H;HAL_Delay_us(1);DIN_L;data = SPI_Re_18Data();DIN_H;CONVST_L;CONVST_H;return data;
}
*/double TansformData(uint8_t mode)
{double transdata;uint32_t data;
//  if(mode == Wire3Soft_1)
//  {//      data = getData_3WireSoft()+105;data = getData_3WireSoft();if(data & 0x20000){transdata = ((double)(data&0x1ffff)*4.096)/131071;if(transdata > 8)return 0;return transdata-4.096;}else {transdata = ((double)data*4.096)/131071;if(transdata > 8)return 0;return transdata;}return 0;
}void getRData(float *data, int Avg)
{for(int i=0;i<Avg;i++){data[i] = TansformData(Wire3Soft_1);
//      HAL_Delay_us(1);}
}/*                           第二块ADS8885                          */
double TansformData_2ADS(uint8_t mode)
{double transdata;uint32_t data;data = getData2_3WireSoft();if(data & 0x20000){transdata = ((double)(data&0x1ffff)*4.096)/131071;if(transdata > 8)return 0;return transdata-4.096;}else {transdata = ((double)data*4.096)/131071;if(transdata > 8)return 0;return transdata;}return 0;
}
void getRData_2ADS(float *data, int Avg)
{for(int i=0;i<Avg;i++){data[i] = TansformData_2ADS(Wire3Soft_1);}
}#if 0          //硬件SPI
uint32_t getData_3Wire(void)
{uint32_t data;uint8_t dat[3]={0};HAL_GPIO_WritePin(CTL_GPIO_Port,CTL_Pin,GPIO_PIN_SET);       //拉低CTL引脚,保持电平HAL_GPIO_WritePin(CONVST_GPIO_Port,CONVST_Pin,GPIO_PIN_SET);HAL_Delay_us(1);HAL_GPIO_WritePin(CONVST_GPIO_Port,CONVST_Pin,GPIO_PIN_RESET);if(HAL_SPI_Receive(&hspi3,(uint8_t*)dat,3,0xff) == HAL_OK){data = ((dat[0]<<16) | (dat[1]<<8) | dat[2]);}HAL_GPIO_WritePin(CTL_GPIO_Port,CTL_Pin,GPIO_PIN_RESET);     //拉高CTL引脚,进行下一次转换HAL_Delay_us(1);return data;
}
#endif
#include "soft_spi.h"/*********************************************
模式零         读数据
*********************************************/
/* CPOL = 0, CPHA = 0, MSB first MODE0*/
uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat )
{uint8_t i, read_dat;for( i = 0; i < 8; i++ ){if( write_dat & 0x80 )MOSI_H;else                    MOSI_L;  write_dat <<= 1;HAL_Delay_us(1);   SCLK_H; read_dat <<= 1;  if( MISO ) read_dat++; HAL_Delay_us(1);SCLK_L; __nop();}return read_dat;
}
uint8_t SPI_Receiver_MODE0(void)
{uint8_t n ,dat;for(n=0;n<8;n++){SCLK_L;dat<<=1;if(MISO)       //读取电平dat|=0x01;else dat&=0xfe;SCLK_H;}SCLK_L;return dat;
}/*********************************************
模式一       读数据
*********************************************/
/* CPOL=0,CPHA=1, MSB first MODE1*/
uint8_t SOFT_SPI_RW_MODE1(uint8_t byte)
{uint8_t i,Temp=0;for(i=0;i<8;i++)     // 循环8次{SCLK_H;     //拉高时钟if(byte&0x80){MOSI_H;  //若最到位为高,则输出高}else      {MOSI_L;   //若最到位为低,则输出低}byte <<= 1;     // 低一位移位到最高位HAL_Delay_us(1);SCLK_L;     //拉低时钟Temp <<= 1;     //数据左移if(MISO)Temp++;     //若从从机接收到高电平,数据自加一HAL_Delay_us(1);}return (Temp);     //返回数据
}uint8_t SPI_Receiver_MODE1(void)
{uint8_t n ,dat=0;for(n=0;n<8;n++){SCLK_H;dat<<=1;if(MISO)dat|=0x01;else dat&=0xfe;SCLK_L;}SCLK_L;return dat;
}
uint32_t SPI_Re_18Data(void)
{uint8_t n ;uint32_t dat=0;for(n=0;n<18;n++){#if 1SCLK_H;dat<<=1;if(MISO)dat|=0x00001;else dat&=0x3ffff;SCLK_L;}SCLK_L;dat = (~dat) & (0x3ffff);#endifreturn dat;
}uint32_t SPI2_Re_18Data(void)
{uint8_t n ;uint32_t dat=0;for(n=0;n<18;n++){#if 1SCLK2_H;dat<<=1;if(MISO2)dat|=0x00001;else dat&=0x3ffff;SCLK2_L;}SCLK2_L;dat = (~dat) & (0x3ffff);#endifreturn dat;
}/*********************************************
模式二          读数据
*********************************************/
/* CPOL=1,CPHA=0, MSB first MODE2*/
uint8_t SOFT_SPI_RW_MODE2(uint8_t byte)
{uint8_t i,Temp=0;for(i=0;i<8;i++)     // 循环8次{if(byte&0x80){MOSI_H;  //若最到位为高,则输出高}else      {MOSI_L;   //若最到位为低,则输出低}byte <<= 1;     // 低一位移位到最高位HAL_Delay_us(1);SCLK_L;     //拉低时钟Temp <<= 1;     //数据左移if(MISO)Temp++;     //若从从机接收到高电平,数据自加一HAL_Delay_us(1);SCLK_H;     //拉高时钟}return (Temp);     //返回数据
}uint8_t SPI_Receiver_MODE2(void)
{uint8_t n ,dat;for(n=0;n<8;n++){SCLK_H;dat<<=1;if(MISO)dat|=0x01;else dat&=0xfe;SCLK_L;}SCLK_L;return dat;
}/************************************
模式三          读数据
************************************/
/* CPOL = 1, CPHA = 1, MSB first MODE3*/
uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat )
{uint8_t i, read_dat;for( i = 0; i < 8; i++ ){SCLK_L;if( write_dat & 0x80 )MOSI_H;  elseMOSI_L;  write_dat <<= 1;HAL_Delay_us(1);  SCLK_H; read_dat <<= 1;  if( MISO ) read_dat++; HAL_Delay_us(1);__nop();}return read_dat;
}uint8_t SPI_Receiver_MODE3(void)
{uint8_t n ,dat;SCLK_L;for(n=0;n<8;n++){ SCLK_L;dat<<=1;if(MISO)dat|=0x01;else dat&=0xfe;SCLK_H;}SCLK_H;return dat;
}

注意:由于是使用了两块ADS8885分别对AM和FM两路解调信号进行采样,采到的数据经过加窗,FFT处理,可以得到解调信号的频率

加窗函数

/*
*file       WindowFunction.h
*author     Vincent Cui
*e-mail     whcui1987@163.com
*version    0.3
*data       31-Oct-2014
*brief      各种窗函数的C语言实现
*/#ifndef _WINDOWFUNCTION_H_
#define _WINDOWFUNCTION_H_#include <stdint.h>#define besseli_Flag 0   //缺少besseli函数
#define prod_Flag       0   //缺少prod函数
#define linSpace_Flag   0   //缺少linSpace函数#define BESSELI_K_LENGTH 10#define FLATTOPWIN_A0  0.215578995
#define FLATTOPWIN_A1  0.41663158
#define FLATTOPWIN_A2  0.277263158
#define FLATTOPWIN_A3  0.083578947
#define FLATTOPWIN_A4  0.006947368#define NUTTALL_A0   0.3635819
#define NUTTALL_A1   0.4891775
#define NUTTALL_A2   0.1365995
#define NUTTALL_A3   0.0106411#define BLACKMANHARRIS_A0 0.35875
#define BLACKMANHARRIS_A1 0.48829
#define BLACKMANHARRIS_A2 0.14128
#define BLACKMANHARRIS_A3 0.01168#define PI 3.14159265358979323846264338327950288419717  //定义圆周率值typedef enum
{DSP_ERROR = 0,DSP_SUCESS,
}dspErrorStatus;dspErrorStatus triangularWin(uint16_t N, double w[]);
dspErrorStatus bartlettWin(uint16_t N, double w[]);
dspErrorStatus bartLettHannWin(uint16_t N, double w[]);
dspErrorStatus blackManWin(uint16_t N, double w[]);
dspErrorStatus blackManHarrisWin(uint16_t N, double w[]);
dspErrorStatus bohmanWin(uint16_t N, double w[]);
dspErrorStatus chebyshevWin(uint16_t N, double r, double w[]);
dspErrorStatus flatTopWin(uint16_t N, double w[]);
dspErrorStatus gaussianWin(uint16_t N, double alpha, double w[]);
dspErrorStatus hammingWin(uint16_t N, double w[]);
dspErrorStatus hannWin(uint16_t N, double w[]);
dspErrorStatus nuttalWin(uint16_t N, double w[]);
dspErrorStatus parzenWin(uint16_t N, double w[]);
dspErrorStatus rectangularWin(uint16_t N, double w[]);#if besseli_Flag
dspErrorStatus kaiserWin(uint16_t N, double beta, double w[]);
#endif#if prod_Flag
dspErrorStatus taylorWin(uint16_t N, uint16_t nbar, double sll, double w[]);
#endif#if linSpace_Flag
dspErrorStatus tukeyWin(uint16_t N, double r, double w[]);
#endif#endif
/*
*file       WindowFunction.c
*author     Vincent Cui
*e-mail     whcui1987@163.com
*version    0.3
*data       31-Oct-2014
*brief      各种窗函数的C语言实现
*/#include "winfun.h"
#include <math.h>
#include <stdlib.h>#if prod_Flag
/*函数名:taylorWin
*说明:计算泰勒窗。泰勒加权函数
*输入:
*输出:
*返回:
*调用:prod()连乘函数
*其它:用过以后,需要手动释放掉*w的内存空间
*        调用示例:ret = taylorWin(99, 4, 40, &w); 注意此处的40是正数 表示-40dB
*/
dspErrorStatus taylorWin(dspUint_16 N, dspUint_16 nbar, dspDouble sll, dspDouble **w)
{dspDouble A;dspDouble *retDspDouble;dspDouble *sf;dspDouble *result;dspDouble alpha, beta, theta;dspUint_16 i, j;/*A = R   cosh(PI, A) = R*/A = (dspDouble)acosh(pow((dspDouble)10.0, (dspDouble)sll / 20.0)) / PI;A = A * A;/*开出存放系数的空间*/retDspDouble = (dspDouble *)malloc(sizeof(dspDouble) * (nbar - 1));if (retDspDouble == NULL)return DSP_ERROR;sf = retDspDouble;/*开出存放系数的空间*/retDspDouble = (dspDouble *)malloc(sizeof(dspDouble) * N);if (retDspDouble == NULL)return DSP_ERROR;result = retDspDouble;alpha = prod(1, 1, (nbar - 1));alpha *= alpha;beta = (dspDouble)nbar / sqrt(A + pow((nbar - 0.5), 2));for (i = 1; i <= (nbar - 1); i++){*(sf + i - 1) = prod(1, 1, (nbar - 1 + i)) * prod(1, 1, (nbar - 1 - i));theta = 1;for (j = 1; j <= (nbar - 1); j++){theta *= 1 - (dspDouble)(i * i) / (beta * beta * (A + (j - 0.5) * (j - 0.5)));}*(sf + i - 1) = alpha * (dspDouble)theta / (*(sf + i - 1));}/*奇数阶*/if ((N % 2) == 1){for (i = 0; i < N; i++){alpha = 0;for (j = 1; j <= (nbar - 1); j++){alpha += (*(sf + j - 1)) * cos(2 * PI * j * (dspDouble)(i - ((N - 1) / 2)) / N);}*(result + i) = 1 + 2 * alpha;}}/*偶数阶*/else{for (i = 0; i < N; i++){alpha = 0;for (j = 1; j <= (nbar - 1); j++){alpha += (*(sf + j - 1)) * cos(PI * j * (dspDouble)(2 * (i - (N / 2)) + 1) / N);}*(result + i) = 1 + 2 * alpha;}}*w = result;free(sf);return DSP_SUCESS;
}
#endif/*
*函数名:triangularWin
*说明:计算三角窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = triangularWin(99, w);
*/
dspErrorStatus triangularWin(uint16_t N, double w[])
{uint16_t i;/*阶数为奇*/if ((N % 2) == 1){for (i = 0; i < ((N - 1) / 2); i++){w[i] = 2 * (double)(i + 1) / (N + 1);}for (i = ((N - 1) / 2); i < N; i++){w[i] = 2 * (double)(N - i) / (N + 1);}}/*阶数为偶*/else{for (i = 0; i < (N / 2); i++){w[i] = (i + i + 1) * (double)1 / N;}for (i = (N / 2); i < N; i++){w[i] = w[N - 1 - i];}}return DSP_SUCESS;
}#if linSpace_Flag
/*
*函数名:tukeyWin
*说明:计算tukey窗函数
*输入:
*输出:
*返回:linSpace()
*调用:
*其它:用过以后,需要手动释放掉*w的内存空间
*        调用示例:ret = tukeyWin(99, 0.5, &w);
*/
dspErrorStatus tukeyWin(dspUint_16 N, dspDouble r, dspDouble **w)
{dspErrorStatus retErrorStatus;dspUint_16        index;dspDouble        *x, *result, *retPtr;dspDouble        alpha;retErrorStatus = linSpace(0, 1, N, &x);if (retErrorStatus == DSP_ERROR)return DSP_ERROR;result = (dspDouble *)malloc(N * sizeof(dspDouble));if (result == NULL)return DSP_ERROR;/*r <= 0 就是矩形窗*/if (r <= 0){retErrorStatus = rectangularWin(N, &retPtr);if (retErrorStatus == DSP_ERROR)return DSP_ERROR;/*将数据拷出来以后,释放调用的窗函数的空间*/memcpy(result, retPtr, (N * sizeof(dspDouble)));free(retPtr);}/*r >= 1 就是汉宁窗*/else if (r >= 1){retErrorStatus = hannWin(N, &retPtr);if (retErrorStatus == DSP_ERROR)return DSP_ERROR;/*将数据拷出来以后,释放调用的窗函数的空间*/memcpy(result, retPtr, (N * sizeof(dspDouble)));free(retPtr);}else{for (index = 0; index < N; index++){alpha = *(x + index);if (alpha < (r / 2)){*(result + index) = (dspDouble)(1 + cos(2 * PI * (dspDouble)(alpha - (dspDouble)r / 2) / r)) / 2;}else if ((alpha >= (r / 2)) && (alpha <(1 - r / 2))){*(result + index) = 1;}else{*(result + index) = (dspDouble)(1 + cos(2 * PI * (dspDouble)(alpha - 1 + (dspDouble)r / 2) / r)) / 2;}}}free(x);*w = result;return DSP_SUCESS;
}
#endif/*
*函数名:bartlettWin
*说明:计算bartlettWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = bartlettWin(99, w);
*/
dspErrorStatus bartlettWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < (N - 1) / 2; n++){w[n] = 2 * (double)n / (N - 1);}for (n = (N - 1) / 2; n < N; n++){w[n] = 2 - 2 * (double)n / ((N - 1));}return DSP_SUCESS;
}/*
*函数名:bartLettHannWin
*说明:计算bartLettHannWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = bartLettHannWin(99, w);
*/
dspErrorStatus bartLettHannWin(uint16_t N, double w[])
{uint16_t n;/*奇*/if ((N % 2) == 1){for (n = 0; n < N; n++){w[n] = 0.62 - 0.48 * fabs(((double)n / (N - 1)) - 0.5) + 0.38 * cos(2 * PI * (((double)n / (N - 1)) - 0.5));}for (n = 0; n < (N - 1) / 2; n++){w[n] = w[N - 1 - n];}}/*偶*/else{for (n = 0; n < N; n++){w[n] = 0.62 - 0.48 * fabs(((double)n / (N - 1)) - 0.5) + 0.38 * cos(2 * PI * (((double)n / (N - 1)) - 0.5));}for (n = 0; n < N / 2; n++){w[n] = w[N - 1 - n];}}return DSP_SUCESS;
}/*
*函数名:blackManWin
*说明:计算blackManWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = blackManWin(99, w);
*/
dspErrorStatus blackManWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < N; n++){w[n] = 0.42 - 0.5 * cos(2 * PI * (double)n / (N - 1)) + 0.08 * cos(4 * PI * (double)n / (N - 1));}return DSP_SUCESS;
}/*
*函数名:blackManHarrisWin
*说明:计算blackManHarrisWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = blackManHarrisWin(99, w);
*  minimum 4-term Blackman-harris window -- From Matlab
*/
dspErrorStatus blackManHarrisWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < N; n++){w[n] = BLACKMANHARRIS_A0 - BLACKMANHARRIS_A1 * cos(2 * PI * (double)n / (N)) + \BLACKMANHARRIS_A2 * cos(4 * PI * (double)n / (N)) - \BLACKMANHARRIS_A3 * cos(6 * PI * (double)n / (N));}return DSP_SUCESS;
}/*
*函数名:bohmanWin
*说明:计算bohmanWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = bohmanWin(99, w);
*/
dspErrorStatus bohmanWin(uint16_t N, double w[])
{uint16_t n;double x;for (n = 0; n < N; n++){x = -1 + n *  (double)2 / (N - 1);/*取绝对值*/x = x >= 0 ? x : (x * (-1));w[n] = (1 - x) * cos(PI * x) + (double)(1 / PI) * sin(PI * x);}return DSP_SUCESS;
}/*
*函数名:chebyshevWin
*说明:计算chebyshevWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = chebyshevWin(99,100, w);
*/
dspErrorStatus chebyshevWin(uint16_t N, double r, double w[])
{uint16_t n, index;double x, alpha, beta, theta, gama;/*10^(r/20)*/theta = pow((double)10, (double)(fabs(r) / 20));beta = pow(cosh(acosh(theta) / (N - 1)), 2);alpha = 1 - (double)1 / beta;if ((N % 2) == 1){/*计算一半的区间*/for (n = 1; n < (N + 1) / 2; n++){gama = 1;for (index = 1; index < n; index++){x = index * (double)(N - 1 - 2 * n + index) / ((n - index) * (n + 1 - index));gama = gama * alpha * x + 1;}w[n] = (N - 1) * alpha * gama;}theta = w[(N - 1) / 2];w[0] = 1;for (n = 0; n < (N + 1) / 2; n++){w[n] = (double)(w[n]) / theta;}/*填充另一半*/for (; n < N; n++){w[n] = w[N - n - 1];}}else{/*计算一半的区间*/for (n = 1; n < (N + 1) / 2; n++){gama = 1;for (index = 1; index < n; index++){x = index * (double)(N - 1 - 2 * n + index) / ((n - index) * (n + 1 - index));gama = gama * alpha * x + 1;}w[n] = (N - 1) * alpha * gama;}theta = w[(N / 2) - 1];w[0] = 1;for (n = 0; n < (N + 1) / 2; n++){w[n] = (double)(w[n]) / theta;}/*填充另一半*/for (; n < N; n++){w[n] = w[N - n - 1];}}return DSP_SUCESS;
}/*
*函数名:flatTopWin
*说明:计算flatTopWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = flatTopWin(99, w);
*/
dspErrorStatus flatTopWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < N; n++){w[n] = FLATTOPWIN_A0 - FLATTOPWIN_A1 * cos(2 * PI * (double)n / (N - 1)) + \FLATTOPWIN_A2 * cos(4 * PI * (double)n / (N - 1)) - \FLATTOPWIN_A3 * cos(6 * PI * (double)n / (N - 1)) + \FLATTOPWIN_A4 * cos(8 * PI * (double)n / (N - 1));}return DSP_SUCESS;
}/*
*函数名:gaussianWin
*说明:计算gaussianWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = gaussianWin(99,2.5, w);
*/
dspErrorStatus gaussianWin(uint16_t N, double alpha, double w[])
{uint16_t n;double k, beta, theta;for (n = 0; n < N; n++){if ((N % 2) == 1){k = n - (N - 1) / 2;beta = 2 * alpha * (double)k / (N - 1);}else{k = n - (N) / 2;beta = 2 * alpha * (double)k / (N - 1);}theta = pow(beta, 2);w[n] = exp((-1) * (double)theta / 2);}return DSP_SUCESS;
}/*
*函数名:hammingWin
*说明:计算hammingWin窗函数,汉明窗
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = hammingWin(99, w);
*/
dspErrorStatus hammingWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < N; n++){w[n] = 0.54 - 0.46 * cos(2 * PI *  (double)n / (N - 1));}return DSP_SUCESS;
}/*
*函数名:hannWin
*说明:计算hannWin窗函数,汉宁窗
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = hannWin(99, w);
*/
dspErrorStatus hannWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < N; n++){w[n] = 0.5 * (1 - cos(2 * PI * (double)n / (N - 1)));}return DSP_SUCESS;
}#if besseli_Flag
/*
*函数名:kaiserWin
*说明:计算kaiserWin窗函数
*输入:
*输出:
*返回:
*调用:besseli()第一类修正贝塞尔函数
*其它:用过以后,需要手动释放掉*w的内存空间
*        调用示例:ret = kaiserWin(99, 5, &w);
*/
dspErrorStatus kaiserWin(dspUint_16 N, dspDouble beta, dspDouble **w)
{dspUint_16 n;dspDouble *ret;dspDouble theta;ret = (dspDouble *)malloc(N * sizeof(dspDouble));if (ret == NULL)return DSP_ERROR;for (n = 0; n < N; n++){theta = beta * sqrt(1 - pow(((2 * (dspDouble)n / (N - 1)) - 1), 2));*(ret + n) = (dspDouble)besseli(0, theta, BESSELI_K_LENGTH) / besseli(0, beta, BESSELI_K_LENGTH);}*w = ret;return DSP_SUCESS;
}
#endif/*
*函数名:nuttalWin
*说明:计算nuttalWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = nuttalWin(99, w);
*/
dspErrorStatus nuttalWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < N; n++){w[n] = NUTTALL_A0 - NUTTALL_A1 * cos(2 * PI * (double)n / (N - 1)) + \NUTTALL_A2 * cos(4 * PI * (double)n / (N - 1)) - \NUTTALL_A3 * cos(6 * PI * (double)n / (N - 1));}return DSP_SUCESS;
}/*
*函数名:parzenWin
*说明:计算parzenWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = parzenWin(99, w);
*/
dspErrorStatus parzenWin(uint16_t N, double w[])
{uint16_t n;double alpha, k;if ((N % 2) == 1){for (n = 0; n < N; n++){k = n - (N - 1) / 2;alpha = 2 * (double)fabs(k) / N;if (fabs(k) <= (N - 1) / 4){w[n] = 1 - 6 * pow(alpha, 2) + 6 * pow(alpha, 3);}else{w[n] = 2 * pow((1 - alpha), 3);}}}else{for (n = 0; n < N; n++){k = n - (N - 1) / 2;alpha = 2 * (double)fabs(k) / N;if (fabs(k) <= (double)(N - 1) / 4){w[n] = 1 - 6 * pow(alpha, 2) + 6 * pow(alpha, 3);}else{w[n] = 2 * pow((1 - alpha), 3);}}}return DSP_SUCESS;
}/*
*函数名:rectangularWin
*说明:计算rectangularWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = rectangularWin(99, w);
*/
dspErrorStatus rectangularWin(uint16_t N, double w[])
{uint16_t n;for (n = 0; n < N; n++){w[n] = 1;}return DSP_SUCESS;
}

卡尔曼滤波

#include "kalman.h"/***卡尔曼滤波器*@param  Kalman *kfp 卡尔曼结构体参数*               float input 需要滤波的参数的测量值(即传感器的采集值)*@return 滤波后的参数(最优值)*/
float KalmanFilter(float inData)
{static float prevData = 0;                                 //上一个数据static float p = 10, q = 0.001, r = 0.001, kGain = 0;      // q 控制误差 r 控制响应速度p = p + q;kGain = p / ( p + r );                                      //计算卡尔曼增益inData = prevData + ( kGain * ( inData - prevData ) );      //计算本次滤波估计值p = ( 1 - kGain ) * p;                                      //更新测量方差prevData = inData;return inData;                                             //返回估计值}/* 优化后的卡尔曼滤波 更改Q值,响应加快,但太大会有震荡更改R值,响应减慢,越大稳定性会提高,但时间会增加
*/unsigned long kalman_filter( unsigned long ADC_Value )
{float LastData;float NowData;float kalman_adc;static float kalman_adc_old = 0;static float PP;static float Q = 0.5;static float R = 10;static float Kg = 0;static float P = 1;NowData = ADC_Value;LastData = kalman_adc_old;P = PP + Q;Kg = P / ( P + R );kalman_adc = LastData + Kg * ( NowData - kalman_adc_old );PP = ( 1 - Kg ) * P;P = PP;kalman_adc_old = kalman_adc;return ( unsigned long )( kalman_adc );}/* 优化后的卡尔曼滤波 更改Q值,响应加快,但太大会有震荡更改R值,响应减慢,越大稳定性会提高,但时间会增加
*/float kalman_filter_FPU( float Val )
{float LastData;float NowData;float kalman_adc;static float kalman_adc_old = 1.0;static float PP;static float Q = 0.5;static float R = 10;static float Kg = 0;static float P = 1;NowData = Val;LastData = kalman_adc_old;P = PP + Q;Kg = P / ( P + R );kalman_adc = LastData + Kg * ( NowData - kalman_adc_old );PP = ( 1 - Kg ) * P;P = PP;kalman_adc_old = kalman_adc;return ( kalman_adc );}

主要程序

FFT的计算
void FFT_Caculate(uint16_t *adc_buf, uint16_t FFT)
{for(int i = 0; i < FFT; i++){fft_inputbuf[2*i]=adc_buf[i] * 3.3 / 4096;  //实部fft_inputbuf[2*i+1]=0;//虚部全部为0}arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT);    //把运算结果复数求模得幅值 fft_outputbuf[0] /= FFT;for(int i = 1; i < FFT/2 ;i++) {fft_outputbuf[i] /= (FFT/2);}for(int i=0;i<FFT/2;i++){printf("%f\n",fft_outputbuf[i]);}
}void FFT_Caculate_NonePrint(uint16_t *adc_buf, uint16_t FFT)
{for(int i = 0; i < FFT; i++){fft_inputbuf[2*i]=adc_buf[i] * 3.3 / 4096;  //实部fft_inputbuf[2*i+1]=0;//虚部全部为0}arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT);    //把运算结果复数求模得幅值 fft_outputbuf[0] /= FFT;for(int i = 1; i < FFT/2 ;i++) {fft_outputbuf[i] /= (FFT/2);}
}unsigned long FFT_Caculate_Float(float *adc_8885_buf, uint16_t FFT)
{unsigned long dds_fre;float c_fre=0,m_fre;int temp_i;for(int i=0;i<FFT;i++){fft_inputbuf[2*i]=adc_8885_buf[i];  //实部fft_inputbuf[2*i+1]=0;//虚部全部为0}arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH);    //把运算结果复数求模得幅值for(int i=0;i<FFT_LENGTH/2;i++){if(fft_outputbuf[i]>c_fre){c_fre=fft_outputbuf[i];temp_i = i;}}m_fre = (float)ADS8885_CLK/1024.0 * temp_i;         //基带频率dds_fre = (unsigned long)((m_fre/1000)+1)*1000; //把频率给DDSreturn dds_fre;
}
ADS8885计算频率和幅度
void ADS8885_Calculat_Fre(double *fre)
{int temp_ii=0;float cmp_fre=0;getRData(adc8885_val,FFT_LENGTH);for(int i = 0; i < FFT_LENGTH; i++){fft_inputbuf[2*i]=adc8885_val[i];fft_inputbuf[2*i+1]=0;//虚部全部为0}arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH);    //把运算结果复数求模得幅值for(int i=10;i<FFT_LENGTH/2;i++){if(fft_outputbuf[i]>cmp_fre){cmp_fre=fft_outputbuf[i];temp_ii = i;}}*fre = (float)ADS8885_CLK/1024.0 * temp_ii;*fre = (float)((int)(*fre/1000)+1)*1000;
}void ADS8885_Calculat_Amg(float *adc8885_avgs)
{float adc8885_minval = 5.0;float adc8885_maxval = -5.0;for(int k=0;k<10;k++){getRData(adc8885_val,FFT_LENGTH);for(int i=0;i<FFT_LENGTH/2;i++) {if(adc8885_val[i] > adc8885_maxval)adc8885_maxval=adc8885_val[i];if(adc8885_val[i] < adc8885_minval)adc8885_minval=adc8885_val[i];}*adc8885_avgs += (adc8885_maxval-(adc8885_minval));}*adc8885_avgs /= 10.0;
}

结语

main函数过于长且没整理,暂时不贴出
本次还是很可惜,没有将代码写全,若将第三部分的频率拓展到第一、二部分,那才是真真正正的将整个解决完毕,FM解调部分若是想10M-30M均能解调,使用模块的话是肯定不行的,除非至少三块或三块以上的解调模块来互补解调,所以这里的FM解调方法可能采用频谱分析仪的做工思想,用窄带滤波法,分几百Hz的带宽来在频带上一路扫过去,若只有一根则是无调制,三根则是AM调制,若干根则是FM调制。

关于2022年TI省赛--F题信号调制度测量装置相关推荐

  1. 2022年电赛F题 信号调制度测量装置

    红叶何时落水 题目要求: 一.任务 设计制作信号调制度测量装置,该装置测量并显示信号源输出的被测信号调制度等参数,识别并显示被测信号的调制方式,输出解调信号.测量系统如图1所示. 二.要求 (1)被测 ...

  2. 2021电赛A题:信号失真度测量装置

    元件清单 TIVA C Series:TM4C123G LaunchPad Nokia 5110 LCD LM358 电阻.电容和杜邦线若干 系统总方案设计 首先,先将信号发生器输出的信号通过直流偏置 ...

  3. 2022电赛F题思路

    2022电赛到现在为止已经出了结果.这是我第一次参加电赛,以前也没有相关的比赛经历,在这四天三夜的时间里能够和队友完成这样一项完整的作品,对我们来说都具有很大的意义.虽然最后还是有一些细节上的问题,不 ...

  4. 竞赛无人机搭积木式编程——以2022年TI电赛送货无人机一等奖复现为例学习(7月B题)

    在学习本教程前,请确保已经学习了前4讲中无人机相关坐标系知识.基础飞行控制函数.激光雷达SLAM定位条件下的室内定点控制.自动飞行支持函数.导航控制函数等入门阶段的先导教程. 同时用户在做二次开发自定 ...

  5. 2023美赛F题全部代码+数据+结果 数学建模

    2023年美赛F题全部思路 数据代码都已完成 全部内容见链接:https://www.jdmm.cc/file/2708700/ 1.根据文献选的GGDP的指标,发现GGDP与水资源等有关,由此可以筛 ...

  6. 2022美国大学生数学建模竞赛F题思路

    一.思路 思路下载链接:2022美国大学生数学建模竞赛F题思路 二.题目 三.2021最全数学建模比赛时间.含金量.获奖率等数据一览! 2021最全数学建模比赛时间.含金量.获奖率等数据一览!

  7. 2020电赛F题回顾——简易无接触温度测量与身份识别装置

    2020电赛F题回顾--简易无接触温度测量与身份识别装置 第一次参加电赛,已经大三了,这也有可能是我的最后一次,不禁感慨时间过得真快.在实验室一起奋斗的夜晚既辛苦又幸福,感谢陪伴在我身边一起做电赛的同 ...

  8. 2021年美赛F题总结

    2021年美赛F题总结 肝到了早上六点20分才算是把F题的论文交上去了呜呜,最后把论文发给官方的时候3个人紧张死了,检查了7,8遍就怕出一点错,官方不接收我们的文章,那个点已经神志不清了,又在官网不停 ...

  9. 2021电赛F题视觉教程+代码免费开源

    2021电赛F题视觉教程+代码免费开源 最近好多要电赛题的源码,其他csdn营销号下载都需要会员或钱,正好最近课设又要做一遍电赛小车题,哥们先把代码开源了,饿死营销号 电赛宝藏链接: 四天三夜,那布满 ...

最新文章

  1. 今日 Paper | 多人姿势估计;对话框语义分析;无监督语义分析;自然语言处理工具包等
  2. 前深度学习时代CTR预估模型的演化之路 [王喆观点]
  3. 码牛安卓移动互联网高级开发正式课
  4. hdu 5521 Meeting(最短路)
  5. 守卫者的挑战(guard)
  6. 回溯算法详解之全排列、N皇后问题
  7. 2034.股票价格波动-LeetCode
  8. oracle创建触发器
  9. 强烈推荐这款能探测别人工资的黑科技!秀的我头皮发麻
  10. chromecast 协议_如何解决常见的Google Chromecast问题
  11. 牛客寒假集训营 牛牛战队的比赛地
  12. 测试人员只能点点点?深度剖析测试人员如何变得更优秀
  13. 正襟危坐说--操作系统(伍):进程间通信
  14. c语言编程求pai的近似值,c语言:求π的近似值
  15. cadence常用快捷键及小技巧(画斜线、开balloons等)
  16. 【转载】无公网IP搞定群晖+ZEROTIER ONE实现内网穿透
  17. 地理坐标系、大地坐标系、地图投影与重投影
  18. 谷歌首度证实重返中国的Dragonfly计划存在丨Q新闻
  19. ES6字符串、对象、数组不常见但实用的API方法
  20. 计算机成绩统计优秀率,在excel中如何计算及格率和优秀率及统计各分数段人数.doc...

热门文章

  1. java毕业生设计自动化办公系统计算机源码+系统+mysql+调试部署+lw
  2. 基于B/S架构的合同信息管理系统(Java+Web+MySQL)
  3. JVM优化--垃圾回收
  4. 文件流中读行的正确使用(fgets、feof、ferror)
  5. Scala语言学习开发工具(一)
  6. 双电梯电梯调度算法的简单分析
  7. 计算机专业暨南还是深大,自考深大还是暨南大学好,深圳自考报名选深圳大学还是暨南大学?...
  8. ViewModel浅析
  9. 2018杭电ACM集训队单人排位赛 - 1Problem A. 内蒙创业
  10. 数字孪生技术,才是智慧城市的起点!