jjzjj

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

红叶落水 2023-04-11 原文

红叶何时落水

 题目要求:

一、任务

设计制作信号调制度测量装置,该装置测量并显示信号源输出的被测信号调制度等参数,识别并显示被测信号的调制方式,输出解调信号。测量系统如图1所示。

二、要求

(1)被测信号为电压峰峰值100mV的普通单音调幅(AM)电压,其载频为10MHz、调制信号为频率1~3kHz的正弦信号。测量并显示的调幅度,要求测量误差绝对值≤0.1;输出解调信号,要求解调信号波形无明显失真。 (20分)

(2)被测信号为电压峰峰值100mV的单音调频(FM)电压,其载频为10MHz、调制信号为频率3~5kHz的正弦信号。测量并显示的调频度,测量误差绝对值≤0.3;测量并显示的最大频偏(kHz);输出解调信号,要求解调信号波形无明显失真。(25分)

(3)被测信号为载波电压峰峰值100mV的高频电压,其载频范围为10MHz~30MHz(频率步进间隔0.5MHz)。若为已调波(AM或FM波)时,其调制信号为频率范围5kHz~10kHz(频率步进间隔1kHz)内某一频率的正弦信号。测量装置应能自主识别的调制方式,即能判断出为调幅、调频或未调载波。测量并显示的调制度(或),测量误差要求分别同前面第 (1) 、(2)项的要求;当被测信号为调频波时,要求测量并显示其最大频偏(kHz);输出解调信号,要求解调信号波形无明显失真。(45分)

任务分析

最主要的任务是AM信号与FM信号要实现解调,并且测量出相关参数;

简单来说有两套方案

第一套硬件解调,并将所需测量的参数转化为电压量。由单片机测量参数,进行计算和显示;

AM解调

首先,将信号放大,上拉到2V左右。然后用包络检波电路将其解调出来,再加一个底通滤波器即可。

具体电路见:效果图

                       原理图与连线图

FM解调我没做,好像是用鉴相器制作。

难点:载波频率为10MHZ,普通的芯片频带无法实现。

比如说AM的解调,如果我们打算用820单运放将其放大并上拉,我们就会发现当载波为10Mhz时,输出的信号实现了放大功能。但一旦将载波信号变为20MHZ,增益便会发生变化(频带不够宽)。当然,增益发生变化对于信号的解调影响不大,还是可以解出来的。但是,AM的调幅度是用解调出来的正弦波的峰峰值/直流偏置得来的。因为增益发生变化,会导致参数发生变化。所以后面单片机的测量便有很大的麻烦。(一会在软件部分说明)

解决方案,使用无源电路将其衰减(防止调制波在放大模块那里出现失真),进入专用放大模块,之后,不进行上拉,直接让二极管将上半个调试波形解调出来。这样就避免了820的带宽问题。但是,这个方案需要一直去调阻抗,一不小心,信号直接衰没了。

第二套软件解调并测量

AM 对于周期信号来说,我们可以通过快速FFT运算,从频谱图中分析他的各种谐波。

难点

1.根据奈奎斯特采样定理,我们知道想要分析出频谱不混叠的频谱图,采样率必须大于最大谐波的二倍。那么就意味着AD采样率要大于60Mhz。普通的32单片机明显达不到这个采样率。就拿F103芯片来说,板载AD采样率在正常工作范围内为1Mhz。如果使AD超频工作的化,也只能达到2.5Mhz,与此同时,把主时钟超频到112M,采样率勉强达到4.5M。但此时采集到的波精度已经有了不小的损失。如果外接AD的话,也不太行,经过测试最大采样率为25M。如果用FPGA的话,采样率倒是可以达到60M。

