目录
今年四天三夜的电赛,对于我来说终于算是圆满了,还记得去年大二的时候参加电赛,还是什么都不知道,跟着两个大三的学长组队,最后选择了E题,结果最后因为当时还没有学习高频,比赛过了两天才差不多看懂题目,最后草草收场,一无所得。
而今年,我做了充分的准备,由于我们实验室是偏向于做信号测量与处理的,为此今年能做的只有D和F题,F题和去年的E题有一点类似,但想到去年结果,让我对这类的题有点小阴影,但D题混沌信号发生器,虽然电路图简单,但是没有练习过,而F题对于我们来说第一问肯定可以做出来,最终,权衡再三,我们组选择了F题,经过四天三夜的不懈努力,我们也是最终完整的实现了题目要求。
为了纪念一下这个过程,特意写此博客,和大家分享一下我们做题的经历,以及编写代码的思想。 在这篇文章中,你可以看到我们做F题的整体思路以及设计方案,由于我同时负责代码的编写,因此文章的重点将在算法这一方面,硬件方面我将只简单提一下如何搭建。
设计制作信号调制度测量装置,该装置测量并显示信号源输出的被测信号调制度等参数,识别并显示被测信号的调制方式,输出解调信号。
(1)被测信号为电压峰峰值100mV的普通单音调幅(AM)电压uAM,其载频为10MHz、调制信号为频率1~3kHz的正弦信号。测量并显示uAM的调幅度ma,要求测量误差绝对值≤0.1;输出解调信号,要求解调信号波形无明显失真。 (20分)
(2)被测信号为电压峰峰值100mV的单音调频(FM)电压uFM,其载频为10MHz、调制信号为频率3~5kHz的正弦信号。测量并显示uFM的调频度mf,测量误差绝对值|Δ|≤0.3;测量并显示的最大频偏Δfm (kHz);输出解调信号,要求解调信号波形无明显失真。(25分)
(3)被测信号为载波电压峰峰值100mV的高频电压,其载频范围为10MHz~30MHz(频率步进间隔0.5MHz)。若为已调波(AM或FM波)时,其调制信号为频率范围5kHz~10kHz(频率步进间隔1kHz)内某一频率的正弦信号。测量装置应能自主识别的调制方式,即能判断出为调幅、调频或未调载波。测量并显示的调制度(或),测量误差要求分别同前面第 (1) 、(2)项的要求;当被测信号为调频波时,要求测量并显示其最大频偏(kHz);输出解调信号,要求解调信号波形无明显失真。(45分)
(1)题中“普通单音调幅波”是指:载波为正弦波,调制信号为单频正弦信号,其频谱包括完整的载频与上、下边频分量。题中“单音调频波”是指:载波为正弦波,调制信号为单频正弦信号。
(2)本题被测信号为AM信号时,其调幅度范围是:0.2<ma≤1;被测信号为FM信号时,其调频度范围是:1<mf≤6;被测信号为未调载波,是指被测信号为正弦载波或连续波(CW)。本题第(3)项要求测量装置能自主识别出被测信号的三种可能调制方式。
(3)如测量装置需对被测信号进行A/D变换,应借鉴适用于对高频窄带信号抽样的“带通抽样定律”。“奈奎斯特抽样定律”亦称为“低通抽样定律”,它适于对基带信号的抽样。
(4)测试时可自带具有AM/FM调制信号输出功能的信号源,并以自带信号源输出信号的参数设置值作为测量基准值。
(5)要求第(3)项的操作必须是一键启动,装置应连续完成调制方式识别与调制度等参数的测量和显示,测量过程中不得有人工介入。
首先,阅读完题目之后,我们可以得出以下信息:
第一问 要求我们实现10MhZ载波下AM的解调以及ma的测量;
第二问 要求我们实现10MhZ载波下FM的解调以及mf和Δfm 的测量;
第三问要求我们实现在自动识别AM,FM,CW的情况下,自动测量10-30MhZ载波的对应参数。
由此,可以看出,F题的关键在于AM,FM的解调;ma,mf,Δfm 的测量;AM,FM,CW的识别;以及自动测量这几个方面。
AM调幅信号具体表达式如下
uAM(t)=Uc[1+mf(t)]cos(wct) (2-1)
其中,Uc为调幅信号幅度,f(t)为调制信号,cos(wct)为载波,m即为ma。
当f(t)为正弦波sinxt(即题目要求的调制信号)时:
uAM(t) = Uccos(wct) + Ucmsinxtcos(wct)
=Uccos(wct) + Ucm/2( sin(xt+wct) + cos(xt-wct))
由此我们可以看出,AM信号中有三种频率的正弦波,分别是wc,(x+wc),(wc-x)。这正是AM的频谱分布,即,AM信号的频率分量=3,在之后我们会用到。
方法一:直接测AM信号的波峰和波谷幅度可得,公式如下:
ma = (A-B)/(A+B)=波谷/波峰 (2-2)

