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); }
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; } }