void NovatechChannelPair::defineAttributes() 
{
	//addAttribute("Center Frequency (MHz)", centerFreq);
	//addAttribute("Delta Frequency (MHz)", deltaFreq);

	

	addAttribute("Frequency Ramp Rate (MHz/ms)", freqRampRate);
	addAttribute("Min Ramp Resolution (MHz)", maxResolution);
	addAttribute("Low Freq Channel", valueToString(lowFreqChannel, ""), "0, 1, 2, 3");
	addAttribute("High Freq Channel", valueToString(highFreqChannel, ""), "0, 1, 2, 3");

	MixedValue valueIn("");
	MixedData	dataOut;
	double lowFreq = 100, highFreq = 100;

	if (partnerDevice("Novatech").read(lowFreqChannel + 10, valueIn, dataOut))
	{
		lowFreq = dataOut.getVector().at(0).getDouble();
	}
	else
		std::cerr << "Error reading Novatech" << std::endl;

	dataOut.clear();
	if (partnerDevice("Novatech").read(highFreqChannel + 10, valueIn, dataOut))
	{
		highFreq = dataOut.getVector().at(0).getDouble();
	}
	else
		std::cerr << "Error reading Novatech" << std::endl;

	centerFreq = (lowFreq + highFreq)/2;
	deltaFreq = highFreq - lowFreq;
	
}
bool MathematicaPeakFinder::calculateFeedbackSignalsFromFirstAndSecondSideband(const MixedData& peaks, MixedData& feedback)
{
	WolframLibraryData libData = 0;
	WolframRTL_initialize(WolframLibraryVersion);
	libData = WolframLibraryData_new(WolframLibraryVersion);

	//Setup arguments

	//Initialize peak tensor
	MTensor peakTensor;
	int err;
	mint type = MType_Real;
	mint rank = 2;
	mint dims[2];
	dims[0] = 4;
	dims[1] = 2;
	err = libData->MTensor_new(type, rank, dims, &peakTensor);

	if(err != 0)
		return false;

	mint peakPos[2];

	for(int i = 1; i <= dims[0]; i++) {
		peakPos[0] = i;
		for(int j = 1; j <= dims[1]; j++) {
			peakPos[1] = j;
			err = libData->MTensor_setReal(peakTensor, peakPos, 
				peaks.getVector().at(i-1).getVector().at(j-1).getDouble());
		}
	}

	if(err != 0)
		return false;

	//Initialize result tensor
	MTensor feedbackResults;
	type = MType_Real;
	rank = 1;
	mint dimsRes[1];
	dimsRes[0] = 2;
	err = libData->MTensor_new(type, rank, dimsRes, &feedbackResults);

	if(err != 0)
		return false;

	Initialize_getFeedbackSignalsFromFirstAndSecondSidebands(libData);			//Begin call to Mathematica code

	err = getFeedbackSignalsFromFirstAndSecondSidebands(libData, peakTensor, &feedbackResults);

	Uninitialize_getFeedbackSignalsFromFirstAndSecondSidebands(libData);		//End call to Mathematica code

		
	if( err == 0) {
		//Copy results of the feedback function

		double value = 0;
		mint pos[1];
		feedback.clear();
		
		for(int j = 1; j <= 2; j++) {
			pos[0] = j;
			err = libData->MTensor_getReal(feedbackResults, pos, &value);
			feedback.addValue(value);
		}
	}
	
	cout << "Feedback results:" << endl;
	cout << feedback.print() << endl;

	libData->MTensor_free(peakTensor);
	libData->MTensor_free(feedbackResults);

	return (err == 0);
}
bool MathematicaPeakFinder::findFirstAndSecondOrderSidebandPeaks(const STI::Types::TDataMixedSeq& rawSidebandData, 
														const CalibrationResults_ptr& calibration, 
														double firstOrderSidebandSpacing, 
														double secondOrderSidebandSpacing, 
														double minimumX,
														double targetRange,
														MixedData& peaks,
														double carrierOffset)
{
	WolframLibraryData libData = 0;
	WolframRTL_initialize(WolframLibraryVersion);
	libData = WolframLibraryData_new(WolframLibraryVersion);

	//Setup arguments

	MTensor formatedSidebandData;		//List of {x,y} pairs, with gaps when y is below threshold

	if(!convertRawScopeData(libData, rawSidebandData, formatedSidebandData)) {
		return false;
	}

	//Initialize calibration tensor
	MTensor calTensor;
	int err;
	mint type = MType_Real;
	mint rank = 2;
	mint dims[2];
	dims[0] = 2;
	dims[1] = 2;
	err = libData->MTensor_new(type, rank, dims, &calTensor);

	if(err != 0)
		return false;

	if(!calibration->getPeaks(libData, &calTensor))
		return false;

	//Initialize results tensor
	MTensor peakResults;
	type = MType_Real;
	rank = 2;
	dims[2];
	dims[0] = 4;	//First and second order sidebands: { {+1, -1}, {+2, -2} }
	dims[1] = 2;	//{time, peak height}
	err = libData->MTensor_new(type, rank, dims, &peakResults);

	mreal firstOrderSidebandSpacingArg = firstOrderSidebandSpacing;
	mreal secondOrderSidebandSpacingArg = secondOrderSidebandSpacing;
	mreal minX = minimumX;
	mreal targetRangeArg = targetRange;
	mreal carrierOffsetArg = carrierOffset;

	if(err == 0) {
		Initialize_findFirstAndSecondOrderSidebands(libData);		//Begin call to Mathematica code

		err = findFirstAndSecondOrderSidebands(libData, formatedSidebandData, calTensor, firstOrderSidebandSpacingArg, secondOrderSidebandSpacingArg, minX, targetRangeArg, carrierOffsetArg, &peakResults);

		Uninitialize_findFirstAndSecondOrderSidebands(libData);		//End call to Mathematica code
	}
	
	if( err == 0) {
		//Copy results of peak search

		double value = 0;
		mint pos[2];
		peaks.clear();
		MixedData peak;
		for(int i = 1; i <= 4; i++) {
			pos[0] = i;
			peak.clear();
			for(int j = 1; j <= 2; j++) {
				pos[1] = j;
				err = libData->MTensor_getReal(peakResults, pos, &value);
				peak.addValue(value);
			}
			peaks.addValue(peak);
		}
	}

	cout << "Peak find results:" << endl;
	cout << peaks.print() << endl;
	

	libData->MTensor_free(formatedSidebandData);
	libData->MTensor_free(calTensor);
	libData->MTensor_free(peakResults);

	return (err == 0);

}