⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calculate_fs.c

📁 最大似然估计算法
💻 C
字号:
#include "timeseries.h"double calculate_fs(double *time, int n_data, int *index, int *f1_count) {	int i, j, k, n;	int error, count;	int year1, year2, leap1, leap2;	int n_attempt = 9;	int n_sample  = 7;	int *bad, *idt;	double s, dp, min_dt, max_dt, scale, t, ds;	double mean, median, n1, n2, fs;	double x1, x2, x3;	double *dt, *dt2, *tmp;	double *max_ds, *break_point;	double sample[] = {0.041666666, 1.0, 2.0, 7.0, 14.0, 30.4375, 365.25};	double daily[]  = {365.24219, 0.0, 0.0, 0.0, 365.0, 365.25, 365.24219, 365.2564, 365.259635};	dt     = (double *) calloc((size_t) (n_data-1),  sizeof(double));	dt2    = (double *) calloc((size_t) (n_data-1),  sizeof(double));	max_ds = (double *) calloc((size_t) (n_attempt), sizeof(double));	bad    = (int *)    calloc((size_t) (n_data-1),  sizeof(int));	idt    = (int *)    calloc((size_t) (n_data-1),  sizeof(int));	error = 0;	for (j = 0; j < n_data-1; j++) {		dt[j] = time[j+1] - time[j];		year1 = (int)floor(time[j]);		leap1 = year1%4 == 0 && year1%100 != 0 || year1%400 == 0;		n1 = 365.0 + (double)leap1;		year2 = (int)floor(time[j+1]);		leap2 = year2%4 == 0 && year2%100 != 0 || year2%400 == 0;		n2 = 365.0 + (double)leap2;		dt2[j] = 0.5 * ( (n1+n2) / n2 / n1);		if (dt[j] <= 0.0) bad[error++] = j;		if (j == 0) min_dt = dt[j];		else min_dt = dt[j] < min_dt ? dt[j] : min_dt; 	}	if (error) {		fprintf(stderr, " calculate_fs : file is not in ascending");		fprintf(stderr, " time order or has duplicated points\n");		for (j = 0; j < error; j++) {		       	fprintf(stderr, "              : t[%d] - t[%d] = %f\n", bad[j]+1, bad[j], dt[bad[j]]);		}		exit(EXIT_FAILURE);	}	free(bad);	/******************************************************************/	/* First find out the number of decimal places in the time stamps */	/******************************************************************/	dp = 0.0;	do {		dp += 1.0;		s = 0.0;		scale = pow(10.0,dp);		for (j = 0; j < n_data; j++) {			t = rint(time[j] * scale) / scale;			s += ((t-time[j])*(t-time[j]));		}		s = sqrt(s / (double) n_data);		} while (s > 1e-13);	/************************************************************************/	/* The 1e-13 was arrived at partly from trial and error and it is       */	/* related to the numerical precision of the computer, meaning it       */	/* can only really distinguish up to 12 decimal places                  */	/* For a specified decimal place, the differences between the full      */	/* value and the "clipped" value should form a uniform distribution     */	/* between -0.5 / 10^dp and 0.5 / 10^dp. Therefore the square root of   */	/* the sum of the differences squared should have a mean equal to       */	/* (N / 12 / 10^(2*dp))^0.5. The difficultly is for small time series   */	/* say less the 250 the error on the mean is quite large and could      */	/* possibly overlap with the dp level below. A better method will be    */	/* developed later, its not really critical at this stage, for well     */	/* defined time series.                                                 */	/************************************************************************/	fprintf(stderr, "min_dt = %f dp = %f\n", min_dt, dp);	/*****************************************************************************/	/* Try to find out how evenly spaced the file is, and the sampling frequency */	/*****************************************************************************/	tmp = (double *) calloc((size_t)(n_data-1), sizeof(double));	count = 0;	for (j = 0; j < n_data-1; j++) {		if (lrint( dt[j] / min_dt) == 1) {			if (count == 0) max_dt = dt[j];			else max_dt = dt[j] > max_dt ? dt[j] : max_dt;			tmp[count] = dt[j];		       	count++;		}	}	qsort((char *)tmp, (size_t)count, sizeof(double), comp_double_asc);	if ((int)fmod(count,2) == 1) {		median = tmp[(count+1)/2 - 1];	} else {                median = ( tmp[count/2-1] + tmp[count/2] ) / 2.0;	}	mean = 0.0;	for (j = 0; j < count; j++) mean += tmp[j];	mean /= (double) count;	free(tmp);	fprintf(stderr, "median = %f mean = %f\n", median, mean);	/***************************************/	/* Work out what sampling it really is */	/***************************************/	break_point = (double *) calloc((size_t)n_sample+1, sizeof(double) );	break_point[0] = 0;	scale = pow(10.0,dp);	for (j = 0; j < n_sample-1; j++) {		x1 = rint(sample[j] / 365.25 * scale) / scale; 		x2 = rint(sample[j+1] / 365.25 * scale) / scale;		x3 = (x2 - x1) * scale / 2.0;		break_point[j+1] = x1 + x3 / scale;	}	break_point[n_sample] = 10.0 * x2;	for (j = 0; j < n_sample; j++) fprintf(stdout, "break_point %f\n", break_point[j]);	i = -1;	n = 0;	for (j = 0; j < n_sample; j++) {		if (median >= break_point[j] && median < break_point[j+1]) {			fprintf(stderr, "sample = %f\n", sample[j]);		       	i = j;			n++;		}	}	if (i < 0 || n > 1) {		fprintf(stderr, " calculate_fs : numerical precision (%f decimal", dp);		fprintf(stderr, " places) of time samples too small to calculate frequency\n");		exit(EXIT_FAILURE);	}	for (j = 4; j < n_attempt; j++) daily[j]  /= sample[i];	daily[1] = 1.0 / min_dt;	daily[2] = 1.0 / median;	daily[3] = 1.0 / mean;	for (j = 0; j < n_attempt; j++) fprintf(stderr, "%f\n", daily[j]);	for (j = 0; j < n_data-1; j++) {		ds = rint( dt[j] / dt2[j]) - (dt[j] / dt2[j]);		idt[j] = lrint(dt[j] / dt2[j]); 		fprintf(stderr, "%f %f %f %d\n", dt[j], dt2[j], ds, idt[j]);		if (j == 0) max_ds[0] = fabs(ds); 		else max_ds[0] = fabs(ds) > max_ds[0] ? fabs(ds) : max_ds[0];	}	fprintf(stderr, "max_ds[0] = %f\n", max_ds[0]);	for (k = 1; k < n_attempt; k++) {		for (j = 0; j < n_data-1; j++) {			ds = rint( dt[j] * daily[k]) - (dt[j] * daily[k]);			if (j == 0) max_ds[k] = fabs(ds); 			else max_ds[k] = fabs(ds) > max_ds[k] ? fabs(ds) : max_ds[k];		}		fprintf(stderr, "max_ds[%d] = %f\n", k, max_ds[k]);	}	for (j = 0; j < n_attempt; j++) fprintf(stderr, "%f\n", max_ds[j] / daily[j]);	i = 0;	for (k = 1; k < n_attempt; k++) i = max_ds[k] < max_ds[i] ? k : i;	fprintf(stderr, "Choice %d %f\n", i, daily[i]);	count = 0;	index[0] = 0;	for (j = 0; j < n_data-1; j++) {	       	if (i > 0) idt[j] = lrint( dt[j] * daily[i]);		if (idt[j] == 1) count++;		index[j+1] = index[j] + idt[j];	}	fs = daily[i] / 365.24219 / 24.0 / 3600; 		(*f1_count) = count;	free(dt);	free(dt2);	free(max_ds);	free(idt);	free(break_point);	return(fs);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -