作者:SHR-sky 

全国大学生电子设计大赛系列

第一站 :【电赛2023H】信号分离装置


文章目录

前言

正文

一、题目分析

二、解题步骤

三、具体操作

四、核心代码

总结


前言

        这是本人第一篇CSDN博客,旨在分享电赛思路,方便后来的学者,也是记录自己的一段岁月。虽然CSND风评存在问题,但是需要肯定的是,这确实是新手小白最需要的、最方便的平台,曾经我的学习之路上也多有CSDN的帮助,现在也希望同样对新手们能起到一点帮助。

        之所以第一篇选择2023H题,是因为我觉得这最能体现STM32F407数字信号处理特性,并且最适合入门的一道题目。


正文

一、题目分析

1.读题

提炼一下:将一定频率的信号混合,然后分离出来,并且这些信号的频率是离散、可列举的

题目要求如下

        本文工程已上传GitHub,链接如下,欢迎star:SHR-sky/2023-H: 2023年电赛H题工程,完成所有问题。主控采用STM32,软件上采用DFT与FFT算法,通过控制定时器实现精准延时,从而实现相位校准,抑制漂移 (github.com)

2. 思路

所以,我们目标有五个:

  • 合成信号
  • 分离不同频率正弦波信号
  • 判断信号类型(waveform)
  • 分离不同类型、不同频率的信号
  • 控制分离后信号的相位差

        读完题目,显然,采用纯模拟的方法非常不可行。在不同类型信号(三角和正弦)的分离中,模拟滤波器显然非常难以设计。过多的滤波器同样也会造成比赛过程中焊接、调试的困难。

        所以,面对这些问题,自然而然地,我们会想到从频域上进行分析,我们就会采用数字系统。在频谱中,我们可以简单地得到,各个信号分量的频率,得到信号的类型。当我们分析得到混合信号的频谱信息后,我们当然可以通过这些信息,采用不同的参数、类型数字滤波器对信号进行分离。但是,数字滤波器的设计显然会非常麻烦,需要非常高阶的滤波器。

        我们不妨转换一下思路。既然我们采用数字方案,我们为什么不直接采用DDS(直接数字频率合成)技术,根据频谱信息,重建出信号?甚至于,由于题目只有有限几种频率的信号,我们为什么不直接采用打表加上DAC的方法,直接产生重建波形?

        当意识到这点后,我们唯一需要解决的问题就是“相位飘移”问题。如果重建信号不同源,那么由于晶振间微小的频率差异,会导致波形并非成倍数关系,会在示波器上“跑起来”。原因其实就是,频率非整数倍数,波形之间的相位差随时间在变化,表现为波形之间的相互运动,以其中一个信号为触发信源,另一个就会“飘移”。

        为了解决这点,首先,可以采取FPGA驱动DAC,由于保证了相同的时钟,所以最终不会存在细微的频率差;同样,我们也可以采用多通道的DDS模块(此处非常不建议采用飞线让两块DDS共用一个晶振),使得输出信号同源,这里推荐AD9959模块,使用方法详见本人博客;然而,第二种方法无法产生三角波,根据芯片手册,STM32F07的DAC速率,在本题频率较低的条件下,是足够的。本博客采用方案三。

        但是,方案三,实际上仍然存在波形偏移(本人尝试过FPGA方案,同样也存在这种情况,只有DDS可以完全避免),所以需要相位校正。

一点杂谈:其实在知乎上看到一种说法“电赛越来越成为一种烧钱比赛,买好的模块就可以解决问题,比赛者开始轻视‘奇技淫巧’的技术”。我觉得本题的这种解法就是一种很好的回应,只用到单片机内部的ADC和DAC,即可完成所有要求。

二、解题步骤

首先给出系统框图

1.数字正交分解——得到频率信息

        首先,利用matlab制作一张正/余弦值表,用于运算和DA重建。由于数值过多,此处不放具体代码。每行都是两百个点,表达一种特定频率的波形。(后续三角波的重建也需要制表)

        由于CSDN自带的Latex公式不大好看,所以此处推导过程用截图替代。

 

2.FFT——得到波形信息

此处一定注意,修改堆栈大小,不然FFT会爆栈,导致出现奇怪的结果

首先,要安装DSP库,这样才能使用,DSP库的安装我是按照这篇教程来的:

事隔五年之后,开启第2版DSP数字信号处理和CMSIS-NN神经网络教程,同步开启三代示波器,更至50章(2021-11-01) - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz! (armbbs.cn)

判断的理论依据是:三角波在奇次谐波上存在谐波分量。先对3次谐波的能量进行计算——并将其与基频功率进行比较,当达到一定比例时就认为这些频点上存在谐波失真,也就是输入是三角波。但是当被测信号C中混合的A、B两个单频信号中的一个的频率刚好是另一个信号频率的3倍时(例如A为10KHz,B为30KHz时),低频信号的3次谐波会和较高频率信号的能量混淆在一起,从而使算法是无法判断低频信号是三角波还是正弦波的。所以进一步对低频信号的五次谐波进行判断,方法与其他频点上对三次谐波的判断相同。