方法二:测量载波和调制信号幅度可得,公式如下:
ma = K Uc/Uf (2-3)
其中K为系数,受不同的调制方式影响,通常当调制方式确定后,K将不在改变,只需已知调制度ma的基础上,反推一次K即可。
当然,值得注意的是,当载波和调制信号经过相同的线性变化后,(2-3)仍可适用,只不过K会发生变化。
对于这次题目来说,直接测量波峰波谷幅度难度较大,为此采用公式(2-3)计算ma。而Uc与Uf 可以通过FFT分析AM波形得到。K系数的确定只需在搭建好系统后进行一次标定即可。
可能有些朋友对FFT比较陌生,只需要知道FFT是一种可以分析出周期信号的频谱和对应幅度的算法即可。
AM信号大体有两种解调方法,相干解调和非相干解调,其中,非相干解调中的包络检波电路最为简单,只需检波二极管和电阻电容即可搭建,其中检波二极管推荐2AP9,针对此频段效果较好。
我们最开始采用包络检波,但之后发现了更好的方案,便进行的替代,具体方案在FM中细说。
FM调频信号具体表达式如下
uFM(t)=Uccos(wct+msinxt) (3-1)
其中,Uc为调频信号幅度,f(t)为调制信号,cos(wct)为载波,m即为mf。
由此可见,FM信号的相位会产生规律性的变化,由此体现在频谱上则是会在载波频率附近产生其他的频率分量,当mf>1时,总共的频率分量>3。
对于这道题,我们只需要知道以下几点:FM的解调方式以及mf和Δfm 的计算。
对于解调,如果不了解原理也没有关系,直接使用现有的FM解调模块即可,网上均有售卖,这不是这个题目的重点。我们则是采用了CD1691芯片,这是一个固定频率的AM,FM的集成解调模块,多在收音机中出现。模块原理图如图所示:

