コード例 #1
0
ファイル: hp83711bDevice.cpp プロジェクト: jasonhogan/sti
bool hp83711bDevice::readChannel(unsigned short channel, const MixedValue& valueIn, MixedData& dataOut)
{
	//
	
	bool measureSuccess;
	std::string measurementResult;

	if(channel == 0)
	{
		measurementResult = queryDevice("FREQ:CW?");
		std::cerr << measurementResult << std::endl;
		//measurementResult.erase(0,2);
		measureSuccess = stringToValue(measurementResult, frequency, std::ios::dec, 10);
		//wavelength = wavelength * 1000000000; // multiply by 10^9
		std::cerr.precision(10);
		std::cerr << "The output frequency is:" << frequency << " Hz" << std::endl;
		dataOut.setValue(frequency);
		return measureSuccess;
	}
	else if(channel == 1)
	{
		measurementResult = queryDevice("POW:LEV?");
		std::cerr << measurementResult << std::endl;
		//measurementResult.erase(0,2);
		measureSuccess = stringToValue(measurementResult, power);
		std::cerr << "The output power is: " << power << "dBm" << std::endl;
		dataOut.setValue(power);
		return measureSuccess;
	}

	std::cerr << "Expecting either Channel 0 or 1" << std::endl;
	return false;
}
コード例 #2
0
bool PhaseMatrixDevice::readChannel(unsigned short channel, const MixedValue& valueIn, MixedData& dataOut)
{
	bool success = false;

	if(channel == 2) {	//Read Frequency
		std::stringstream command;
		double frequency;

		success = measureFrequency(frequency);

		if(success) {
			dataOut.setValue(frequency / 1000);		//Phase Matrix returns milli Hz; return value in Hz
			currentFreqHz = frequency / 1000;
		}
	}

	if(channel == 3) {	//Read Power
		double power;

		success = measurePower(power);

		if(success) {
			dataOut.setValue(power);
			currentPower = power;
		}
	}

	return success;
}
コード例 #3
0
ファイル: hp83711bDevice.cpp プロジェクト: jasonhogan/sti
std::string hp83711bDevice::execute(int argc, char** argv)
{
	//command structure:  >analogIn readChannel 1
	//returns the value as a string

	if(argc < 3)
		return "Error: Invalid argument list. Expecting 'channel'.";

	int channel;
	bool channelSuccess = stringToValue(argv[2], channel);

	if(channelSuccess && channel >=0 && channel <= 1)
	{
		MixedData data;
		bool success = readChannel(channel, 0, data);

		if(success)
		{
			cerr << "Result to transfer = " << data.getDouble() << endl;
			return valueToString( data.getDouble() );
		}
		else
			return "Error: Failed when attempting to read.";
	}

	return "Error";
}
コード例 #4
0
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;
	
}
コード例 #5
0
std::string STF_AD_FAST::STF_AD_FAST_Device::execute(int argc, char **argv)
{

	//command structure:  >analogIn readChannel 1
	//returns the value as a string

	if(argc < 3)
		return "Error: Invalid argument list. Expecting 'channel'.";

	int channel;
	bool channelSuccess = stringToValue(argv[2], channel);

	if(channelSuccess && channel >= 0 && channel <= 1)
	{
		//RawEvent rawEvent(10000, channel, 0);	//time = 1, event number = 0

	//	DataMeasurement measurement(10000, channel, 0);

	//	writeChannel(rawEvent); //runs parseDeviceEvents on rawEvent and executes a short timing sequence

		MixedData data;
		bool success = read(channel, 0, data);
//		makeMeasurement( measurement );


		//DataMeasurementVector& results = getMeasurements();

//		waitForEvent(0)

//int x=0;
//while(x != 3)
//{		
//cerr << "Waiting to send..." << endl;
//cin >> x;
//}


		if(success)
		{
			cerr << "Result to transfer = " << data.getDouble() << endl;
			return valueToString( data.getDouble() );
		}
		else
			return "Error: Failed when attempting to read.";
	}

	return "Error";
}
コード例 #6
0
bool Novatech409B::readChannel(unsigned short channel, const MixedValue& valueIn, MixedData& dataOut)
{
	std::vector <std::vector<double> > freqAmpPhases;
	std::vector <double> freqAmpPhase;

	std::string state;

	if (channel > 9 && channel < 14)
	{
//		for (unsigned int i = 0; i < frequencyChannels.size(); i++)
//		{
//			freqAmpPhase.clear();

		if(refreshLocallyStoredFrequencyChannels()) {

			freqAmpPhase.push_back(frequencyChannels.at(channel - 10).frequency);
			freqAmpPhase.push_back(frequencyChannels.at(channel - 10).amplitude);
			freqAmpPhase.push_back(frequencyChannels.at(channel - 10).phase);
			freqAmpPhases.push_back(freqAmpPhase);
	
			dataOut.setValue(freqAmpPhase);
		}
		else {
			std::cerr << "Failed to read channel." << endl;
			return false;
		}
	}
	else
	{
		std::cerr << "Expecting channel 10 - 13 for a read command" << std::endl;
		return false;
	}

	return true;
}
コード例 #7
0
bool RemoteDevice::read(unsigned short channel, const MixedValue& valueIn, MixedData& dataOut)
{
	bool success = false;

	STI::Types::TDataMixed_var tData;

	try {
		success = getCommandLineRef()->readChannel(channel, valueIn.getTValMixed(), tData.out());
	}
	catch(CORBA::TRANSIENT& ex) {
		cerr << printExceptionMessage(ex, "RemoteDevice::execute(...)");
	}
	catch(CORBA::SystemException& ex) {
		cerr << printExceptionMessage(ex, "RemoteDevice::execute(...)");
	}
	catch(CORBA::Exception&) {
	}
	catch(...) {
	}

	if( success )
	{
		dataOut.setValue( tData.in() );
	}

	return success;
}
コード例 #8
0
void HPSidebandLockDevice::defineAttributes()
{

	//Contact arroyo to determine initial temperature setpoint
	//Note that defineAttributes does NOT get called until after all the partners are registered.
	//Channel 2 for Arroyos is the read on the temperature, channel 0 allows a general query to get the temperature setpoint
	MixedValue valueIn;
	valueIn.setValue("TEC:SET:T?");
	MixedData dataOut;
	bool success = partnerDevice("Arroyo").read(0, valueIn, dataOut);
	double tempSetpoint;
	if (success && STI::Utils::stringToValue(dataOut.getString(), tempSetpoint))
		temperatureSetpoint = tempSetpoint;
	else
		cout << "Could not contact Arroyo to determine current temperature setpoint" << endl;

	//Temperature parameters
	addAttribute("Crystal Temp. Setpoint (deg C)", temperatureSetpoint);
	addAttribute("Sideband Asymmetry Gain", gainSidebandAsymmetry);
	addAttribute("Maximum temperature step (deg C)", maxTemperatureStep);
	addAttribute("Enable Asymmetry Lock", (asymmetryLockEnabled ? "True" : "False"), "True, False");
	
	//RF parameters
	addAttribute("Calibration Trace RF Setpoint", rfSetpointCalibration);
	addAttribute("RF modulation setpoint", rfSetpoint);
	
	
	//"Sideband/Carrier"
	addAttribute("Peak Ratio Gain", gainPeakRatio);
	addAttribute("Enable Peak Ratio Lock", (peakRatioLockEnabled ? "True" : "False"), "True, False");
	
	addAttribute("Feedback delay (ms)", feedbackDelay_ms);

	//Peak finding algorithm attributes
	addAttribute("Calibration Trace FSR (ms)", calibrationFSR_ms);
	addAttribute("Calibration Trace Peak Height (V)", calibrationPeakHeight_V);
	addAttribute("1st Sideband to Carrier Spacing (ms)", firstSidebandSpacing_ms);
	addAttribute("2nd Sideband to Carrier Spacing (ms)", secondSidebandSpacing_ms);
	addAttribute("Peak Search Target Range (ms)", peakTargetRange_ms);
	
	addAttribute("Minimum Spectrum X Position (ms)", minSpectrumX_ms);
	addAttribute("Maximum Fractional Sideband Splitting Change", maximumFractionalChangeSplitting);
	
	addAttribute("Peak Ratio Selection", "1st sideband/carrier", "1st sideband/carrier, 2nd sidebands/1st sidebands");

	addAttribute("Carrier-Calibration Offset (ms)", carrierOffset_ms);
}
コード例 #9
0
::CORBA::Boolean CommandLine_i::readChannel(::CORBA::UShort channel, const STI::Types::TValMixed& value, STI::Types::TDataMixed_out data)
{
//	DataMeasurement measurement(100000, channel, 1);

	MixedData mixedData;

	bool success = sti_device->read(channel, MixedValue(value), mixedData);

	data = new STI::Types::TDataMixed();

	if(success)
	{
		(*data) = mixedData.getTDataMixed();
	}

	return success;
}
コード例 #10
0
ファイル: STI_Application.cpp プロジェクト: jasonhogan/sti
bool STI_Application::readChannel(unsigned short channel, const MixedValue& valueIn, MixedData& dataOut) {
	if(channel == 0) {
		dataOut.setValue(
			handleFunctionCall(
			valueIn.getVector().at(0).getString(), valueIn.getVector().at(1).getVector())
			);
		return true;
	}
	return readAppChannel(channel, valueIn, dataOut);
}
コード例 #11
0
ファイル: STI_Application.cpp プロジェクト: jasonhogan/sti
void STI_Application::loadGUI()
{
	networkFile = new NetworkFileSource(appGUIpathName);

	//Put the GUI into a file
	STI::Types::TFile file;

	file.description = CORBA::string_dup("");
	file.fileName = CORBA::string_dup(appGUIpathName.c_str());
	file.fileServerAddress = CORBA::string_dup("");
	file.fileServerDirectory = CORBA::string_dup("");
	file.networkFile = networkFile->getNetworkFileReference();

	//Put the loaded GUI into the labeled data as a File
	MixedData guiData;
	guiData.addValue(GUIjavaclasspath);
	guiData.addValue(file);
	setLabeledData("JavaGUI", guiData);
}
コード例 #12
0
void HighPowerIntensityLockDevice::HPIntensityLockEvent::collectMeasurementData()
{
	//save the current value of the VCA setpoint
	MixedData vcaData;
	vcaData.addValue(std::string("VCA Setpoint"));
	vcaData.addValue(_this->vcaSetpoint);

	//Also save the PD voltage:
	MixedData pdData;
	pdData.addValue(std::string("PD Voltage"));
	pdData.addValue(_this->photodiodeVoltage);

	MixedData feedbackLoopData;
	feedbackLoopData.addValue( vcaData );
	feedbackLoopData.addValue( pdData );

	//Save feedbackLoopData as a measurement for the HP Intensity Lock device
	eventMeasurements.at(0)->setData( feedbackLoopData );
}
コード例 #13
0
ファイル: mccUSBDAQDevice.cpp プロジェクト: jasonhogan/sti
bool MccUSBDAQDevice::readChannel(unsigned short channel, const MixedValue& valueIn, MixedData& dataOut)
{
	double result;

	if( readInputChannel(channel, result) )
	{
		dataOut.setValue( result );
		return true;
	}
	else
	{
		return false;
	}
}
コード例 #14
0
ファイル: LoggedMeasurement.cpp プロジェクト: jasonhogan/sti
void LoggedMeasurement::getDeviceData(MixedData& data)
{
	double value = 0;

	if(type == Attribute)
	{
		device->refreshDeviceAttributes();
		STI_Device::stringToValue(device->getAttribute(measurementKey), value);
		data.setValue(value);
	}
	else if(type == Channel)
	{
		device->read(this->getChannel(), valueIn, data);
		// Debugging only; broken for vectors
//		value = data.getNumber();
//		std::cerr << "Logged: " << value << std::endl;
	}
}
コード例 #15
0
ファイル: LoggedMeasurement.cpp プロジェクト: jasonhogan/sti
void LoggedMeasurement::makeMeasurement()
{
//	measurementTimer.reset();

	MixedData newResult;
	MixedData delta;
	MixedData sigmaSqrd;
	
	getDeviceData(newResult);
	if(measurement == 0)
		delta.setValue(newResult);
	else
		delta.setValue(newResult - measurement);

	thresholdExceeded = false;

	//Does the -1 have to be on the rhs?
	if(sigma != 0 && ((delta < sigma*threshold*(-1)) || (delta > sigma*threshold) ) )
	{
		//spurious data point detected
		thresholdExceeded = true;
		std::cerr << "Threshold Exceeded" << std::endl;
		measurement.setValue(newResult);
		numberAveragedMeasurements = 0;
	}
	else
	{
		//the measurement average resets after each save interval
		measurement.setValue((measurement * numberAveragedMeasurements + newResult) / (numberAveragedMeasurements + 1));
	}

	numberAveragedMeasurements++;

	//standard deviation sigma always includes a contribution from the previous sigma (before numberAveragedMeasurements is reset).
	sigmaSqrd.setValue(
		(sigma*sigma * numberAveragedMeasurements + delta*delta) / (numberAveragedMeasurements + 1) 
		);
	sigma.setValue(sigmaSqrd.sqroot());

	if (numberAveragedMeasurements >= maxNumberToAverage || thresholdExceeded)
	{
		resultIsReady = true;
	}
}
コード例 #16
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);

}
コード例 #17
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;
	}

}
コード例 #18
0
void HPSidebandLockDevice::HPSidebandLockEvent::collectMeasurementData()
{

	MixedData results;
//	results.addValue(0);
//	eventMeasurements.at(0)->setData( results );
//	return;

	boost::shared_lock< boost::shared_mutex > readLock(_this->spectrumMutex);

	long timeout = 5; //seconds
	boost::system_time wakeTime = 
		boost::get_system_time()
		+ boost::posix_time::seconds( static_cast<long>(timeout) );

	//Attempt to wait until the data is ready, or until timeout
	_this->callbackCondition.timed_wait(readLock, wakeTime);

	if(getChannel() == _this->calibrationTraceChannel) {
		
		MixedData calPeaks;
		_this->calibrationResults->getPeakValues(calPeaks);
		
		MixedData calResults;
		calResults.addValue(std::string("Calibration Peaks"));
		calResults.addValue(calPeaks);
		
		results.addValue(calResults);

		eventMeasurements.at(0)->setData( results );
	}
	else if (getChannel() == _this->lockLoopChannel) {

		MixedData peakResults;
		peakResults.addValue(std::string("Spectral Peaks"));
		peakResults.addValue(_this->targetSpectrumPeaks);
		
		MixedData feedbackResults;
		feedbackResults.addValue(std::string("Feedback Signals (sideband difference, sideband to carrier ratio)"));
		feedbackResults.addValue(_this->feedbackSignals);

		results.addValue(feedbackResults);
		results.addValue(peakResults);
		
		eventMeasurements.at(0)->setData( results );
	}
}
コード例 #19
0
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);
}