view Plot.c @ 183:791ca26fee6a

Rewrite data writing to file Fmt() uses by default truncation to conver double arguments to their text representation. Rounding must be used. Rewrite using standard C functions to get rid of this problem (and probably make it more efficient). Extend to handle arbitrary number of channels and to report errors on opening the data files.
author Daniele Nicolodi <daniele.nicolodi@obspm.fr>
date Fri, 21 Feb 2014 18:42:30 +0100
parents be87c8e78266
children a3494d2806ee
line wrap: on
line source

#include <ansi_c.h>
#include <userint.h>

#include "utils.h"
#include "FXPlot.h"
#include "Plot.h"

void Plot_InitPanel(Plot_Data *Instance, const char *title, double ymin, double ymax, int parent, int control)
{
	if ((Instance->PlotPanel = LoadPanel (0, "FXPlot.uir", PLOTPANEL)) < 0)
		return;
	
	SetPanelAttribute(Instance->PlotPanel, ATTR_TITLE, title);  
	SetPanelAttribute(Instance->PlotPanel, ATTR_CALLBACK_DATA, (void *)Instance);
	Instance->active = TRUE;
	Instance->parent = parent;
	Instance->control = control;
	Instance->IndexPoint = 0;
	Instance->Mean = 0;
	Instance->Slope = 0;
	Instance->ADev = 0;
	Instance->Frequencies = calloc(MAXPOINTSNUMBER, sizeof(double));
	DisplayPanel(Instance->PlotPanel);
	
	SetCtrlVal(Instance->PlotPanel, PLOTPANEL_MIN, ymin);
	SetCtrlVal(Instance->PlotPanel, PLOTPANEL_MAX, ymax);
	
	if ((ymin != 0.0) && (ymax != 0.0)) {
		/* manual scaling */
		SetCtrlVal(Instance->PlotPanel, PLOTPANEL_MIN, ymin);
		SetCtrlVal(Instance->PlotPanel, PLOTPANEL_MAX, ymax);
		SetAxisScalingMode(Instance->PlotPanel, PLOTPANEL_FREQPLOT, VAL_LEFT_YAXIS, VAL_MANUAL, ymin, ymax);
	} else {
		/* auto scaling */
		SetCtrlVal(Instance->PlotPanel, PLOTPANEL_CHECKBOX_AUTOSCALE, TRUE);
		SetAxisScalingMode(Instance->PlotPanel, PLOTPANEL_FREQPLOT, VAL_LEFT_YAXIS, VAL_AUTOSCALE, 0, 0);
	}
}


void Plot_ClosePanel(Plot_Data * Instance)
{
	Instance->active = FALSE;
	free(Instance->Frequencies);
	SetCtrlVal(Instance->parent, Instance->control, FALSE);
	DiscardPanel(Instance->PlotPanel); 
}