所以,想实现软件解调,就要用带通采样(传送门

这里我采用的是204khz的采样率,刚好可以包含题目中所有的频率。

AM频谱图有三个谐波,最长的那根的频率便是载波频率。而两根短谐波之间的频率差便是调制波信号的频率。

对于FM 同样采样率,会出现多个周期的谐波

 我们可以通过分析该频谱来得出所有信息。

信息采集完毕后,用板载DA输出一个相应频率的正弦波即可。(如果觉得DA输出的波形不够好看,加个滤波电路滤一下即可)。

明天开始测评。

代码部分:

采样率204khzAD配置

TIM1_PWM定时器配置

void tim1_pwm_config(uint16_t psc,uint16_t arr,uint8_t val)
{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

    
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_Period = arr -1;
    TIM_TimeBaseInitStruct.TIM_Prescaler = psc -1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);

    

    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;

    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStruct.TIM_Pulse = arr / 2;
    TIM_OC1Init(TIM1,&TIM_OCInitStruct);
    TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);

    TIM_CtrlPWMOutputs(TIM1,ENABLE);
    TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_OC1);
    TIM_Cmd(TIM1,ENABLE);
}

DMA1配置

void Adc_dma(void)
{
    //ADC1      DMA1_CHANNEL1
    
    DMA_InitTypeDef DMA_InitStruct;


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

    DMA_InitStruct.DMA_BufferSize = size;
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)ADC_arr;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;

    DMA_Init(DMA1_Channel1,&DMA_InitStruct);

    DMA_Cmd(DMA1_Channel1,ENABLE);

}

ADC1配置

void adc_init(void)
{
    int i=0;
		ADC_InitTypeDef ADC_InitStruct;
		for(i=0; i<size; i++)
		{
		ADC_arr[i]=0;
		}
    adc_gpio_init();
    Adc_dma();
    adc_nvic_init();


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

    ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
    // ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
    ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStruct.ADC_NbrOfChannel = 1;
    ADC_InitStruct.ADC_ScanConvMode = DISABLE;

    ADC_Init(ADC1,&ADC_InitStruct);

//    ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_1Cycles5);

    ADC_DMACmd(ADC1,ENABLE);

    ADC_ExternalTrigConvCmd(ADC1, ENABLE);

    ADC_Cmd(ADC1,ENABLE);

    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1) == SET);

    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1) == SET);

   

}

FFT计算函数

typedef double real;

typedef struct{
  real Re; 
  real Im;
} complex;
double arr_res[_N] = {0};
void fft( complex *v, int n, complex *tmp )
{
  if(n>1) {   /* N???1,????*/
    int k,m;    complex z, w, *vo, *ve;
    ve = tmp; vo = tmp+n/2;
    for(k=0; k<n/2; k++) {
      ve[k] = v[2*k];
      vo[k] = v[2*k+1];
    }
    fft( ve, n/2, v );  /* FFT ???? v[] */
    fft( vo, n/2, v );  /* FFT ???? v[] */
    for(m=0; m<n/2; m++) {
      w.Re = cos(2*PI*m/(double)n);
      w.Im = -sin(2*PI*m/(double)n);
      z.Re = w.Re*vo[m].Re - w.Im*vo[m].Im; /* Re(w*vo[m]) */
      z.Im = w.Re*vo[m].Im + w.Im*vo[m].Re; /* Im(w*vo[m]) */
      v[  m  ].Re = ve[m].Re + z.Re;
      v[  m  ].Im = ve[m].Im + z.Im;
      v[m+n/2].Re = ve[m].Re - z.Re;
      v[m+n/2].Im = ve[m].Im - z.Im;
    }
  }
  return;
}