当然,这个模块依旧是有局限性的,其只能解调455K的AM信号和10.7MHz的FM信号,且15脚控制AM和FM模式的切换,即其无法自动识别AM和FM信号。
为了使用这个模块解调,我们需要将题目要求的信号频率转化到CD1691能够解调的频率范围去。为此,就需要用到混频,简单来说就是需要将其与一个指定频率的正弦波相乘,从而改变载波频率,原理公式如下:
sinxsiny = 1/2( sin(x+y) + cos(x-y) ) (3-2)
就是 利用积化和差公式实现混频,例如,当信号为10MHz的FM信号把其看作sinyt(实际上其并不是一个单一频率的信号,但其的频谱分布是在10MHz附近),我们只需要将其与频率为20.7M的正弦波sinxt相乘,就可以得到10.7MHz和30.7MHz两个频率的FM信号之和,将其送入CD1691模块中,其会解调出频率为10.7MHz的FM信号,而30.7MHz的则会自动过滤,从而实现FM信号的解调,AM解调也是同样的道理。
当然,具体操作起来仍有两个问题需要解决:
AM和FM信号的判断,由此控制CD1691模块处于AM/FM模式;
载波频率的判断,由此决定sinx频率;
PS:第二个问题是打算做第三问时考虑,第一,二问的载波频率固定为10MHz,相当于sinxt的频率也是固定的,对于AM,为9.55MHz,FM则20.7MHz。
对于第一个问题,很明显,需要我们根据AM和FM的不同的进行判断,而在二者最开始的介绍中,我已经有所提示,AM的频谱图上恒有3个波峰(频率分量恒为3),FM的频谱图上的波峰恒大于3(mf>1时,而题目正好要求mf>1)。这正是区别两种波形的依据。
那么,一提到分析信号的频谱。我们自然就会想到FFT算法,其是专门用来分析信号不同频率分量的算法。但其受限于采样频率fs,在实时采样中要求 fs>2f(f为信号频率),FFT才能基本分析出信号频率,而根据经验来说,当 fs>5f 左右时,才可以基本分析准确。而再考虑到STM32系列的内置ADC实际采样频率最大为1MHz,10MHz及以上的信号根本无法直接进行采样。
因此,对于ADC的所需要采样的信号,同样需要进行信号处理,最简单的1办法也是进行混频,将其混至32可以采样的频段。在此,我采用的是混频至200kHz并且使用等效采样(为了不再受限于采样频率,提高准确度)的方式,在对混频后的信号进行(在此之前,需要过一个低通滤波器,把高频分量滤除)采样以及FFT分析,再通过数波峰个数的方法判断波形。这样,第一个问题就解决了。
对于第二个问题,其实也是通过判断频谱的方式解决,具体做法等到代码部分进行解释。
PS:由于FFT具体测频时需要注意的东西较多,之后我会再写一篇来介绍FFT和等效采样。
原理就不解释了,直接上公式
mf = K Uo/fo (3-3)
Δfm = mf*fo = K Uo (3-4)
Uo为解调后的波形幅度,fo为解调后的波形频率,即为调制信号的频率,K为比例系数,由硬件具体电路决定。由这两个公式我们可以很明显地看出,其解调信号的幅度受其Δfm的影响,Δfm越大,幅度越大。
为此,我们只需要再输出部分利用峰值检波模块测量FM解调后信号的峰值再用ADC采集,再测出其的频率,即可得到mf和Δfm。
由2和3,我们可以大体得到整个系统的框架,系统框架图如下:
通过使用DS4062函数信号发生器产生FM/AM信号,前级通过VCA821程控放大器进行放大,输入至两路AD835模拟乘法器,其中一路AD835模拟乘法器与AD9851本地追踪信号相乘后,通过无源LC低通滤波器滤除高频分量实现频谱搬移,后送入STM32嵌入式MCU进行频谱分析,实现当前调制模式的判断,以及AM情况下ma的计算,另一路信号通过AD835模拟乘法器与AD9854本地解调信号相乘后进入FM/AM选择模块,经过MCU进行调制识别后再送入FM/AM集成解调器进行解调,再将其送入AD8052放大器放大(方便FM时测幅度),若鉴定为调幅波输出解调波形;若鉴定为调频波,则将其中一路送入峰值检波,另一路送入自动增益控制系统,将其幅度进行增益放大(方便32进行测频),一路送入STM32嵌入式MCU进行频率识别,由此计算mf,另一路直接输出。
PS: 这里采用AD8052和VCA821是因为其高频特性较好。
最终电路搭建如下:

