C语言函数指针的应用——利用双线性积分求一个自定义方波函数的谐波分析

简介

如果在一个大型C语言程序中要反复调用函数,而调用的函数又不明确时,函数指针就是一个非常有用的东西。如果你的函数体内可以传递不同的函数,那就非得用函数指针实现不可。下面我就用一个例子给大家分享一下C语言函数指针的妙用。

格式介绍

C语言函数指针的格式为(*function)([参数表列])。函数指针主要有两种使用方法:①用函数指针指向某个函数做选择②当做函数的参数传递,使程序模块化更强,耦合性更弱

代码

#include <stdio.h>
#include <math.h>	//需要用到平方和开方
#include <ctype.h> //根据输入表列智能检测有多少个值,需要用到isdigt数字判断函数
#include <malloc.h>	//根据输入的最高谐波次数动态分配内存存储谐波分量的值
#include <windows.h>	//使最后编写的exe可以脱离C环节运行,需要在代码末尾加system("pause");
#define pi 3.14159265	//pi值符号常量
double amplify(double (*function)(double x),int n);//双线性积分函数,参数为函数指针、上界、下界 
double RMS(double (*function)(double x));//对一个函数在周期内求有效值 
double square_wave(double x);	//方波函数,根据时间表列和数值表列查表实现函数分段
double period;//被分析方波的周期
double time[30]={0};//方波的时间时刻数组,首地址是从0附近的周期最左边的坐标开始的依次改变的电平处的值,只保留一个周期的 
double level[30]={0};//方波的电平数组,表示与时间区别对应的电平
int fund_f;//指定傅里叶分解时的基频 
int count=0;//统计输入个数 
//以上为声明 
int main()
{
	char t;//用于检测字符是否数字,实现动态输入 
	int i=0;//扫描计数偏移量
	int Nc;//截止谐波次数 
	double *AP=NULL;//用于存放幅值数组的指针 
	//以上为定义变量部分 
	printf("***对用户定义的方波进行傅里叶级数展开***\n请输入方波的周期: ");
	scanf("%lf",&period);
	fflush(stdin);
	printf("请输入方波的在(-T/2,T/2)周期改变电平的时间时刻(不含±T/2的时刻,用空格分隔):\n");
	while((t=getchar())!='\n')
	{
		if(isdigit(t)||t=='-')//浮点数都是以负号或者数字开头的 
		{
			ungetc(t,stdin);
			scanf("%lf",time+i);//扫描的浮点数一次存入 
			count++;//统计输入时间节点的个数 
			i++; 
		}
	 } 
	 *(time+i+1)=period/2;
	printf("请输入方波的在上述改变时间时刻对应的电平值\n【说明】第一个电平对应(-T/2,t0),最后一个电平对应(tn,T/2),用空格分隔:\n");
	fflush(stdin);//循环结束,刷新标准输入口 
	i=0;//偏移量清零 
	while((t=getchar())!='\n')
	{
		if(isdigit(t)||t=='-')//浮点数都是以负号或者数字开头的 
		{
			ungetc(t,stdin);
			scanf("%lf",level+i);//扫描的浮点数一次存入 
			i++;
		}
	 } 
	fflush(stdin);//循环结束,刷新标准输入口  
	printf("请输入傅里叶分解的基频: ");
	scanf("%d",&fund_f);
	printf("请输入分析的谐波最高次数: ");
	scanf("%d",&Nc);
	AP=(double *)calloc(Nc,sizeof(double));
	if(AP==NULL)
	{
		printf("\n\r意外错误:内存分配失败!\n");
		return 1;
	}
	printf("\n\r动态内存分配成功!\n");
	 for(i=0;i<=Nc;i++)
	 {
	 	AP[i]=amplify(square_wave,i);
	 	printf("\r正在计算中...%lf%%",100*(float)i/Nc);	//双线性积分方法计算较慢,这里可以动态显示计算进度
	 }
	 printf("\r|谐波次数:\t振幅\n");
	 for(i=0;i<=Nc;i++)
	 {
	 	printf("|%d:\t%8.5lf",i,AP[i]);
	 	if((i+1)%5==0)printf("\n");
	 }
	 printf("\r\n|N次谐波含有率如下:\n");	//n次谐波含有率
	 for(i=0;i<=Nc;i++)
	 {
	 	printf("|%d:\t%7.3lf%%",i,100*AP[i]/AP[1]);
	 	if((i+1)%5==0)printf("\n");
	 }
	 printf("\n\rRMS=%7.4lf,Fundamental=%7.4lf",RMS(square_wave),AP[1]);	//打印有效值和基波分量
	 system("pause");	//保留窗口,在单独运行exe的时候不加这一句会闪退
	return 0;
} 
//根据电平数组和时间间隔数组查找对应时间的方波的电平 
double square_wave(double x)
{
	int i;
	for(i=0;i<count;i++)
	{
		if(x<*(time+i))return *(level+i);
	}
	return *(level+count);//如果均不是,返回level数组的最后一个值,即[tn,T/2]的值 
} 
double amplify(double (*function)(double x),int n)
{
	double sin_integral=0,cos_integral=0;//积分值
	double x0,x1;//双线性积分需要两个变量迭代计算
	for(x1=-period/2;x1<period/2;x0=x1,x1+=1e-5)
	{
		sin_integral+=0.5*1e-5*((*function)(x1)*sin(n*2*pi*fund_f*x1/period)+(*function)(x0)*sin(n*2*pi*fund_f*x0/period));
		cos_integral+=0.5*1e-5*((*function)(x1)*cos(n*2*pi*fund_f*x1/period)+(*function)(x0)*cos(n*2*pi*fund_f*x0/period));
	 } 
	 return sqrt(pow(sin_integral,2)+pow(cos_integral,2))/period;
}
double RMS(double (*function)(double x))	//计算方波有效值
{
	double integral=0;
	double x0,x1;//采用双线性积分
	for(x1=-period/2;x1<period/2;x0=x1,x1+=1e-5)
	{
		integral+=0.5*1e-5*(pow((*function)(x1),2)+pow((*function)(x0),2));		
	}
	return sqrt(integral/period);	
} 

分析三相全桥变压器二次侧电流波形的谐波如上图,最高谐波设定为100次

猜你喜欢

转载自blog.csdn.net/weixin_44044411/article/details/85198002