C语言——二分法得出测量电容值对应的纸张数(电赛19年纸张计数装置)

本人在备战2021年全国大学生电子设计竞赛的训练中,练习了19年的纸张计数装置的题目。在最终由单片机MCU学习计算拟合出的电容曲线,以及对应纸张数相应的电容值利用二分法得到最终测量的纸张数。以下介绍我们使用二分法的实际用法以及在使用过程中碰到的一些问题。

在此工程中二分法的作用是:在若干个大小排列后的数据(存储在数组)中,遍历寻找测量数据与这若干个数据中最接近的数据所对应的位置。

int half=35,low=0,high=70;

void Half_FindPlace(void)
{
    
    
	
	if(low<high)
	{
    
    if(Data_temp<Data[half]-(Data[half]-Data[half+1])/2)
	{
    
    
	low=half+1,high=high;
	}
	else
	{
    
    
		  
	high =half,low=low;
	}
    }
half =(high+low)/2;
}

函数中low就是二分法左边界,high是二分法的右边界,half是我们的中间值。
如果我们有70个数据那么我们 half我们取中间值half=35,左边界low=0,右边界=70。

解释一下函数的意思,在数据大小递减的数组中,我们将测得的数据跟我们的中间值的右边界进行比较。若小于,“往左边查询” 则我们的左边界变为之前的中间值,右边界不变。否则“往右边查询”我们的右边界为之前的中间值,左边界不变。递增则相反即可。

如下图所示,因为所拟合出来的数据不是完全线性的所以我们这样取值,去两相邻值的进行平分的方法,进行平分。如果我们测量的数据落在Data[3]的范围内,我们就返回4(也就是距离第四个数据最近)。从而实现根据测量值返回对应的最优、距离最近的数据位置。
在这里插入图片描述简易的解释下这张图吧。举个例子:比如我用算法计算处的1张纸的数据是100,2张纸的数据是50,3张纸的数据是30。那么第二张纸的范围就是((100+50)/2,(50+30)/2)。假设我们实际测量到的数据为45 ,它距离2张纸对应的50最近,那么二分法计算出来的最终结果就为2。

以下是我们进行二分法的操作流程,我们假设有60个数据 即high=60,low=0,half=30.

我们列举出其中13张-17张纸的对应的MCU计算出的数据,并且符合电容衰减的大致曲线图(下降的斜率越来越平缓)之后假设实际测量的现场数据为45。然后我们进行遍历二分法。将每一步low、half、high的值记录,让大家充分了解二分法的作用过程。每一步都按照程序中的与中间值的右边界进行比较,从而慢慢缩小范围,慢慢逼近寻找的对应纸张数。

当low=high,那么我们就可以输出当前的half值,就是我们需要得到的结果。
在这里插入图片描述

重点:
1.low、high、half都定义为int型,如果做除法为小数的话,则省略小数部分。
eg:(11+12)/2=11

2.若数据总个数为x,那么我们二分法的次数n至少应满足2^n>x;
若数据总个数为60,那么我们二分法至少要遍历6次。
若数据总个数为30,那么我们二分法至少要遍历5次

3.在使用时应搭配for循环进行使用,若数据个数为60个,那么我们应该for循环至少六次,即执行六次二分法才能够得到想要的结果。在我们实际应用当中,如在单片机的程序编写中,(stm32、AT89C51、MSP430等)我们会碰见二分法只执行一次,或者二分法一直执行占用系统资源。for循环就很好的解决了这一问题,既能得出想要的结果,还能不一直占用系统资源。

4.每次重新测量时,我们应该将low,half,high的值初始化。

5.我们遍历二分法的结果往往可能与实际结果相差一点,比如在测量纸张数时,可能由于实际环境的干扰,我们的结果老是稳定差一张,那么我们就可以将右边界的权重稍微修改。之前是两个相邻数据之和0.5 ,我们可以根据实际情况将其改为0.4或*0.6等等,从而使我们的结果便懂得更加准确。

以上就是我对二分法在实践应用中的一些见解,如果有疑问或者有相关想法可以在评论区讨论!如果觉得文章对你有用的话,欢迎评论、点赞、关注哦!

猜你喜欢

转载自blog.csdn.net/qq_46336588/article/details/121597770