ADC采样使用定时器控制ADC进行采样,同时采用DMA传输节省资源实现,FFT则是直接调用官方库。ADC初始化不再赘述,详见附件代码,调用FFT函数进行FFT分析放法如下:
//进行FFT分析的方法
//ADC_Value[i]为DMA下ADC采集到的数据
//lBufOutArray为计算结果
//GetPowerMag();是将lBufOutArray进行处理得到各个频率分量lBufMagArray
for(i=0;i<NPT;i++)
{
lBufInArray[i]=ADC_Value[i]<<16;
}
cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT);
GetPowerMag();
在得到各个频率分量lBufMagArray后,我们则可以直接对其进行寻找峰值的操作,从而得到波峰个数,函数如下:
//a为lBufMagArray,返回值及为波峰个数
int peak_count2(unsigned int *a)
{
int i,j,count = 0;
unsigned int *pp = a;
unsigned int aMax =0;
for ( i=1; i < 150; i++)
{
if (a[i]>aMax)
{
aMax = a[i];
}
if ((a[i]>a[i+1])&&(a[i]>a[i-1])&&(a[i]>80))
//80是为过去峰值较小的频率,滤去干扰,可以根据实际情况调整
{
count++;
}
pp++;
}
if(aMax <200)
count = 0;
if(aMax >1500)
count = 1;
return count;
}
当对采集后的信号进行FFT分析和波峰个数的计数后,由AM,FM.CW(正弦波,只有一种频率,即波峰只有一个)的特征,便可判断出此时波形的类型,函数如下:
//AM,FM波形判断
void wave_judge()
{
int i,j,cnt;
u32 Fre2;
POINT_COLOR=WHITE;
BACK_COLOR=BLACK;
for(i=0;i<NPT;i++)
{
lBufInArray[i]=ADC_Value[i]<<16;
}
cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT);
GetPowerMag();
cnt = peak_count2(lBufMagArray);
if(cnt <= 1)
{
wave_status = CM;
LCD_Fill(260,0, 320,170, BLACK);
LCD_ShowString(270,180,25,30,24," CW ");
}
else if(cnt <= 3)
{
wave_status = AM;
//wc_cnt = 0;
//控制继电器进行切换输出的解调波类型
GPIO_ResetBits(GPIOC,GPIO_Pin_4);
LCD_ShowString(270,180,25,30,24," AM ");
//控制AD9854输出对应的sinx实现混频
Fre2 = 9050000+500000*wc_cnt;
AD9854_SetSine(Fre2,4000);
//wc_cnt = 0;
delay_ms(500);
//计算ma
show_ma();
}
if(cnt > 3)
{
wave_status = FM;
GPIO_SetBits(GPIOC,GPIO_Pin_4);
LCD_ShowString(270,180,25,30,24," FM ");
//控制AD9854输出对应的sinx实现混频
Fre2 = 20200000+500000*wc_cnt;
AD9854_SetSine(Fre2,4000);
delay_ms(500);
//计数mf和频偏
show_mf();
}
}
扫频和频率判断的思路其实很简单,首先是扫频,之前已经提到过,不同频率的信号,想要将其混频至同一个频段,所需要乘的sinxt频率是不一样的,有着一一对应的关系,而当混频后的频率不在这个频段时,FFT分析出的频谱图上面理想情况是没有波峰的。而第三问的载波频率只有固定的40种,我们只需要依次使用对应的sinxt进行混频。判断FFT结果是否有波峰,如果没有,说明此时的sinxt不是当前载波频率所要的,再切换下一个sinxt继续判断,直到出现波峰时,说明此时混频成功,而由于不同的sinxt和载波频率是一一对应的关系,我们也就间接得到了此时的载波频率。
这就是扫频和频率判断的基本算法,具体扫频代码如下:
void scan_f()
{
int i,j,cnt;
u8 str[20];
{
Fre = 9300000;//混频到200k
}
POINT_COLOR=WHITE;
BACK_COLOR=BLACK;
//依次设置两路DDS频率
AD9854_SetSine (Fre ,4000);
Write(Fre,Power_Down,0); //AD9851
delay_ms(600);
for(i=0;i<NPT;i++)
{
lBufInArray[i]=ADC_Value[i]<<16;
}
cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT);
GetPowerMag();
lcd_show_fft(lBufMagArray);
//数波峰个数
cnt = peak_count2(lBufMagArray);
wc_cnt = 0;
for(j = 0;j<42;j++)
{
if (cnt == 0)//说明未到达指定频率
{
//wc_cnt 设计的是全局变量,用于间接当前载波频率
wc_cnt = wc_cnt + 1;
sprintf((char *)str," wc:%d ",wc_cnt);
LCD_ShowString(260,458,60,30,12,(uint8_t *)str);
Fre += 500000;//题目的信号步进为0.5M
Write(Fre,Power_Down,0); //AD9851 控制STM32采集那一路
delay_ms(600);//给予DMA缓冲时间
AD9854_SetSine (Fre ,4000);
for(i=0;i<NPT;i++)
{
lBufInArray[i]=ADC_Value[i]<<16;
}
cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT);
GetPowerMag();
cnt = peak_count2(lBufMagArray);
}
}
}
波形判断以及改变对应输入CD1691的频率则交给wave_judge()进行。
这样就实现了一次扫频,如果想实现自动扫频只需要在此函数外多添加些条件即可,具体见后文。
之前提到过,其 ma = K Uc/Uf
对于FFT分析后的频谱图,简单来说,就是次峰幅度/主峰幅度 * K,K需要标定。
对于我们的系统来说,K 计算下为 2左右。代码如下
寻找峰值,次峰值代码:
//p为lBufMagArray
void lcd_print_fft(unsigned int *p)
{
unsigned int *pp = p;
unsigned int i = 0,j = 0,flag[NPT/2] ={0} ;
float f[NPT/2]={0.00},a[NPT/2]={0.00};
for(i=0;i<NPT/2;i++)
{
if(*pp>10)
{
f[j]=(float)i*Fs/NPT;
a[j]=(float)*pp*(3.3/4096);
flag[j] = i;
j++;
}
pp++;
}
select_max(f,a,j,flag);
}
//寻找最大,次大值
void select_max(float *f,float *a,unsigned int ij,unsigned int *flag)
{
int i,j;
float aMax =0.0,aSecondMax = 0.0;
float aMax_pr =0.0,aSecondMax_pr = 0.0;
float fMax =0.0,fSecondMax = 0.0;
int nMax=0,nSecondMax=0;
for ( i = 1; i < ij; i++)//i±ØÐëÊÇ1£¬ÊÇ0µÄ»°£¬»á°ÑÖ±Á÷·ÖÁ¿¼Ó½øÈ¥£¡£¡£¡£¡
{
if (a[i]>aMax)
{
aMax = a[i];
nMax=i;
fMax=f[nMax];
}
}
for ( i=1; i < ij; i++)
{
if (nMax == i)
{
continue;
}
if (a[i]>aSecondMax&&a[i]>a[i+1]&&a[i]>a[i-1])
{
aSecondMax = a[i];
nSecondMax=i;
fSecondMax=f[nSecondMax];
}
}
//为了克服栅栏效应,减小误差
aSecondMax_pr =sqrt(lBufMagArray[flag[nSecondMax]]*lBufMagArray[flag[nSecondMax]]+lBufMagArray[flag[nSecondMax]+1]*lBufMagArray[flag[nSecondMax]+1]
+lBufMagArray[flag[nSecondMax]-1]*lBufMagArray[flag[nSecondMax]-1]+lBufMagArray[flag[nSecondMax]-2]*lBufMagArray[flag[nSecondMax]-2]
+lBufMagArray[flag[nSecondMax]+2]*lBufMagArray[flag[nSecondMax]+2])*(3.3/4096);
ma = ((aSecondMax_pr/aMax)*2);
}
ma即为所求,当然,为了进一步减小误差,采用中值滤波法以及标定系数的方式实现,优化后的ma如下:
//采用中值滤波法减小误差
void show_ma()
{
int i,j;
float tmd[N_TMD];
float temp;
float ma_now;
for(j=0;j<N_TMD;j++)
{
for(i=0;i<NPT;i++)
{
lBufInArray[i]=ADC_Value[i]<<16;
}
cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT);
GetPowerMag();
lcd_print_fft(lBufMagArray);
//ma为全局变量
tmd[j] = ma;
}
//再次进行采样
for( i=0;i<N_TMD-1;i++)
{
for( j=0;j<N_TMD-1-i;j++)
{
if(tmd[j] > tmd[j+1])
{
temp = tmd[j];
tmd[j] = tmd[j+1];
tmd[j+1] = temp;
}
}
}
LCD_Fill(260, 0, 320,119, BLACK);
LCD_Fill(260, 320, 320,360, BLACK);
LCD_ShowString(275,120,30,20,16,"ma:");
if(tmd[4] >0.89)
ma_now = tmd[4]-0.03;
if(tmd[4] <=0.89)
ma_now = tmd[4]+0.08;
LCD_ShowFloat3(260,150,ma_now,6,16);
}
由之前的公式 mf = K Uo/fo
可知,只需测得FM解调信号幅度以及频率便可得知mf和Δfm,幅度可以直接通过另一路ADC测量峰值检波输出即可,频率为了简化代码,直接采用定时器输入捕获测量,通常其用于测方波,但经过实际证明,当正弦波信号波谷在(0-300mv)时波峰在(1.9v-3.3v)时,其测量正弦波的频率误差同样很小,这也是在系统设计时FM解调输出接自动增益模块(AGC)的原因,为了保证幅度在此范围内。
在实际情况种,我们发现,不同频率段的K有较为明显的差别,为了减小误差,我对K值进行了分频段标定,最终测量代码如下:
//FM测频率
int FM_fre()
{
int i,j;
int tmd[N_FMf];
int temp;
for(j=0;j<N_FMf;j++)
{
tmd[j] = (int)((float)(2000000)/(float)(Rising_Last-Falling));
}
//冒泡排序
for( i=0;i<N_FMf-1;i++)
{
for( j=0;j<N_FMf-1-i;j++)
{
if(tmd[j] > tmd[j+1])
{
temp = tmd[j];
tmd[j] = tmd[j+1];
tmd[j+1] = temp;
}
}
}
//采用中值滤波
return tmd[4];
}
//计算mf和频偏
void show_mf()
{
float FM_f,range;
float mf = 0,f_sh = 0;
//标定比例系数K
float K[8] = {35.5,44,53,61,70,78,87,96};
u8 str[20];
//测频率
FM_f = FM_fre();
//测幅度
range = Get_Adc_Average(ADC_Channel_0,5);
{
//9.9k以上
if(FM_f >9900)
{
f_sh = range*K[7];
mf = f_sh/FM_f;
}
//8.9-9.9
else if(FM_f >8900)
{
f_sh = range*K[6];
mf = f_sh/FM_f;
}
//7.9-8.9
else if(FM_f >7900)
{
f_sh = range*K[5];
mf = f_sh/FM_f;
}
//6.9-7.9
else if(FM_f >6900)
{
f_sh = range*K[4];
mf = f_sh/FM_f;
}
//5.9-6.9
else if(FM_f >5900)
{
f_sh = range*K[3];
mf = f_sh/FM_f;
}
//4.9-5.9
else if(FM_f >4900)
{
f_sh = range*K[2];
mf = f_sh/FM_f;
}
//3.9-4.9
else if(FM_f >3900)
{
f_sh = range*K[1];
mf = f_sh/FM_f;
}
//2.9-3.9
else if(FM_f >2900)
{
f_sh = range*K[0];
mf = f_sh/FM_f;
}
}
sprintf((char *)str,"F:%d ",(int)FM_f);
LCD_ShowString(260,320,60,30,12,(uint8_t *)str);
sprintf((char *)str,"A:%d ",Get_Adc_Average(ADC_Channel_0,5));
LCD_ShowString(260,340,60,30,12,(uint8_t *)str);
LCD_ShowString(275,0,30,20,16,"mf:");
LCD_ShowFloat3(260,30,mf,6,16);
LCD_ShowString(275,60,30,20,16,"f_sh");
LCD_ShowxNum(270,90,(u32)f_sh,5,12,0);
LCD_Fill(260, 120, 320,170, BLACK);
}
由于我们最终将三问都做出来了,因此直接使用的第三问代码,同样可以测量前两问(无非载波频率不一样),为了实现定时判断当前状态,采用了状态机的原理,通过记录次态和现态来实现。最终主函数如下:
int main(void)
{
int i,cnt2;
u8 key;
u32 Fre3;
u8 str[20];
delay_init();
uart_init(115200);
LCD_Init();
KEY_Init();
{
TIM1_Int_Init(189-1,2-1);//200kHz
}
TIM2_Cap_Init();
GPIO_AD9854_Configuration();
AD9851_Configuration();
delay_ms(50);
AD9854_Init ();
Adc_Init2();
ADC1_Configuration();
DMA_Configuration();
LCD_Clear(BLACK);
POINT_COLOR=WHITE;
BACK_COLOR=BLACK;
{
Fre = 9300000;
}
delay_ms(50);
AD9854_SetSine(Fre ,4000);
Write(Fre,Power_Down,0);
while(1)
{
//自动测量程序
{
delay_ms(500);
for(i=0;i<NPT;i++)
{
lBufInArray[i]=ADC_Value[i]<<16;
}
cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT);
GetPowerMag();
lcd_show_fft(lBufMagArray);
cnt2 = peak_count2(lBufMagArray);
if(cnt2 == 0)//说明此时载波频率发生了变化
{
scan_f();
wave_judge();
}
else//载波频率未变
{
if(cnt2 <= 3)
wave_status_now = AM;//设置现态为AM
if(cnt2 > 3)
wave_status_now = FM;//设置现态为FM
//当上一次状态和此时均为AM时
if(wave_status == AM && wave_status_now == AM)
{
//再一次计算ma
show_ma();
//更新现态
wave_status = AM;
}
//同理
if(wave_status == FM&& wave_status_now == FM)
{
show_mf();
wave_status = FM;
}
//说明载波类型发生了变化,而载波频率未变
if(wave_status == AM && wave_status_now == FM)
{
//切换输出通道
GPIO_ResetBits(GPIOC,GPIO_Pin_4);
//再次扫频
scan_f();
wave_judge();
}
if(wave_status == FM && wave_status_now == AM)
{
//切换输出通道
GPIO_ResetBits(GPIOC,GPIO_Pin_4);
scan_f();
wave_judge();
}
}
}
}
}
最后,附上详细过程,有需要的可以下载参考:
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实
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%。 映宇宙在财报中表示,收入减少主要是由于行业竞争加剧,该集团对旗下产品采取更为谨慎的运营策略以应对市场变化。不过,映宇宙的毛利率则有所提升
1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva
目录一、inout在设计文件中的使用方法1.1、inout的第一种使用方法1.2、inout实现的第二种使用方法1.3、inout使用总结 二、inout在仿真测试中的使用方法一、inout在设计文件中的使用方法在FPGA的设计过程中,有时候会遇到双向信号(既能作为输出,也能作为输入的信号叫双向信号)。比如,IIC总线中的SDA信号就是一个双向信号,QSPIFlash的四线操作的时候四根信号线均为双向信号。在Verilog中用关键字inout定义双向信号,这里总结一下双向信号的处理方法。1.1、inout的第一种使用方法 实际上,双向信号的本质是由一个三态门组成的,三态门可以输出高电平,低电
我一直在尝试用Ruby实现Luhn算法。我一直在执行以下步骤:该公式根据其包含的校验位验证数字,该校验位通常附加到部分帐号以生成完整帐号。此帐号必须通过以下测试:从最右边的校验位开始向左移动,每第二个数字的值加倍。将乘积的数字(例如,10=1+0=1、14=1+4=5)与原始数字的未加倍数字相加。如果总模10等于0(如果总和以零结尾),则根据Luhn公式该数字有效;否则无效。http://en.wikipedia.org/wiki/Luhn_algorithm这是我想出的:defvalidCreditCard(cardNumber)sum=0nums=cardNumber.to_s.s
下面是我写的一个计算斐波那契数列中的值的方法:deffib(n)ifn==0return0endifn==1return1endifn>=2returnfib(n-1)+(fib(n-2))endend它工作到n=14,但在那之后我收到一条消息说程序响应时间太长(我正在使用repl.it)。有人知道为什么会这样吗? 最佳答案 Naivefibonacci进行了大量的重复计算-在fib(14)fib(4)中计算了很多次。您可以将内存添加到您的算法中以使其更快:deffib(n,memo={})ifn==0||n==1returnnen
为了防止在迁移到生产站点期间出现数据库事务错误,我们遵循了https://github.com/LendingHome/zero_downtime_migrations中列出的建议。(具体由https://robots.thoughtbot.com/how-to-create-postgres-indexes-concurrently-in概述),但在特别大的表上创建索引期间,即使是索引创建的“并发”方法也会锁定表并导致该表上的任何ActiveRecord创建或更新导致各自的事务失败有PG::InFailedSqlTransaction异常。下面是我们运行Rails4.2(使用Acti
我想从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
我想知道如何连接到带参数的信号(使用Rubyblock)。我知道如何连接到一个不带参数的:myCheckbox.connect(SIGNAL:clicked){doStuff}但是,这不起作用:myCheckbox.connect(SIGNAL:toggle){doStuff}它不起作用,因为切换槽采用参数voidQAbstractButton::toggled(boolchecked)。我怎样才能让它与参数一起工作?谢谢。 最佳答案 对您的问题的简短回答是,您必须使用slots方法声明要连接的插槽的方法签名:classMainGU