void Plot_AddFrequency(Plot_Data * Instance, double Freq)
{
	double Drift = 0;
	int DeDrift;
	int N = 0;

	double Mean  = Instance->Mean;
	double Slope = Instance->Slope;
	double ADev  = Instance->ADev; 
	
	/* Correct Freq with drift (feed forward) if dedrift is on */
	GetCtrlVal(Instance->PlotPanel, PLOTPANEL_CHECKBOX_DEDRIFT, &DeDrift);
	if (DeDrift) {
		GetCtrlVal(Instance->PlotPanel, PLOTPANEL_DEDRIFT, &Drift);
		Freq -= ((double) Instance->IndexPoint)*Drift;
	}
	
	/* Add Freq to graph plot */
	Instance->Frequencies[Instance->IndexPoint++] = Freq;
	N = Instance->IndexPoint;
	
	if (N > 1) {
		/* adev and slope computation need at least 2 data points */
		Instance->Slope = (Slope*(N-2) + 6*(Freq-Mean)/N)/(N+1);
		SetCtrlVal(Instance->PlotPanel, PLOTPANEL_SLOPE, Instance->Slope);
		Instance->ADev = sqrt( ( ADev*ADev*(N-2) + 0.5*pow(Freq-Instance->Frequencies[N-2],2) ) / (N-1));
		SetCtrlVal(Instance->PlotPanel, PLOTPANEL_ADEV, Instance->ADev);
	}
	Instance->Mean = (Mean*(N-1)+Freq)/N;
	SetCtrlVal(Instance->PlotPanel, PLOTPANEL_MEAN, Instance->Mean);
	
	/* if too many points recorded restart */
	if (N > MAXPOINTSNUMBER - 2) {
		Instance->IndexPoint = 0;
		Instance->Mean = 0;
		Instance->Slope = 0;
		Instance->ADev = 0;
		SetCtrlVal(Instance->PlotPanel,PLOTPANEL_MEAN, 0.0);
		SetCtrlVal(Instance->PlotPanel,PLOTPANEL_SLOPE, 0.0);
		SetCtrlVal(Instance->PlotPanel,PLOTPANEL_ADEV, 0.0);
	}
	
	DeleteGraphPlot(Instance->PlotPanel, PLOTPANEL_FREQPLOT, -1, VAL_IMMEDIATE_DRAW);
	PlotY(Instance->PlotPanel, PLOTPANEL_FREQPLOT, Instance->Frequencies, Instance->IndexPoint,
		VAL_DOUBLE, VAL_THIN_LINE, VAL_EMPTY_SQUARE, VAL_SOLID, 1, VAL_BLUE);
	
	int autoscale;
	GetCtrlVal(Instance->PlotPanel, PLOTPANEL_CHECKBOX_AUTOSCALE, &autoscale);
	if (autoscale) {
		/* update plot limits */
		double ymin, ymax;
		GetAxisScalingMode(Instance->PlotPanel, PLOTPANEL_FREQPLOT,VAL_LEFT_YAXIS, NULL, &ymin, &ymax);
		SetCtrlVal(Instance->PlotPanel, PLOTPANEL_MIN, ymin);
		SetCtrlVal(Instance->PlotPanel, PLOTPANEL_MAX, ymax);
		/* adjust control limits */
		SetCtrlAttribute(Instance->PlotPanel, PLOTPANEL_MIN, ATTR_MAX_VALUE, ymax);
		SetCtrlAttribute(Instance->PlotPanel, PLOTPANEL_MAX, ATTR_MIN_VALUE, ymin);
	}
}


/* callbacks */

int CVICALLBACK CB_PlotEvent(int panel, int event,
		void *callbackData, int eventData1, int eventData2)
{
	switch (event)
	{
		case EVENT_CLOSE:
			Plot_Data *data;
			GetPanelAttribute (panel, ATTR_CALLBACK_DATA, &data);
			Plot_ClosePanel(data);
			break;
	
		case EVENT_KEYPRESS:
			int keycode = GetKeyPressEventVirtualKey(eventData2);
			int index;
			double step;
			switch (keycode)
			{
				case 2304: /* right arrow */
					GetCtrlIndex(panel, PLOTPANEL_SCALINGSTEP, &index);
					if (index < 10) {
						SetCtrlIndex(panel, PLOTPANEL_SCALINGSTEP, ++index);
						GetCtrlVal(panel, PLOTPANEL_SCALINGSTEP, &step);
						SetCtrlAttribute(panel, PLOTPANEL_MIN, ATTR_INCR_VALUE, step);
						SetCtrlAttribute(panel, PLOTPANEL_MAX, ATTR_INCR_VALUE, step);
					}
					break;
				case 2048: /* left arrow */
					GetCtrlIndex(panel, PLOTPANEL_SCALINGSTEP, &index);
					if (index > 0) {
						SetCtrlIndex(panel, PLOTPANEL_SCALINGSTEP, --index);
						GetCtrlVal(panel, PLOTPANEL_SCALINGSTEP, &step);
						SetCtrlAttribute(panel, PLOTPANEL_MIN, ATTR_INCR_VALUE, step);
						SetCtrlAttribute(panel, PLOTPANEL_MAX, ATTR_INCR_VALUE, step);
					}
					break;
			}
			break;
	}
	return 0;
}