3.TIM.cnt——实现相位延迟校正

一种非常有效的,精准延时的方法,思路来自:2023全国大学生电子设计竞赛H题全解 [原创www.cnblogs.com/helesheng] - helesheng - 博客园

为什么要这样做呢?

4. 加法器——信号混和

        作为本解法唯一的硬件,这里做一点提示。

        很基础的模电知识,这里不做讲解。

三、核心代码

        在main函数中描述了控制逻辑。

        在实际实验中,发现利用串口屏改变模式之后,需要软重启一下。然后采用goto回到程序的入口。

extern u8 do_ad_flag1;
extern u8 do_ad_flag2;
		
int main()
{
again:
	int cnt0 = 0;
	int cnt1 = 0;
	wave_type[0] = 0;
	wave_type[1] = 0;
	Serial_Init();
	ADC_GPIO_Init();						    // ADC引脚初始化。
	TIM3_Config();                     // 触发ADC采样频率,采样频率2MHz
	ADC_Config();                               // ADC 2000K采样频率,采集6000个数据,需要花费3ms
	ADC_DMA_Trig( ADC1_DMA_Size ); 	// 开始AD采集,设置采样点数
	for(int i=0; i<10000; i++);
	cal_2frqs(fre);
	fft_cal_2types(fre,wave_type);
	
	diff_phi_per5_1 = 1166.666666/(fre[1]*5+10);
	diff_phi_per5_0 = 1166.666666/(fre[0]*5+10);

	for(int i=0; i<200; i++)
	{
		meDA1_Value[i] = DAC_SIN[i];
	}
	TIM4_Init();
	DA1_Init();
	//TIM4->CNT = 65535-(4438)-TIM4->CNT;
	TIM6_Init();
	DA2_Init();
	TIM_Cmd(TIM4, ENABLE);  
	TIM_Cmd(TIM6, ENABLE);  
	while(1);
	
	if(wave_type[0]==0)
	{
		for(int i=0; i<200; i++)
		{
			meDA1_Value[i] = DAC_SIN[(fre[0])*200+i];
		}
	}
	else
	{
		for(int i=0; i<200; i++)
		{
			meDA1_Value[i] = Tri_Wave[(fre[0])*200+i];
		}
	}
	if(wave_type[1]==0)
	{
		for(int i=0; i<200; i++)
		{
			meDA2_Value[i] = DAC_SIN[(fre[1])*200+i];
		}
	}
	else
	{
		for(int i=0; i<200; i++)
		{
			meDA2_Value[i] = Tri_Wave[(fre[1])*200+i];
		}
	}
	
	TIM4_Init();
	DA1_Init();
	TIM6_Init();
	DA2_Init();
	TIM_Cmd(TIM4, ENABLE);  
	TIM_Cmd(TIM6, ENABLE);  
	
	while (1)	
    {	
		if(mode_flag==0)
		{
			do_ad_flag2 = 0;
			while(do_ad_flag2==0);
			ADC_DMA_Trig( ADC1_DMA_Size );
			get_pos_angle();
			delayTime1 = (8400.0*pos_angle_1 / (3.1415926*((double)fre[1]+ 2.0))+0.5);
			TIM6->CNT = 65535 - (delayTime1-TIM6->CNT);
			
			do_ad_flag1 = 0;
			while(do_ad_flag1==0);
			ADC_DMA_Trig( ADC1_DMA_Size );
			get_pos_angle();
			delayTime0 = (8400.0*pos_angle_0 / (3.1415926*((double)fre[0]+ 2.0))+0.5);
			TIM4->CNT = 65535 - (delayTime0-TIM4->CNT);
		} 
		else 
		{
			int t= (double)change_phi/360.0 * (1000.0/(fre[1]*2.0+10.0))*29.71;
			if(change_phi!=0)
			{
				TIM4->CNT = 65535-(t)-TIM4->CNT;
			
				change_phi = 0;
			}
			
		}
		if(flag == 1)
		{
			NVIC_SystemReset();
			for(int i=0; i<=10000; i++);
			NVIC_SystemReset();
			wave_type[0] = 0;
			wave_type[1] = 0;
			flag = 0;
			change_phi = 0;
			goto again; 
		}
    }
}

四、注意事项

  • FFT需要修改堆栈大小
  • DSP库需要移植,并且选择 Single Precison
  • 定时器使用前查询手册,确定是32位还是64位


总结

一个非常经典的信号处理,对基础的算法进行考察的题目。在题目中,硬件上只需要加法器(其实片内ADC采样之后,做加法,再用DAC输出也行,不过这样就有点“炫技”之意,没有必要为了“纯软件”而多花时间和浪费单片机资源),其余均为软件完成,体现了“最少资源”的特点。

完整工程可见本人仓库:GitHub - SHR-sky/2023-H: 2023年电赛H题工程,完成所有问题。主控采用STM32,软件上采用DFT与FFT算法,通过控制定时器实现精准延时,从而实现相位校准,抑制漂移

Logo

一起探索未来云端世界的核心,云原生技术专区带您领略创新、高效和可扩展的云计算解决方案,引领您在数字化时代的成功之路。

更多推荐