【血压】 最小二乘法高斯拟合 c语言实现 【高斯列主元素消元法,选主元,高斯拟合】

【血压】 最小二乘法高斯拟合 c语言实现

基础原理

最小二乘法&高斯函数变形
在这里插入图片描述
在这里插入图片描述

GuassFitTest.h

#ifndef GUASSFITTEST_H
#define GUASSFITTEST_H
#include "ALG.h"
/*该工程作为单片机最小二乘法高斯拟合的测试工程*/

//变量声明放在c文件,函数声明放在h文件

//高斯公式原理可参考:
//https://blog.csdn.net/dingzj2000/article/details/103719368
//数值计算方法教材 103-108页
// fai0 = 1   fai1 = x   fai2 = x^2

#endif


GuassFitTest.c

/**************************************
2021 04 10
作者:SZU guangjie2333
功能:c语言实现最小二乘法高斯拟合
*************************************/


/*头文件引用*/
#include "GuassFitTest.h"


/*内部变量定义*/

//拟合曲线的袖带压AD
static int cuffPressAD[14] = { 2863,2717,2586,2461,2346,2220,2117,
						2053,1950,1882,1807,1718,1643,1557 };
//拟合曲线的脉搏波AD
static int paluseAD[14] = { 5622,4007,3004,4229,8464,9874,12125,
					10680,8704,6426,4256,4114,3555,3243 };
//放气阶数
int s_iPluseStepCnt = 14;


/*主函数*/
void main()
{
	B_parameter B;
	Gaussian_parameter guassian;
	float Z[14]; //高斯函数两边取对数,变形,得到一个二次函数。 Z[i] = ln y[i] = ln paluseAD[i]
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		cuffPressAD[i] =(int)(cuffPressAD[i] * 0.097 - 108);  //AD-真实值  线性转换公式
		paluseAD[i] =(int)(paluseAD[i] / 16);                 //脉搏波AD放大了16倍
		Z[i] = log(paluseAD[i]);
		printf("cuffPressAD[%d] = %d \n  paluseAD[%d] = %d \n Z[%d] = %f \n",i, cuffPressAD[i], i,paluseAD[i],i,Z[i]);
	}
	//计算最小二乘法的B向量
	B = GaussianElimination(Z, cuffPressAD,s_iPluseStepCnt);
	//计算高斯曲线的参数
	guassian = CalcGaussianParameter(B);
	//0~250点进行高斯拟合
     GuassFit(guassian);

	printf(" \n\n b0 = %f  b1 = %f  b2 = %f \n\n",B.b0,B.b1,B.b2);
	printf(" \n\n a = %f  b = %f  c = %f \n\n",guassian.a, guassian.b, guassian.c);
}



ALG.h

#ifndef ALG_H
#define ALG_H

/*该文件是算法函数的头文件*/

#include "stdio.h"
#include "stdlib.h"
#include  "math.h"

typedef struct
{
	float b0;
	float b1;
	float b2;
}B_parameter;

typedef struct
{
	float a;
	float b;
	float c;
}Gaussian_parameter;

typedef struct
{
	float value;
	int index;
}matrixData;

//高斯列主元素消元法,返回b0,b1, b2
B_parameter GaussianElimination(float* y, int* x, int s_iPluseStepCnt); 
//计算高斯曲线参数
Gaussian_parameter CalcGaussianParameter(B_parameter B);
//0~250高斯拟合
void GuassFit(Gaussian_parameter gaussian);
#endif // !ALG


## ALG.c

#include"ALG.h"

/*该文件用于高斯拟合最小二乘法算法的c语言实现*/

/*************************************
* 宏定义区
**************************************/
#define ROW  3          //行
#define LINE 4          //列


/*************************************
* 内部变量定义区
**************************************/


//权重(由于前面的点会由于刚刚关阀的影响,脉搏波波动大,故权重为0)
w[14] = {0,0,0,1,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 };

/*************************************
* 内部函数定义区
**************************************/

//(fai0,fai0)的内积,返回1      求和
static float xfun0(int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		sum += 1 * w[i];
	}

	return sum;
}

//(fai0,fai1)的内积,返回x      求和
static float xfun1(int* x, int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0;i < s_iPluseStepCnt ; i++)
	{
		sum += x[i] * w[i];
	}

	return sum;
}

//(fai0,fai2) || (fai1,fai1)的内积,返回x^2    求和
static float xfun2(int* x, int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		sum += x[i]*x[i] * w[i];
	}

	return sum;
}


//(fai1,fai2)的内积,返回x^3    求和
static float xfun3(int* x, int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		sum += x[i] * x[i] * x[i] * w[i];
	}

	return sum;
}

//(fai2,fai2)的内积,返回x^4    求和
static float xfun4(int* x, int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		sum += x[i] * x[i] * x[i] * x[i] * w[i];
	}

	return sum;
}


//(y,fai0)的内积,返回y*1    求和
static float yfun0(float* y, int* x ,int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		sum += y[i] * 1 * w[i];
	}

	return sum;
}

//(y,fai1)的内积,返回y*x    求和
static float yfun1(float* y, int* x, int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		sum += y[i] * x[i] * w[i];
	}

	return sum;
}