int CVICALLBACK Plot_CB_ChangeYLim (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	double ymin, ymax;
	
	switch (event)
	{
		case EVENT_COMMIT:
			GetCtrlVal(panel, PLOTPANEL_MIN, &ymin);
			GetCtrlVal(panel, PLOTPANEL_MAX, &ymax);
			/* adjust control limits */
			SetCtrlAttribute(panel, PLOTPANEL_MIN, ATTR_MAX_VALUE, ymax);
			SetCtrlAttribute(panel, PLOTPANEL_MAX, ATTR_MIN_VALUE, ymin);
			/* disable autoscaling */
			SetCtrlVal(panel, PLOTPANEL_CHECKBOX_AUTOSCALE, FALSE);
			SetAxisScalingMode(panel, PLOTPANEL_FREQPLOT, VAL_LEFT_YAXIS, VAL_MANUAL, ymin, ymax);
			break;
	}
	return 0;
}


int CVICALLBACK Plot_CB_ChangeAutoScale (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	int autoscale = FALSE;
	double ymin, ymax;
	
	switch (event)
	{
		case EVENT_COMMIT:
			GetCtrlVal(panel, PLOTPANEL_CHECKBOX_AUTOSCALE, &autoscale);
			if (autoscale) {
				SetAxisScalingMode(panel, PLOTPANEL_FREQPLOT, VAL_LEFT_YAXIS, VAL_AUTOSCALE, 0, 0);
				GetAxisScalingMode(panel, PLOTPANEL_FREQPLOT,VAL_LEFT_YAXIS, NULL, &ymin, &ymax);
				SetCtrlVal(panel, PLOTPANEL_MIN, ymin);
				SetCtrlVal(panel, PLOTPANEL_MAX, ymax);
				/* adjust control limits */
				SetCtrlAttribute(panel, PLOTPANEL_MIN, ATTR_MAX_VALUE, ymax);
				SetCtrlAttribute(panel, PLOTPANEL_MAX, ATTR_MIN_VALUE, ymin);
			} else {
				GetCtrlVal(panel, PLOTPANEL_MIN, &ymin);
				GetCtrlVal(panel, PLOTPANEL_MAX, &ymax);
				SetAxisScalingMode(panel, PLOTPANEL_FREQPLOT, VAL_LEFT_YAXIS, VAL_MANUAL, ymin, ymax);
			}
			break;
	}
	return 0;
} 


int  CVICALLBACK Plot_CB_ChangeScalingStep(int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	double step;

	switch (event)
	{
		case EVENT_COMMIT:
			GetCtrlVal(panel, PLOTPANEL_SCALINGSTEP, &step);
			SetCtrlAttribute(panel, PLOTPANEL_MIN, ATTR_INCR_VALUE, step);
			SetCtrlAttribute(panel, PLOTPANEL_MAX, ATTR_INCR_VALUE, step);
			break;
	}
	return 0;
}


int CVICALLBACK Plot_CB_Reset (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	Plot_Data *data;
	switch (event)
	{
		case EVENT_COMMIT:
			GetPanelAttribute (panel, ATTR_CALLBACK_DATA, &data);
			data->IndexPoint = 0;
			data->Mean = 0;
			data->Slope = 0;
			data->ADev = 0;
			break;
	}
	return 0;
}


int CVICALLBACK Plot_CB_GetDrift (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	Plot_Data *data;
	int dedrift;
	double drift;
	
	switch (event)
	{
		case EVENT_COMMIT:
			GetPanelAttribute(panel, ATTR_CALLBACK_DATA, &data);  
			GetCtrlVal(panel, PLOTPANEL_CHECKBOX_DEDRIFT, &dedrift);
			if (dedrift) {
				GetCtrlVal(panel, PLOTPANEL_DEDRIFT, &drift);
				drift += data->Slope;
				SetCtrlVal(panel, PLOTPANEL_DEDRIFT, drift);
				data->IndexPoint = 0;
				data->Mean = 0;
				data->Slope = 0;
				data->ADev = 0;
			} else
				SetCtrlVal(panel,PLOTPANEL_DEDRIFT, data->Slope);
			break;
	}
	return 0;
}


int CVICALLBACK Plot_CB_ChangeDrift (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	int dedrift;
	Plot_Data *data;
	
	switch (event)
	{
		case EVENT_COMMIT:
			GetCtrlVal(panel, PLOTPANEL_CHECKBOX_DEDRIFT, &dedrift);
			if (dedrift) {
				GetPanelAttribute (panel, ATTR_CALLBACK_DATA, &data);
				data->IndexPoint = 0;
				data->Mean = 0;
				data->Slope = 0;
				data->ADev = 0;
			}
			break;
	}
	return 0;
}