void ifft( complex *v, int n, complex *tmp )
{
  if(n>1) {   
    int k,m;    complex z, w, *vo, *ve;
    ve = tmp; vo = tmp+n/2;
    for(k=0; k<n/2; k++) {
      ve[k] = v[2*k];
      vo[k] = v[2*k+1];
    }
    ifft( ve, n/2, v );  /* FFT ???? v[] */
    ifft( vo, n/2, v );  /* FFT ???? v[] */
    for(m=0; m<n/2; m++) {
      w.Re = cos(2*PI*m/(double)n);
      w.Im = sin(2*PI*m/(double)n);
      z.Re = w.Re*vo[m].Re - w.Im*vo[m].Im; /* Re(w*vo[m]) */
      z.Im = w.Re*vo[m].Im + w.Im*vo[m].Re; /* Im(w*vo[m]) */
      v[  m  ].Re = ve[m].Re + z.Re;
      v[  m  ].Im = ve[m].Im + z.Im;
      v[m+n/2].Re = ve[m].Re - z.Re;
      v[m+n/2].Im = ve[m].Im - z.Im;
    }
  }
  return;
}

void fft_dispose(float arr[]) {
	complex v[_N], scratch[_N];
  double amp[_N];
  int k, i;
	printf("in");
	for(k=0; k<_N; k++) {
    v[k].Re = arr[k];
    v[k].Im = 0;
  }
	fft(v, _N, scratch );
	printf("\n\r\n\r\n\r");

	
  for(i = 1; i < _N/2; i++)
  {		
			arr_res[i] = sqrt(v[i].Re*v[i].Re+v[i].Im*v[i].Im);
			printf("%f,",arr_res[i]);
  }

	printf("\n\r\n\r\n\r");
}

DA配置

void Dac2_Init()
{
		GPIO_InitTypeDef GPIO_InitStructure;
    DAC_InitTypeDef DAC_InitType;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

    DAC_DeInit(); 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_SetBits(GPIOA, GPIO_Pin_5);

    DAC_StructInit(&DAC_InitType); 
    DAC_InitType.DAC_Trigger = DAC_Trigger_T4_TRGO; 
    DAC_InitType.DAC_WaveGeneration = DAC_WaveGeneration_None;
    DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0; 
    DAC_InitType.DAC_OutputBuffer = DAC_OutputBuffer_Disable; 
    DAC_Init(DAC_Channel_2, &DAC_InitType); 

    DAC_Cmd(DAC_Channel_2, ENABLE); 
    DAC_DMACmd(DAC_Channel_2, ENABLE);
}

DMA2配置


void MYDMA_Config(u32 cpar, u32 cmar, u16 cndtr) // cpar?????,cmar?????,cndtr????????(???????)
{
    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); 

    DMA_DeInit(DMA2_Channel4);

    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; 
    DMA_InitStructure.DMA_BufferSize = cndtr; 
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 
    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; 
    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;

    DMA_Init(DMA2_Channel4, &DMA_InitStructure);
    DMA_Cmd(DMA2_Channel4, ENABLE);
}

TIM4配置


void TIM4_Config(u16 arr,u16 psc)
{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); 

		
		TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
    TIM_TimeBaseStructure.TIM_Period = arr - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = psc;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
		TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
		
    TIM_SelectOutputTrigger(TIM4,TIM_TRGOSource_Update); 
		TIM_Cmd(TIM4, ENABLE);
}

main

 int main(void)
 { 
	u16 i;
	u16 n = NPT;
	int *p;
	int *f;
	double m;
	double v_x = 0,i_x;
	int h = 0;
	Init();
	
	while(1)
	{
		delay_s(1);
	 for(i = 0; i < Votage_BUFFER_Size; i++)
	 {
		XR[i]=ADC_arr[i];				 
	 }

	 	qsort(ADC_arr, Votage_BUFFER_Size, sizeof(ADC_arr[0]), compDec);
		LCD_ShowxNum(132,300, (u32)(ADC_arr[1900] - ADC_arr[120]) * 1000 / ADC_arr[120],5,16,0X80);
		printf("\n\r\n\r");
		fft();

	 for(i = 0; i < Votage_BUFFER_Size ; i++)
	 {
		XI[i] = XR[i];
	 }
	
		GET_code(XI, XR);
	
	  draw(XR, 512, 10);

		DMA_DeInit(DMA1_Channel1);
		adc_init(); 
		IWDG_Feed();
	}											    
}	
 
