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);
}
Example #3
0
void HPSidebandLockDevice::handleMeasuredSpectrumSecondToFirst(const STI::Types::TDataMixedSeq& rawSidebandData)
{
	MathematicaPeakFinder peakFinder(minPointsPerPeak);
	
	if(!peakFinder.findFirstAndSecondOrderSidebandPeaks(
		rawSidebandData, 
		calibrationResults, 
		firstSidebandSpacing_ms * 0.001, 
		secondSidebandSpacing_ms * 0.001, 
		minSpectrumX_ms * 0.001, 
		peakTargetRange_ms * 0.001,
		targetSpectrumPeaks, carrierOffset_ms*0.001))
	{
		return;	//error
	}
	if(!peakFinder.calculateFeedbackSignalsFromFirstAndSecondSideband(targetSpectrumPeaks, feedbackSignals)) {
		return;	//error
	}

	MixedData calPeaks;
	calibrationResults->getPeakValues(calPeaks);
	//targetSpectrumPeaks format:	{{L1,R1},{L2,R2}}

	double new1stSidebandSplitting_ms = fabs(
		1000 *
		(targetSpectrumPeaks.getVector().at(1).getVector().at(0).getDouble() - 
		calPeaks.getVector().at(1).getVector().at(0).getDouble())
		);
	

	double new1stSidebandSplitting_msA = fabs(new1stSidebandSplitting_ms - carrierOffset_ms/2);
	double new1stSidebandSplitting_msB = fabs(new1stSidebandSplitting_ms + carrierOffset_ms/2);

	double new2ndSidebandSplitting_ms = fabs(
		1000 *
		(targetSpectrumPeaks.getVector().at(3).getVector().at(0).getDouble() - 
		calPeaks.getVector().at(1).getVector().at(0).getDouble())
		);

	double new2ndSidebandSplitting_msA = fabs(new2ndSidebandSplitting_ms - carrierOffset_ms/2);
	double new2ndSidebandSplitting_msB = fabs(new2ndSidebandSplitting_ms + carrierOffset_ms/2);

	double fractionalChangeSplitting1stA = fabs( 1 - (new1stSidebandSplitting_msA / firstSidebandSpacing_ms) );
	double fractionalChangeSplitting1stB = fabs( 1 - (new1stSidebandSplitting_msB / firstSidebandSpacing_ms) );
	double fractionalChangeSplitting2ndA = fabs( 1 - (new2ndSidebandSplitting_msA / secondSidebandSpacing_ms) );
	double fractionalChangeSplitting2ndB = fabs( 1 - (new2ndSidebandSplitting_msB / secondSidebandSpacing_ms) );

	//This is a check to varify that the correct scope trace was analyzed. In case the scope trace is
	//incorrect, the new measured sideband splitting is likely very different. We reject the feedback 
	//attempt in this case.
		

	double fractionalChangeSplitting1st, fractionalChangeSplitting2nd;
	double new1stSidebandSplittingCarrierOffset_ms, new2ndSidebandSplittingCarrierOffset_ms;

	if ((fractionalChangeSplitting1stA + fractionalChangeSplitting2ndA) < (fractionalChangeSplitting1stB + fractionalChangeSplitting2ndB))
	{
		fractionalChangeSplitting1st = fractionalChangeSplitting1stA;
		fractionalChangeSplitting2nd = fractionalChangeSplitting2ndA;

		new1stSidebandSplittingCarrierOffset_ms = new1stSidebandSplitting_msA;
		new2ndSidebandSplittingCarrierOffset_ms = new2ndSidebandSplitting_msA;
	}
	else
	{
		fractionalChangeSplitting1st = fractionalChangeSplitting1stB;
		fractionalChangeSplitting2nd = fractionalChangeSplitting2ndB;

		new1stSidebandSplittingCarrierOffset_ms = new1stSidebandSplitting_msB;
		new2ndSidebandSplittingCarrierOffset_ms = new2ndSidebandSplitting_msB;
	}

	if((fractionalChangeSplitting1st < maximumFractionalChangeSplitting) && 
		(fractionalChangeSplitting2nd < maximumFractionalChangeSplitting)) {
		//New sideband splitting is within acceptable range. Save it and apply feedback.
		firstSidebandSpacing_ms = new1stSidebandSplittingCarrierOffset_ms;		//Update sideband splitting
		secondSidebandSpacing_ms = new2ndSidebandSplittingCarrierOffset_ms;		//Update sideband splitting


		double calPeakMean = (calPeaks.getVector().at(0).getVector().at(0).getDouble() + calPeaks.getVector().at(1).getVector().at(0).getDouble())/2;
		double firstSidebandMean = (targetSpectrumPeaks.getVector().at(0).getVector().at(0).getDouble() + targetSpectrumPeaks.getVector().at(1).getVector().at(0).getDouble())/2;

		cout << "Old carrier-calibration offset: " << carrierOffset_ms << endl;
		carrierOffset_ms = 1000*(firstSidebandMean - calPeakMean);
		cout << "New carrier-calibration offset: " << carrierOffset_ms << endl;

		//Feedback on sideband asymmetry
		asymmetryLockLoop(feedbackSignals.getVector().at(0).getDouble());

		//Feedback on sideband/carrier ratio
		peakRatioLockLoop(feedbackSignals.getVector().at(1).getDouble());

		//Do this once after calling both loops
		refreshDeviceAttributes();	//update the attribute text file and the client
	} else {
		cout << "Feedback error: Attempted change to one of the sideband splittings is too large:" << endl
			<< "   1st order: Old splitting: " << firstSidebandSpacing_ms << " ms, new splitting: " 
			<< new1stSidebandSplittingCarrierOffset_ms << " ms, fractional change: " << fractionalChangeSplitting1st << endl
			<< "   2nd order: Old splitting: " << secondSidebandSpacing_ms << " ms, new splitting: " 
			<< new2ndSidebandSplittingCarrierOffset_ms << " ms, fractional change: " << fractionalChangeSplitting2nd << endl;
	}

}