//(y,fai2)的内积,返回y*1    求和
static float yfun2(float* y, int* x, int s_iPluseStepCnt)
{
	float sum = 0;
	for (int i = 0; i < s_iPluseStepCnt; i++)
	{
		sum += y[i] * x[i] * x[i] * w[i];
	}

	return sum;
}

//选第k次交换的列最大值当主元,返回所在行
static matrixData row_k_max(float matrix[ROW][LINE],int k)
{
	matrixData line[ROW] ;
	matrixData Max;
	//初始化
	for (int i = 0; i < ROW; i++)
	{
		line[i].value = 0;
		line[i].index = i;
	}
	//赋初值
	for (int i = k; i < ROW; i++)
	{
		line[i].value = matrix[i][k];
	}
	//比较大小
	Max.value = 0;
	for (int i = k; i < ROW; i++)
	{
		if (fabs(line[i].value) > fabs(Max.value))
		{
			Max = line[i];
		}
	}
	return Max;
}

//交换两行
static void swapRow(float matrix[ROW][LINE],int k, int maxRowE)
{
	float temp = 0;
	for (int i = 0; i < LINE; i++)
	{
		temp = matrix[k][i];
		matrix[k][i] = matrix[maxRowE][i];
		matrix[maxRowE][i] = temp;
	}
}

static void printfMatrix(float matrix[ROW][LINE])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0 ; j < LINE; j++)
		{
			printf(" %f ", matrix[i][j]);
		}
		printf("\n");
	}
}


/*
外部函数调用
*/

//高斯列主元素消元法,返回b0,b1, b2
B_parameter GaussianElimination(float* y, int* x, int s_iPluseStepCnt)
{
	B_parameter B;  //最小二乘法的待求解向量
	matrixData Max; //第k次交换,列的最大值和索引
	float m;

	//计算增广矩阵中的每个值
	float matrix[ROW][LINE];
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < LINE; j++)
		{
			if (LINE-1 == j)
			{
				//计算最后一列即Z向量的值
				switch (i)
				{
					case 0: matrix[i][j] = yfun0(y, x, s_iPluseStepCnt); break;
					case 1: matrix[i][j] = yfun1(y, x, s_iPluseStepCnt); break;
					case 2: matrix[i][j] = yfun2(y, x, s_iPluseStepCnt); break;
					default: break;
				}
			}
			else
			{
				//计算x矩阵的每个值
				switch (i+j)
				{
					case 0: matrix[i][j] = xfun0(s_iPluseStepCnt); break;
					case 1: matrix[i][j] = xfun1(x, s_iPluseStepCnt); break;
					case 2: matrix[i][j] = xfun2(x, s_iPluseStepCnt); break;
					case 3: matrix[i][j] = xfun3(x, s_iPluseStepCnt); break;
					case 4: matrix[i][j] = xfun4(x, s_iPluseStepCnt); break;
					default: break;
				}
			}

		}
	}

	printf("打印初始的矩阵\n\n");
	printfMatrix(matrix);

	//进行列主元素消元
	for (int i = 0; i < ROW-1; i++)   //i代表第i次交换
	{
		//选主元
		Max = row_k_max(matrix,i);
		//交换行
		if (Max.index != i)
		{
			swapRow(matrix,i,Max.index);
		}
		//消主元
		for (int j = i+1; j < ROW; j++)
		{
			m = matrix[j][i] / matrix[i][i];  //小除大,避免小值当分母
			for (int k = i; k < LINE ; k++)
			{
				matrix[j][k] = matrix[j][k] - matrix[i][k] * m; //消元
			}
		}

		printf("\n\n打印第%d次变化后的矩阵\n\n",i);
		printfMatrix(matrix);

	}

	//计算最小二乘法的B列向量
	B.b2 = matrix[ROW - 1][LINE - 1] / matrix[ROW - 1][LINE - 2];
	B.b1 = (matrix[ROW - 2][LINE - 1] - B.b2 * matrix[ROW - 2][LINE - 2])/ matrix[ROW - 2][LINE - 3];
	B.b0 = (matrix[ROW - 3][LINE - 1] - B.b2 * matrix[ROW - 3][LINE - 2] - B.b1 * matrix[ROW - 3][LINE - 3])/matrix[ROW - 3][LINE - 4];

	return B;

}

//计算高斯拟合参数a,b,c
Gaussian_parameter CalcGaussianParameter(B_parameter B)
{
	Gaussian_parameter gaussian;
	gaussian.a = exp((B.b0 - (B.b1*B.b1/(4*B.b2))));
	gaussian.b = -1 / B.b2;
	gaussian.c = -B.b1 / (2 * B.b2);
	return gaussian;
}

//从0到250 进行高斯拟合
void GuassFit(Gaussian_parameter gaussian)
{
	float y[250];
	for (int i = 0; i<250;i++)
	{
		y[i] = gaussian.a * exp(-(i-gaussian.c)* (i - gaussian.c) /gaussian.b);
		printf("%f \n",y[i]);
	}
}

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鄢广杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值