void Init(void) {
	int i = 0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	delay_init();	    	 //ÑÓʱº¯Êý³õʼ»¯	  
	uart_init(115200);	 	//´®¿Ú³õʼ»¯Îª9600
	LED_Init();		  		//³õʼ»¯ÓëLEDÁ¬½ÓµÄÓ²¼þ½Ó¿Ú
	LCD_Init();
	adc_init(); 
	IWDG_Init(4,3125); 
	i = 1000000 / Fs;
	tim1_pwm_config(72, (u16) i,1);	
	for(i = 0; i < 72; i++) {
		SIN[i] = SIN[i] * 5 ;
	}
	Dac2_Init();
	MYDMA_Config( (u32) & (DAC->DHR12R2), (u32)SIN, 72);
	//TIM4_Config(100000 / tim4, 0);
}

完整工程如有需要,请到微信小程序“非遗种草社”中留言

有关2022年电赛F题 信号调制度测量装置的更多相关文章

  1. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  2. 映宇宙2022年营收63亿元:同比下降三成,毛利率提升4.3个百分点 - 2

    3月26日,映宇宙(HK:03700,即“映客”)发布截至2022年12月31日的2022年度业绩财务报告。财报显示,映宇宙2022年的总营收为63.19亿元,较2021年同期的91.76亿元下降31.1%。2022年,映宇宙的经营亏损为4698.7万元,2021年同期则为净利润4.57亿元;期内亏损(净亏损)为1.68亿元,2021年同期的净利润为4.33亿元;非国际财务报告准则经调整净利润为3.88亿元,2021年同期为4.82亿元,同比下降19.6%。 映宇宙在财报中表示,收入减少主要是由于行业竞争加剧,该集团对旗下产品采取更为谨慎的运营策略以应对市场变化。不过,映宇宙的毛利率则有所提升

  3. Verilog使用inout信号的方法 - 2

    目录一、inout在设计文件中的使用方法1.1、inout的第一种使用方法1.2、inout实现的第二种使用方法1.3、inout使用总结 二、inout在仿真测试中的使用方法一、inout在设计文件中的使用方法在FPGA的设计过程中,有时候会遇到双向信号(既能作为输出,也能作为输入的信号叫双向信号)。比如,IIC总线中的SDA信号就是一个双向信号,QSPIFlash的四线操作的时候四根信号线均为双向信号。在Verilog中用关键字inout定义双向信号,这里总结一下双向信号的处理方法。1.1、inout的第一种使用方法  实际上,双向信号的本质是由一个三态门组成的,三态门可以输出高电平,低电

  4. ruby - 在 Ruby 中使用 GTK3 自定义信号 - 2

    我想从gtk3中的Widget发出自定义信号。在GTK2中,有一个名为signal_new的函数来创建一个新信号。您可以在此处查看示例:https://github.com/ruby-gnome2/ruby-gnome2/blob/ec373f87e672dbeeaa157f9148d18b34713bb90e/glib2/sample/type-register.rb在GTK3中,这个功能似乎不再可用。那么在ruby​​的GTK3中创建自定义信号的新方法是什么? 最佳答案 GTK3更改为使用define_signal方法而不是si

  5. ruby - QtRuby 使用参数/参数连接信号和槽 - 2

    我想知道如何连接到带参数的信号(使用Rubyblock)。我知道如何连接到一个不带参数的:myCheckbox.connect(SIGNAL:clicked){doStuff}但是,这不起作用:myCheckbox.connect(SIGNAL:toggle){doStuff}它不起作用,因为切换槽采用参数voidQAbstractButton::toggled(boolchecked)。我怎样才能让它与参数一起工作?谢谢。 最佳答案 对您的问题的简短回答是,您必须使用slots方法声明要连接的插槽的方法签名:classMainGU

  6. ruby - 发送信号时运行代码,但不要在 Ruby 中捕获信号 - 2

    我有在服务器上运行的代码,在服务器硬关闭之前,发送了一个信号SIGTERM让我的代码知道它需要清理。我想在发生这种情况时运行代码并将信号发送回同一个程序,以便任何其他需要清理的代码都可以这样做。我不想捕获信号或改变信号行为,我只需要在我的程序的其余部分解释SIGTERM之前运行一些东西。目前我可以做类似的事情Signal.trap('TERM')doputs"Gracefulshutdown"exitend但如果同一个应用中的多段代码试图做同样的事情,它就不起作用了。例如:Signal.trap('TERM')doputs"Gracefulshutdown"exitendSignal.

  7. IDEA 2022 创建 Spring Boot 项目详解 - 2

    如何用IDEA2022创建并初始化一个SpringBoot项目?目录如何用IDEA2022创建并初始化一个SpringBoot项目?0. 环境说明1.  创建SpringBoot项目 2.编写初始化代码0. 环境说明IDEA2022.3.1JDK1.8SpringBoot1.  创建SpringBoot项目        打开IDEA,选择NewProject创建项目。        填写项目名称、项目构建方式、jdk版本,按需要修改项目文件路径等信息。        选择springboot版本以及需要的包,此处只选择了springweb。        此处需特别注意,若你使用的是jdk1

  8. ruby - 如何从 Sass 混合方程中删除测量单位? - 2

    我编写了一个非常简单的Sassmixin,用于将像素值转换为rem值(请参阅JonathanSnook的articleonthebenefitsofusingrems)。这是代码://MixinCode$base_font_size:10;//10px@mixinrem($key,$px){#{$key}:#{$px}px;#{$key}:#{$px/$base_font_size}rem;}//Includesyntaxp{@includerem(font-size,14);}//RenderedCSSp{font-size:14px;font-size:1.4rem;}这个mixi

  9. 2022年10月23日周赛ZZULIOJ - 2

    文章目录问题B:芝华士威士忌和他的小猫咪们代码&注释问题C:愿我的弹雨能熄灭你们的痛苦代码注释问题D:猜糖果游戏代码注释问题E:有趣的次方代码注释问题F:这是一个简单题代码&注释问题G:打印矩阵代码注释问题H:scz的简单考验代码注释问题I:完美区间代码&注释问题J:是狂热的小迷妹一枚吖~代码&注释2022年10月23日周赛ZZULIOJ问题B:芝华士威士忌和他的小猫咪们时间限制:1Sec内存限制:128MB题目描述芝华士威士忌很喜欢带着他的猫咪们一块跑着玩。但是小猫咪们很懒,只有在离他y米以内才愿意和他一块跑。这天他在坐标为x的位置,他想和他的猫咪们一块跑着玩。有n个小猫咪,第i个小猫咪在坐

  10. 【华为OD机试真题 java、python、c++】荒地电站建设【2022 Q4 100分】(100%通过+复盘思路) - 2

    代码请进行一定修改后使用,本代码保证100%通过率,本题目提供了java、python、c++三种代码。复盘思路在文章的最后题目描述祖国西北部有一片大片荒地,其中零星的分布着一些湖泊,保护区,矿区;整体上常年光照良好,但是也有一些地区光照不太好。某电力公司希望在这里建设多个光伏电站,生产清洁能源对每平方公里的土地进行了发电评估,其中不能建设的区域发电量为0kw,可以发电的区域根据光照,地形等给出了每平方公里年发电量x千瓦。我们希望能够找到其中集中的矩形区域建设电站,能够获得良好的收益。输入描述第一行输入为调研的地区长,宽,以及准备建设的电站【长宽相等,为正方形】的边长最低要求的发电量之后每行为

随机推荐