/// <summary> /// Try open junction by the EM, by calling EMOpenJunction. /// if min voltage exceeded without the junction being opened, do a few steps by the stepper motor, then retry EM (recursion). /// </summary> /// <param name="settings"></param> /// <returns></returns> private bool EMTryOpenJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { // // if the EM reached voltage 0 without opening the junction, // return to higher voltage on EM, do some steps by the stepper motor and retry opening by EM. // if (!EMOpenJunction(settings, worker, e)) { m_electroMagnet.ReachEMVoltageGradually(m_electroMagnet.MinDelay, c_initialEMVoltage); MoveStepsByStepperMotor(StepperDirection.UP, 20); return EMTryOpenJunction(settings, worker, e); } return true; }
/// <summary> /// Close the junction asynchronously by the ElectroMagnet /// </summary> /// <param name="settings"></param> private void EMBeginCloseJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { EMCloseJunctionMethodDelegate emCloseJunctionDelegate = new EMCloseJunctionMethodDelegate(EMTryCloseJunction); AsyncCallback callback = new AsyncCallback(EMEndCloseJunction); IAsyncResult asyncResult = emCloseJunctionDelegate.BeginInvoke(settings, worker, e, callback, emCloseJunctionDelegate); }
/// <summary> /// Close the junction by the ElectroMagnet. /// If max voltage exceeded without the junction being closed, return false. /// </summary> /// <param name="settings">The settings to be used to open the junction</param> private bool EMCloseJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { // // Set the direction of the movement // And configure the first setpper delay (shorter) - faster movement // m_electroMagnet.Direction = StepperDirection.DOWN; m_electroMagnet.Delay = settings.ElectromagnetSettings.EMFastDelayTime; // // Set false to stop operation flag // Keep polling the value until it is abit different than 0. // This is a problem of instability with Flaxer's card. // double initialVoltage = AnalogIn(0); while (initialVoltage == 0.0) { initialVoltage = AnalogIn(0); } m_quitJunctionClosingOperation = false; bool isDelayedChanged = false; // // Until we've not been signaled from outer thread to stop we'll continue moving up. // while (!m_quitJunctionClosingOperation) { // // Cancel the operatin if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } if (!m_electroMagnet.MoveSingleStep()) { // // if min Votlage on EM was exceeded return false. // return false; } double currentVoltage = AnalogIn(0); // // If voltgae had been changed in 0.0001% then switch to slow mode // Note that voltage can be negative so we must take the absoulute value // The two numbers must be of the same sign in order for us to compare them // if (!isDelayedChanged && (currentVoltage * initialVoltage > 0) && (Math.Abs(currentVoltage) > Math.Abs(initialVoltage) * 10)) { m_electroMagnet.Delay = settings.ElectromagnetSettings.EMSlowDelayTime; isDelayedChanged = true; } // // If hold-on trigger was exceeded, wait 10 ms and check if still true. // if (settings.ElectromagnetSettings.IsEMHoldOnEnable && Math.Abs(currentVoltage) > Math.Abs(settings.ElectromagnetSettings.EMHoldOnMaxVoltage * 1.1)) { Thread.Sleep(10); if (Math.Abs(currentVoltage) > Math.Abs(settings.ElectromagnetSettings.EMHoldOnMaxVoltage * 1.1)) { // // trigger was truely exceeded. try to hold on to a certain junction voltage. // if (!StabilizeJunction(currentVoltage, settings.ElectromagnetSettings.EMHoldOnMaxVoltage, settings.ElectromagnetSettings.EMHoldOnMinVoltage)) { return false; } else { return true; } } } Thread.Sleep(m_electroMagnet.Delay); } return true; }
/// <summary> /// Open the junction by the ElectroMagnet. /// If min voltage exceeded without the junction being opened, return false. /// </summary> /// <param name="settings">The settings to be used to open the junction</param> private bool EMOpenJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { // // Set the direction of the movement // And configure the first setpper delay (shorter) - faster movement // m_electroMagnet.Direction = StepperDirection.UP; m_electroMagnet.Delay = settings.ElectromagnetSettings.EMFastDelayTime; // // Read the initial voltgae before we've done anything // double initialVoltage = AnalogIn(0); bool isDelayedChanged = false; m_quitJunctionOpenningOperation = false; // // Until we've not been signaled from outer thread to stop we'll continue moving up. // while (!m_quitJunctionOpenningOperation) { // // Cancel the operatin if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } if (!m_electroMagnet.MoveSingleStep()) { // // if min Votlage on EM was exceeded return false. // return false; } double currentVoltage = AnalogIn(0); // // If voltgae had been changed in 0.0001% then switch to slow mode // Note that voltage can be negative so we must take the absoulute value // if (!isDelayedChanged && (Math.Abs(currentVoltage) < Math.Abs(initialVoltage) * 0.9999)) { m_electroMagnet.Delay = settings.ElectromagnetSettings.EMSlowDelayTime; isDelayedChanged = true; } // // If hold-on trigger was exceeded, wait 10 ms and check if still true. // if (settings.ElectromagnetSettings.IsEMHoldOnEnable && Math.Abs(currentVoltage) < Math.Abs(settings.ElectromagnetSettings.EMHoldOnMaxVoltage * 1.1)) { Thread.Sleep(10); if (Math.Abs(currentVoltage) < Math.Abs(settings.ElectromagnetSettings.EMHoldOnMaxVoltage * 1.1)) { // // trigger was truely exceeded. try to hold on to a certain junction voltage. // if (!StabilizeJunction(currentVoltage, settings.ElectromagnetSettings.EMHoldOnMaxVoltage, settings.ElectromagnetSettings.EMHoldOnMinVoltage)) { return false; } else { return true; } } } Thread.Sleep(m_electroMagnet.Delay); } return true; }
/// <summary> /// Aquire data from an open position while closing the junction /// </summary> /// <param name="settings"></param> /// <param name="worker"></param> /// <param name="e"></param> /// <returns></returns> private bool PerformMakeJunctionCycles(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { double[,] dataAquired; bool isCancelled = false; int finalFileNumber = settings.GeneralSettings.CurrentFileNumber; List<IDataChannel> physicalChannels = new List<IDataChannel>(); // // Since we set the gain to E5 when configuring the task // it is time to set it back to the desired one. // int gainPower; Int32.TryParse(settings.GeneralSettings.Gain, out gainPower); m_amplifier.ChangeGain(gainPower); // // Change the gain power to 5 before reaching contact // to ensure full contact current // if (settings.GeneralSettings.UseDefaultGain) { m_amplifier.ChangeGain(5); } // // Configure the gain to the desired one if we changed it to E5 for reaching contact // if (settings.GeneralSettings.UseDefaultGain) { m_amplifier.ChangeGain(gainPower); } // // Before stat measuring, bring to contact. // Use stepper motor only since we could be far away from reaching contact // It is an important step since we can't be sure in what position we are currently standing. // TryObtainShortCircuit(settings.GeneralSettings.ShortCircuitVoltage, settings.GeneralSettings.UseShortCircuitDelayTime,settings.GeneralSettings.ShortCircuitDelayTime, worker, e); // // Now we can begin our measurements cycles // for (int i = 0; i < settings.GeneralSettings.TotalNumberOfCycles; i++) { // // Cancel the operatin if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } // // Turn off the laser before we open the junction // if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOff(); Thread.Sleep(5000); } // // Before we start the measurement cycles we reach to contact and then open // It is important to reach to contact before trying to open since // there could be a situation where the junction was not closed entirely in the previous // cycle and so it still seems open where actually it is not. // No need to do it in the first cycle since this is done outside the for loop. // if (settings.ElectromagnetSettings.IsEMEnable && i > 0) { EMTryObtainShortCircuit(settings.ElectromagnetSettings.EMShortCircuitDelayTime, settings.GeneralSettings.ShortCircuitVoltage, worker, e); } else { TryObtainShortCircuit(settings.GeneralSettings.ShortCircuitVoltage, settings.GeneralSettings.UseShortCircuitDelayTime,settings.GeneralSettings.ShortCircuitDelayTime, worker, e); } // // Reach to open circuit for initial position // If we intend to use the EM, for the first cycle only, use the stepper motor since // we initially reached to contact with the stepper motor and the EM doesn't have enough force // to withdraw the cantiliver from this intially squeezed position. // isCancelled = (settings.ElectromagnetSettings.IsEMEnable && i > 0) ? EMTryObtainOpenCircuit(settings.ElectromagnetSettings.EMOpenCircuitDelayTime, settings.GeneralSettings.OpenCircuitVoltage, worker, e) : TryObtainOpenCircuit(settings.GeneralSettings.OpenCircuitVoltage, worker, e); if (isCancelled) { break; } // // Turn back on the laser // if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOn(); } // // Start making the junction. // if (settings.ElectromagnetSettings.IsEMEnable) { EMBeginCloseJunction(settings, worker, e); } else { BeginCloseJunction(settings, worker, e); } // // Start the task and wait for the data // try { m_activeTriggeredTask.Start(); } catch (DaqException ex) { throw new SBJException("Error occured when tryin to start DAQ task", ex); } AnalogMultiChannelReader reader = new AnalogMultiChannelReader(m_activeTriggeredTask.Stream); try { dataAquired = reader.ReadMultiSample(-1); if (dataAquired.GetLength(1) < settings.GeneralSettings.TotalSamples) { // // If from some reason we weren't able to // receive all data points, ignore and continue; // m_activeTriggeredTask.Stop(); continue; } if (settings.ChannelsSettings.ActiveChannels.Count != dataAquired.GetLength(0)) { throw new SBJException("Number of data channels doesn't fit the recieved data."); } } catch (DaqException) { // // Probably timeout. // Ignore this cycle and rerun. // m_activeTriggeredTask.Stop(); continue; } // // At this point the reader has returned with all the data // so we can stop the openning of the junction. // m_quitJunctionClosingOperation = true; m_activeTriggeredTask.Stop(); // // Assign the aquired data for each channel. // First clear all data from previous interation. // ClearRawData(settings.ChannelsSettings.ActiveChannels); AssignRawDataToChannels(settings.ChannelsSettings.ActiveChannels, dataAquired); // // physical channel will include both simple and complex channels. // physicalChannels = GetChannelsForDisplay(settings.ChannelsSettings.ActiveChannels); // // calculate the physical data for each channel // GetPhysicalData(physicalChannels); // // Increase file number by one // Save data if needed // finalFileNumber++; if (settings.GeneralSettings.IsFileSavingRequired) { finalFileNumber = SaveData(settings.GeneralSettings.Path, settings.ChannelsSettings.ActiveChannels, physicalChannels, finalFileNumber); } // // Signal UI we have the data // if (DataAquired != null) { DataAquired(this, new DataAquiredEventArgs(physicalChannels, finalFileNumber)); } } return e.Cancel || isCancelled; }
/// <summary> /// Get the task for the data aquisition /// </summary> /// <param name="settings"></param> /// <param name="worker"></param> /// <param name="e"></param> /// <returns></returns> private Task GetMultipleChannelsTriggeredTask(SBJControllerSettings settings, string taskName, RunDirection runDirection, AnalogEdgeReferenceTriggerSlope triggerSlope, double triggerVoltage, BackgroundWorker worker, DoWorkEventArgs e) { AnalogEdgeReferenceTriggerSlope localTriggerSlope; double localTriggerVoltage; // // Determine the trigger slope direction and voltage according to sign of the measured signal. // if (triggerSlope > 0) { localTriggerSlope = triggerSlope; localTriggerVoltage = triggerVoltage; } else { // // Reach to contact in order to retrieve the signal. // if (settings.ElectromagnetSettings.IsEMEnable) { EMTryObtainShortCircuit(settings.ElectromagnetSettings.EMShortCircuitDelayTime, settings.GeneralSettings.ShortCircuitVoltage, worker, e); } else { TryObtainShortCircuit(settings.GeneralSettings.ShortCircuitVoltage, settings.GeneralSettings.UseShortCircuitDelayTime, settings.GeneralSettings.ShortCircuitDelayTime, worker, e); } // // Determines the direction of the current - // Either positive (then voltage is negative) or negative (then voltage is positive number) // bool isPositiveVoltage = AnalogIn(0) > 0; // // Trigger's slope depends both on voltage sign and also on the direction of measurement - break or make junction. // if (isPositiveVoltage) { localTriggerSlope = (runDirection == RunDirection.Break) ? AnalogEdgeReferenceTriggerSlope.Falling : AnalogEdgeReferenceTriggerSlope.Rising; } else { localTriggerSlope = (runDirection == RunDirection.Break) ? AnalogEdgeReferenceTriggerSlope.Rising : AnalogEdgeReferenceTriggerSlope.Falling; } localTriggerVoltage = isPositiveVoltage ? settings.GeneralSettings.TriggerVoltage * (-1) : settings.GeneralSettings.TriggerVoltage; // // Before re-openning the junction set auto range off // so we can stay at high range suitable to E5 gain. // if (settings.GeneralSettings.UseKeithley) { m_sourceMeter.SetAutoRange(false); } // // Open the junction once again as if we didn't do anything. // if (settings.ElectromagnetSettings.IsEMEnable) { EMTryObtainOpenCircuit(settings.ElectromagnetSettings.EMShortCircuitDelayTime, settings.GeneralSettings.OpenCircuitVoltage, worker, e); } else { TryObtainOpenCircuit(settings.GeneralSettings.OpenCircuitVoltage, worker, e); } } // // Create the task with its propertites // TriggeredTaskProperties taskProperties = new TriggeredTaskProperties(taskName, settings.ChannelsSettings.ActiveChannels, settings.GeneralSettings.SampleRate, settings.GeneralSettings.TotalSamples, localTriggerVoltage, settings.GeneralSettings.PretriggerSamples, localTriggerSlope); return m_daqController.CreateMultipleChannelsTriggeredTask(taskProperties); }
/// <summary> /// Configure laser parameters. /// </summary> /// <param name="settings">The settings by which the laser is to be configured</param> /// <exception cref="SBJException"></exception> private void ConfigureLaserIfNeeded(SBJControllerSettings settings) { // // Return if no need to turn the laser on // if (!settings.LaserSettings.IsLaserOn) { return; } //ILaserController laserController = null; if (settings.LaserSettings.LaserMode.Equals("IODrive")) { (m_LaserController as IODriveLaserController).SetAmplitude(settings.LaserSettings.LaserAmplitudeVolts); } else { if (settings.LaserSettings.LaserMode.Equals("DC")) { (m_LaserController as TaborLaserController).SetDCMode(settings.LaserSettings.LaserAmplitudeVolts); } else { if (settings.LaserSettings.LaserMode.Equals("Square")) { (m_LaserController as TaborLaserController).SetSquareMode(settings.LaserSettings.LaserFrequency, settings.LaserSettings.LaserAmplitudeVolts); } else { throw new SBJException("Invalid laser mode. Expected modes: DC or Sqaure"); } } } if (settings.LaserSettings.IsFirstEOMOn) { m_taborFirstEOMController.SetSinusoidMode(settings.LaserSettings.FirstEOMFrequency); m_taborFirstEOMController.TurnOn(); } if (settings.LaserSettings.IsSecondEOMOn) { m_taborSecondEOMController.SetSinusoidMode(settings.LaserSettings.SecondEOMFrequency); m_taborSecondEOMController.TurnOn(); } }
/// <summary> /// Open the junction asynchronously /// </summary> /// <param name="settings"></param> private void BeginOpenJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { OpenJunctionMethodDelegate openJunctionDelegate = new OpenJunctionMethodDelegate(OpenJunction); AsyncCallback callback = new AsyncCallback(EndOpenJunction); IAsyncResult asyncResult = openJunctionDelegate.BeginInvoke(settings, worker, e, callback, openJunctionDelegate); }
/// <summary> /// Move cantiliver to position until trigger is reached; Then stop. /// </summary> /// <param name="sBJControllerSettings"></param> /// <param name="worker"></param> /// <param name="e"></param> public bool ReachPosition(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { bool isCancelled = false; // // Apply voltage with desired tool: Task or Keithley // ApplyVoltageIfNeeded(settings.GeneralSettings.UseKeithley, settings.GeneralSettings.Bias, settings.GeneralSettings.BiasError, settings.GeneralSettings.Range, settings.GeneralSettings.AutoRange); // // Use Lambda Zup to apply constant voltage on external electromagnet if needed // UseLambdaZupIfNeeded(settings.LambdaZupSettings.IsLambdaZupEnable, settings.LambdaZupSettings.OutputVoltage); // // Configure the laser if needed for this run // ConfigureLaserIfNeeded(settings); // // Save this run settings if desired // SaveSettingsIfNeeded(settings, settings.GeneralSettings.IsFileSavingRequired, settings.GeneralSettings.Path); // //apply initial voltage on the EM // ApplyVoltageOnElectroMagnetIfNeeded(settings.ElectromagnetSettings.IsEMEnable); switch (settings.GeneralSettings.RunDirection) { case RunDirection.Both: //TODO: Add implementation for both direction measurement break; case RunDirection.Break: isCancelled = ReachToPositionByMovingUp(settings, worker, e); break; case RunDirection.Make: isCancelled = ReachToPositionByMovingDown(settings, worker, e); break; } // // Finish the measurement properly // if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOff(); } if (settings.ElectromagnetSettings.IsEMEnable) { m_electroMagnet.Shutdown(); } if (settings.LaserSettings.IsFirstEOMOn) { m_taborFirstEOMController.TurnOff(); } if (settings.LaserSettings.IsSecondEOMOn) { m_taborSecondEOMController.TurnOff(); } if (settings.LambdaZupSettings.IsLambdaZupEnable) { m_lambdaZup.TurnOffOutput(); } m_activeTriggeredTask.Dispose(); m_stepperMotor.Shutdown(); return isCancelled; }
/// <summary> /// Close the junction asynchronously /// </summary> /// <param name="settings"></param> private void BeginCloseJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { CloseJunctionMethodDelegate closeJunctionDelegate = new CloseJunctionMethodDelegate(CloseJunction); AsyncCallback callback = new AsyncCallback(EndCloseJunction); IAsyncResult asyncResult = closeJunctionDelegate.BeginInvoke(settings, worker, e, callback, closeJunctionDelegate); }
/// <summary> /// Manually aquire data /// This method continuously poll the buffer for data until it is stopped by the user. /// </summary> /// <param name="settings">The settings for running the aquisition</param> /// <returns>True whether the operation was cacled by the user. False otherwise.</returns> public bool AquireDataContinuously(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { // // Apply voltage with desired tool: Task or Keithley // ApplyVoltageIfNeeded(settings.GeneralSettings.UseKeithley, settings.GeneralSettings.Bias, settings.GeneralSettings.BiasError, settings.GeneralSettings.Range, settings.GeneralSettings.AutoRange); bool isCancelled = false; int finalFileNumber = settings.GeneralSettings.CurrentFileNumber; // // The array is intialized with size for 1 minute sampling. // double[,] dataAquired = new double[1000, 1000]; List<IDataChannel> physicalChannels = new List<IDataChannel>(); // // Configure the laser if needed for this run // ConfigureLaserIfNeeded(settings); // // Save this run settings if desired // SaveSettingsIfNeeded(settings, settings.GeneralSettings.IsFileSavingRequired, settings.GeneralSettings.Path); // //apply initial voltage on the EM // ApplyVoltageOnElectroMagnetIfNeeded(settings.ElectromagnetSettings.IsEMEnable); // // Create the task // m_activeTriggeredTask = GetContinuousAITask(settings.GeneralSettings.SampleRate, settings.ChannelsSettings.ActiveChannels, null); // // If EM is enabled, and we are asked to skip the first cycle (that is done by the stepper motor), // then return. // if (settings.ElectromagnetSettings.IsEMEnable && settings.ElectromagnetSettings.IsEMSkipFirstCycleEnable) { m_stepperMotor.Shutdown(); return false; } if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOn(); } // // Start the task and wait for the data // try { m_activeTriggeredTask.Start(); } catch (DaqException ex) { throw new SBJException("Error occured when tryin to start DAQ task", ex); } AnalogMultiChannelReader reader = new AnalogMultiChannelReader(m_activeTriggeredTask.Stream); List<List<double>> fullData = new List<List<double>>(settings.ChannelsSettings.ActiveChannels.Count); for (int i = 0; i < fullData.Capacity; i++) { fullData.Add(new List<double>()); } try { // // Before getting all the data clear the lists. // ClearRawData(settings.ChannelsSettings.ActiveChannels); // // As long as the user didn't ask to stop the acquisition // (which is signaled by the stop of the stepper motion) // we coninue sampling. // while (!worker.CancellationPending) { // // Read all available data points in the buffer that // were not read so far. // dataAquired = reader.ReadMultiSample(-1); fullData = AccumulateData(fullData, dataAquired); dataAquired = null; } } catch (DaqException) { // // In case of an error just return // m_activeTriggeredTask.Stop(); m_activeTriggeredTask.Dispose(); if (m_LaserController != null) { m_LaserController.TurnOff(); } if (m_taborFirstEOMController != null) { m_taborFirstEOMController.TurnOff(); } if (m_taborSecondEOMController != null) { m_taborSecondEOMController.TurnOff(); } return false; } // // At this point the user had requested to stop the data aquisition. // By signaling "stop". We can stop the task. // m_activeTriggeredTask.Stop(); // // Assign the aquired data for each channel after an average process // AssignRawDataToChannels(settings.ChannelsSettings.ActiveChannels, ConvertDataToMatrix(fullData)); // // physical channel will include both simple and complex channels. // physicalChannels = GetChannelsForDisplay(settings.ChannelsSettings.ActiveChannels); // // calculate the physical data for each channel // GetPhysicalData(physicalChannels); // // Increase file number by one // Save data if needed // finalFileNumber++; if (settings.GeneralSettings.IsFileSavingRequired) { finalFileNumber = SaveData(settings.GeneralSettings.Path, settings.ChannelsSettings.ActiveChannels, physicalChannels, finalFileNumber); } // // Signal UI we have the data // if (DataAquired != null) { DataAquired(this, new DataAquiredEventArgs(physicalChannels, finalFileNumber)); } // // Finish the measurement properly // if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOff(); } if (settings.ElectromagnetSettings.IsEMEnable) { m_electroMagnet.Shutdown(); } if (settings.LaserSettings.IsFirstEOMOn) { m_taborFirstEOMController.TurnOff(); } if (settings.LaserSettings.IsSecondEOMOn) { m_taborSecondEOMController.TurnOff(); } m_activeTriggeredTask.Dispose(); m_stepperMotor.Shutdown(); return (isCancelled || e.Cancel); }
/// <summary> /// Manually aquire data /// This method continuously poll the buffer for data until it is stopped by the user. /// </summary> /// <param name="settings">The settings for running the aquisition</param> /// <returns>True whether the operation was cacled by the user. False otherwise.</returns> public bool AquireDataManually(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { // // Apply voltage with desired tool: Task or Keithley // ApplyVoltageIfNeeded(settings.GeneralSettings.UseKeithley, settings.GeneralSettings.Bias, settings.GeneralSettings.BiasError, settings.GeneralSettings.Range, settings.GeneralSettings.AutoRange); bool isCancelled = false; int finalFileNumber = settings.GeneralSettings.CurrentFileNumber; // // The array is intialized with size for 1 minute sampling. // double[,] dataAquired = new double[1000, 1000]; List<IDataChannel> physicalChannels = new List<IDataChannel>(); // // Configure the laser if needed for this run // ConfigureLaserIfNeeded(settings); // // Save this run settings if desired // SaveSettingsIfNeeded(settings, settings.GeneralSettings.IsFileSavingRequired, settings.GeneralSettings.Path); // //apply initial voltage on the EM // ApplyVoltageOnElectroMagnetIfNeeded(settings.ElectromagnetSettings.IsEMEnable); // // Create the task // m_activeTriggeredTask = GetContinuousAITask(settings.GeneralSettings.SampleRate, settings.ChannelsSettings.ActiveChannels, null); // // If EM is enabled, and we are asked to skip the first cycle (that is done by the stepper motor), // then return. // if (settings.ElectromagnetSettings.IsEMEnable && settings.ElectromagnetSettings.IsEMSkipFirstCycleEnable) { m_stepperMotor.Shutdown(); return false; } // // Turn off the laser before we reach contact // if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOff(); Thread.Sleep(5000); } // // Change the gain power to 5 before reaching contact // to ensure full contact current // if (settings.GeneralSettings.UseDefaultGain) { m_amplifier.ChangeGain(5); } // // Reach to contact before we start openning the junction // If EM is enabled and we're after the first cycle, use the EM. // If user asked to stop than exit // isCancelled = (settings.ElectromagnetSettings.IsEMEnable) ? EMTryObtainShortCircuit(settings.ElectromagnetSettings.EMShortCircuitDelayTime, settings.GeneralSettings.ShortCircuitVoltage, worker, e) : TryObtainShortCircuit(settings.GeneralSettings.ShortCircuitVoltage, settings.GeneralSettings.UseShortCircuitDelayTime,settings.GeneralSettings.ShortCircuitDelayTime, worker, e); if (isCancelled) { return false; } // // Configure the gain to the desired one before strating the measurement. // And also this is the time to switch the laser on. // if (settings.GeneralSettings.UseDefaultGain) { int gainPower; Int32.TryParse(settings.GeneralSettings.Gain, out gainPower); m_amplifier.ChangeGain(gainPower); } if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOn(); } // // Start openning the junction. // If EM is enabled then use it. // if (settings.ElectromagnetSettings.IsEMEnable) { m_stepperMotor.Shutdown(); EMBeginOpenJunction(settings, worker, e); } else { BeginOpenJunction(settings, worker, e); } // // Start the task and wait for the data // try { m_activeTriggeredTask.Start(); } catch (DaqException ex) { throw new SBJException("Error occured when tryin to start DAQ task", ex); } AnalogMultiChannelReader reader = new AnalogMultiChannelReader(m_activeTriggeredTask.Stream); List<List<double>> averagedData = new List<List<double>>(settings.ChannelsSettings.ActiveChannels.Count); for (int i = 0; i < averagedData.Capacity; i++) { averagedData.Add(new List<double>()); } try { // // Before getting all the data clear the lists. // ClearRawData(settings.ChannelsSettings.ActiveChannels); // // As long as the user didn't ask to stop the acquisition // (which is signaled by the stop of the stepper motion) // we coninue sampling. // while (!m_quitJunctionOpenningOperation) { // // Read all available data points in the buffer that // were not read so far. // dataAquired = reader.ReadMultiSample(-1); // // Get average for the acquired the data and assign to variable // List<double> averageDataValues = GetAverageDataValue(dataAquired); for (int i = 0; i < averageDataValues.Count; i++) { averagedData[i].Add(averageDataValues[i]); } dataAquired = null; // // Cancel the operatin if user asked for // We do it at the end of the loop to make sure we // saved all the data we have available. // if (worker.CancellationPending == true) { e.Cancel = true; break; } } } catch (DaqException) { // // In case of an error just return // m_activeTriggeredTask.Stop(); m_activeTriggeredTask.Dispose(); if (m_LaserController != null) { m_LaserController.TurnOff(); } if (m_taborFirstEOMController != null) { m_taborFirstEOMController.TurnOff(); } if (m_taborSecondEOMController != null) { m_taborSecondEOMController.TurnOff(); } return false; } // // At this point the user had requested to stop the data aquisition. // By signaling "stop". We can stop the task. // m_activeTriggeredTask.Stop(); // // Assign the aquired data for each channel after an average process // AssignRawDataToChannels(settings.ChannelsSettings.ActiveChannels, ConvertDataToMatrix(GetAveragedData(averagedData, 5000))); // // physical channel will include both simple and complex channels. // physicalChannels = GetChannelsForDisplay(settings.ChannelsSettings.ActiveChannels); // // calculate the physical data for each channel // GetPhysicalData(physicalChannels); // // Increase file number by one // Save data if needed // finalFileNumber++; if (settings.GeneralSettings.IsFileSavingRequired) { finalFileNumber = SaveData(settings.GeneralSettings.Path, settings.ChannelsSettings.ActiveChannels, physicalChannels, finalFileNumber); } // // Signal UI we have the data // if (DataAquired != null) { DataAquired(this, new DataAquiredEventArgs(physicalChannels, finalFileNumber)); } // // Finish the measurement properly // if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOff(); } if (settings.ElectromagnetSettings.IsEMEnable) { m_electroMagnet.Shutdown(); } if (settings.LaserSettings.IsFirstEOMOn) { m_taborFirstEOMController.TurnOff(); } if (settings.LaserSettings.IsSecondEOMOn) { m_taborSecondEOMController.TurnOff(); } m_activeTriggeredTask.Dispose(); m_stepperMotor.Shutdown(); return (isCancelled || e.Cancel); }
/// <summary> /// Data aquisition /// </summary> /// <param name="settings">The settings for running the aquisition</param> /// <returns>True whether the operation was cacled by the user. False otherwise.</returns> public bool AquireData(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { bool isCancelled = false; // // Apply voltage with desired tool: Task or Keithley // ApplyVoltageIfNeeded(settings.GeneralSettings.UseKeithley, settings.GeneralSettings.Bias, settings.GeneralSettings.BiasError, settings.GeneralSettings.Range, settings.GeneralSettings.AutoRange); // // Use Lambda Zup to apply constant voltage on external electromagnet if needed // UseLambdaZupIfNeeded(settings.LambdaZupSettings.IsLambdaZupEnable, settings.LambdaZupSettings.OutputVoltage); // // Configure the laser if needed for this run // ConfigureLaserIfNeeded(settings); // // Save this run settings if desired // SaveSettingsIfNeeded(settings, settings.GeneralSettings.IsFileSavingRequired, settings.GeneralSettings.Path); // //apply initial voltage on the EM // ApplyVoltageOnElectroMagnetIfNeeded(settings.ElectromagnetSettings.IsEMEnable); // // Change to E5 gain to determine current sign (+/-) in order to configure the task correctly // This is also used to disable auto range once reached to contact. // m_amplifier.ChangeGain(5); // // Create the task // switch (settings.GeneralSettings.RunDirection) { case RunDirection.Both: //TODO: Add implementation for both direction measurement break; case RunDirection.Break: m_firstTriggeredTask = GetMultipleChannelsTriggeredTask(settings, "firstTriggeredTask" ,RunDirection.Break, 0, 0, worker, e); m_firstTriggeredTask.Control(TaskAction.Verify); double level = m_firstTriggeredTask.Triggers.ReferenceTrigger.AnalogEdge.Level * -1; AnalogEdgeReferenceTriggerSlope slope = m_firstTriggeredTask.Triggers.ReferenceTrigger.AnalogEdge.Slope == AnalogEdgeReferenceTriggerSlope.Falling ? AnalogEdgeReferenceTriggerSlope.Rising : AnalogEdgeReferenceTriggerSlope.Falling; m_secondaryTriggeredTask = GetMultipleChannelsTriggeredTask(settings, "secondaryTriggeredTask", RunDirection.Break, slope, level , worker, e); isCancelled = PerformBreakJunctionCycles(settings, worker, e); break; case RunDirection.Make: m_activeTriggeredTask = GetMultipleChannelsTriggeredTask(settings, null,RunDirection.Make, m_triggerSlope, m_triggerVoltage, worker, e); isCancelled = PerformMakeJunctionCycles(settings, worker, e); break; } // // Finish the measurement properly // if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOff(); } if (settings.ElectromagnetSettings.IsEMEnable) { m_electroMagnet.Shutdown(); } if (settings.LaserSettings.IsFirstEOMOn) { m_taborFirstEOMController.TurnOff(); } if (settings.LaserSettings.IsSecondEOMOn) { m_taborSecondEOMController.TurnOff(); } if (settings.LambdaZupSettings.IsLambdaZupEnable) { m_lambdaZup.TurnOffOutput(); } m_activeTriggeredTask.Dispose(); m_firstTriggeredTask.Dispose(); m_secondaryTriggeredTask.Dispose(); m_stepperMotor.Shutdown(); return isCancelled; }
/// <summary> /// Open the junction /// </summary> /// <param name="settings">The settings to be used to open the junction</param> private void OpenJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { // // Set the direction of the movement and stepping mode // And configure the first setpper delay (shorter) - faster movement // m_stepperMotor.Direction = StepperDirection.UP; m_stepperMotor.SteppingMode = StepperSteppingMode.HALF; m_stepperMotor.Delay = settings.GeneralSettings.StepperWaitTime1; // // Read the initial voltgae before we've done anything // double initialVoltage = AnalogIn(0); bool isDelayedChanged = false; m_quitJunctionOpenningOperation = false; // // Until we've not been signaled from outer thread to stop we'll continue moving up. // while (!m_quitJunctionOpenningOperation) { // // Cancel the operatin if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } m_stepperMotor.MoveSingleStep(); double currentVoltage = AnalogIn(0); // // If voltgae had been changed in 0.0001% then switch to slow mode // Note that voltage can be negative so we must take the absoulute value // if (!isDelayedChanged && (Math.Abs(currentVoltage) < Math.Abs(initialVoltage) * 0.95)) { m_stepperMotor.Delay = settings.GeneralSettings.StepperWaitTime2; isDelayedChanged = true; } Thread.Sleep(m_stepperMotor.Delay); } }
/// <summary> /// Reach to position specified by conductance value and then stop and aqcuire data until asked to stop. /// </summary> /// <param name="settings"></param> /// <param name="worker"></param> /// <param name="e"></param> /// <returns></returns> private bool ReachToPositionByMovingUp(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { double[,] dataAcquired = new double[1000, 1000]; int finalFileNumber = settings.GeneralSettings.CurrentFileNumber; List<IDataChannel> physicalChannels = new List<IDataChannel>(); for (int i = 0; i < settings.GeneralSettings.TotalNumberOfCycles; i++) { // // Cancel the operatin if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } // // This flag is used to signal us when the user asked to stop the real time data acquisition // m_quitRealTimeOperation = false; m_activeTriggeredTask = GetMultipleChannelsTriggeredTask(settings, null, RunDirection.Break, m_triggerSlope, m_triggerVoltage, worker, e); m_activeTriggeredTask.EveryNSamplesReadEventInterval = settings.GeneralSettings.TotalSamples; m_activeTriggeredTask.Done += new TaskDoneEventHandler(OnTaskDoneOpenning); m_activeTriggeredTask.Control(TaskAction.Verify); m_triggerSlope = m_activeTriggeredTask.Triggers.ReferenceTrigger.AnalogEdge.Slope; m_triggerVoltage = m_activeTriggeredTask.Triggers.ReferenceTrigger.AnalogEdge.Level; // // physical channel will include both simple and complex channels. // physicalChannels = GetChannelsForDisplay(settings.ChannelsSettings.ActiveChannels); // // Assign the aquired data for each channel. // First clear all data from previous interation. // ClearRawData(settings.ChannelsSettings.ActiveChannels); // // Create the tasks: One for triggering us to stop and the other for start monitoring the data // m_realTimeTask = GetContinuousAITask(settings.GeneralSettings.SampleRate, settings.ChannelsSettings.ActiveChannels, null); AnalogMultiChannelReader realTimeReader = new AnalogMultiChannelReader(m_realTimeTask.Stream); // // Start closing the junction. // If EM is enabled use the EM. // if (settings.ElectromagnetSettings.IsEMEnable) { EMTryObtainShortCircuit(settings.ElectromagnetSettings.EMShortCircuitDelayTime, settings.GeneralSettings.ShortCircuitVoltage, worker, e); } else { TryObtainShortCircuit(settings.GeneralSettings.ShortCircuitVoltage, settings.GeneralSettings.UseShortCircuitDelayTime,settings.GeneralSettings.ShortCircuitDelayTime, worker, e); } // // Start openning the junction. ASync operation. // If EM is enabled use the EM. // if (settings.ElectromagnetSettings.IsEMEnable) { EMBeginOpenJunction(settings, worker, e); } else { BeginOpenJunction(settings, worker, e); } // // Cancel the operatin if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } // // Start the triggered task. // m_activeTriggeredTask.Start(); // // If the user asked to stop the operation on the external thread then // WaitUntilDone will throw an expection. We can ignore that and return. // try { m_activeTriggeredTask.WaitUntilDone(); } catch (DaqException) { // // We got here if the user asked to stop the operation // break; } // // We reach this point only after we reached the desired conductance value. // As long as the user didn't ask to stop the operation continue recording the data. // while (!m_quitRealTimeOperation) { // // Read operation implicity start the task without the need to call Start() method. // try { dataAcquired = realTimeReader.ReadMultiSample(-1); } catch (DaqException) { continue; } if (dataAcquired.Length == 0) { continue; } // // Assign the aquired data for each channel. // AssignRawDataToChannels(settings.ChannelsSettings.ActiveChannels, dataAcquired); // // calculate the physical data for each channel // GetPhysicalData(physicalChannels); // // Signal UI we have the data // if (DataAquired != null) { DataAquired(this, new DataAquiredEventArgs(physicalChannels, finalFileNumber)); } } if (DoneReadingData != null) { DoneReadingData(this, null); } m_realTimeTask.Stop(); m_realTimeTask.Dispose(); // // Increase file number by one // Save data if needed // finalFileNumber++; if (settings.GeneralSettings.IsFileSavingRequired) { finalFileNumber = SaveData(settings.GeneralSettings.Path, settings.ChannelsSettings.ActiveChannels, physicalChannels, finalFileNumber); } } m_activeTriggeredTask.Dispose(); m_realTimeTask.Dispose(); m_triggerSlope = 0; m_triggerVoltage = 0; return e.Cancel; }
/// <summary> /// Open the junction /// </summary> /// <param name="settings">The settings to be used to open the junction</param> private void CloseJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { // // Set the direction of the movement and stepping mode // And configure the first setpper delay. // m_stepperMotor.Direction = StepperDirection.DOWN; m_stepperMotor.SteppingMode = StepperSteppingMode.HALF; m_stepperMotor.Delay = settings.GeneralSettings.StepperWaitTime1; // // Read the initial voltgae before we've done anything // Keep polling the value until it is abit different than 0. // This is a problem of instability with Flaxer's card. // double initialVoltage = AnalogIn(0); while (initialVoltage == 0.0) { initialVoltage = AnalogIn(0); } bool isDelayedChanged = false; m_quitJunctionClosingOperation = false; // // Until we've not been signaled from outer thread to stop we'll continue moving up. // while (!m_quitJunctionClosingOperation) { // // Cancel the operatin if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } m_stepperMotor.MoveSingleStep(); double currentVoltage = AnalogIn(0); // // If voltgae had been changed in 0.0001% then switch to slow mode // Note that voltage can be negative so we must take the absoulute value // The two numbers must be of the same sign in order for us to compare them // if (!isDelayedChanged && (currentVoltage * initialVoltage > 0 ) && (Math.Abs(currentVoltage) > Math.Abs(initialVoltage) * 50)) { m_stepperMotor.Delay = settings.GeneralSettings.StepperWaitTime2; isDelayedChanged = true; } Thread.Sleep(m_stepperMotor.Delay); } }
/// <summary> /// Try close junction by the EM, by calling EMCloseJunction. /// if max voltage exceeded without the junction being closed, do a few steps by the stepper motor, then retry EM (recursion). /// </summary> /// <param name="settings"></param> /// <returns></returns> private bool EMTryCloseJunction(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { double initialValue = Math.Abs(AnalogIn(0)); while (initialValue == 0.0) { initialValue = Math.Abs(AnalogIn(0)); } // // if the EM reached max voltage without closing the junction, // return to lower voltage on EM, do some steps by the stepper motor and retry opening by EM. // if (!EMCloseJunction(settings, worker, e)) { double currentValue = Math.Abs(AnalogIn(0)); m_electroMagnet.ReachEMVoltageGradually(m_electroMagnet.MinDelay, c_initialEMVoltage); if (currentValue > initialValue*2) { MoveStepsByStepperMotor(StepperDirection.DOWN, 50); } else { MoveStepsByStepperMotor(StepperDirection.DOWN, 200); } return EMTryCloseJunction(settings, worker, e); } return true; }
/// <summary> /// Aquire data from a close position while openning the junction /// </summary> /// <param name="settings"></param> /// <param name="worker"></param> /// <param name="e"></param> /// <returns></returns> private bool PerformBreakJunctionCycles(SBJControllerSettings settings, BackgroundWorker worker, DoWorkEventArgs e) { double[,] dataAquired; bool isCancelled = false; int finalFileNumber = settings.GeneralSettings.CurrentFileNumber; List<IDataChannel> physicalChannels = new List<IDataChannel>(); // // Since we set the gain to E5 when configuring the task // it is time to set it back to the desired one. // int gainPower; Int32.TryParse(settings.GeneralSettings.Gain, out gainPower); m_amplifier.ChangeGain(gainPower); for (int i = 0; i < settings.GeneralSettings.TotalNumberOfCycles; i++) { // // Cancel the operation if user asked for // if (worker.CancellationPending == true) { e.Cancel = true; break; } // // if EM is enabled, and we are asked to skip the first cycle (that is done by the stepper motor), // move on to the next cycle. // if (settings.ElectromagnetSettings.IsEMEnable && settings.ElectromagnetSettings.IsEMSkipFirstCycleEnable && i == 0) { m_stepperMotor.Shutdown(); continue; } // // Turn off the laser before we reach contact // //if (settings.LaserSettings.IsLaserOn) //{ // m_LaserController.TurnOff(); // Thread.Sleep(5000); //} // // Change the gain power to 5 before reaching contact // to ensure full contact current // if (settings.GeneralSettings.UseDefaultGain || settings.GeneralSettings.ChangeGain) { m_amplifier.ChangeGain(5); } // // Reach to contact before we start openning the junction // If EM is enabled and we're after the first cycle, use the EM. // If user asked to stop then exit // isCancelled = (settings.ElectromagnetSettings.IsEMEnable && i > 0) ? EMTryObtainShortCircuit(settings.ElectromagnetSettings.EMShortCircuitDelayTime, settings.GeneralSettings.ShortCircuitVoltage, worker, e) : TryObtainShortCircuit(settings.GeneralSettings.ShortCircuitVoltage, settings.GeneralSettings.UseShortCircuitDelayTime, settings.GeneralSettings.ShortCircuitDelayTime, worker, e); if (isCancelled) { break; } // // Configure the gain to the desired one if we changed it to E5 // before strating the measurement. // And also this is the time to switch the laser on. // if (settings.GeneralSettings.UseDefaultGain) { m_amplifier.ChangeGain(gainPower); } if (settings.LaserSettings.IsLaserOn) { m_LaserController.TurnOn(); } // // Set the bias if AC mode // m_activeTriggeredTask = m_firstTriggeredTask; if (settings.GeneralSettings.ACBias) { double bias = Math.Pow(-1, finalFileNumber) * settings.GeneralSettings.Bias; m_sourceMeter.SetBias(bias, settings.GeneralSettings.Range,settings.GeneralSettings.AutoRange); m_activeTriggeredTask = (bias == settings.GeneralSettings.Bias) ? m_firstTriggeredTask : m_secondaryTriggeredTask; } // // Start openning the junction. // If EM is enabled and we're after the first cycle, use the EM. // if (settings.ElectromagnetSettings.IsEMEnable) { if (i == 0) { // // open the junction by stepper motor. this function does it indipendently; // it doesn't wait for the trigger task to finish. and we stay on the current thread. // ObtainOpenJunctionByStepperMotor(settings.GeneralSettings.TriggerVoltage, worker, e); // // from now on we will use the EM, so we don't want the stepper motor to stay on. // m_stepperMotor.Shutdown(); continue; } else { EMBeginOpenJunction(settings, worker, e); } } else { BeginOpenJunction(settings, worker, e); } // // Start the task and wait for the data // try { m_activeTriggeredTask.Start(); } catch (DaqException ex) { throw new SBJException("Error occured when tryin to start DAQ task", ex); } if (settings.GeneralSettings.ChangeGain && (settings.GeneralSettings.StepperWaitTime2 > settings.GeneralSettings.StepperWaitTime1)) { while (!m_quitJunctionOpenningOperation && (m_stepperMotor.Delay != settings.GeneralSettings.StepperWaitTime2)) { } if (!m_quitJunctionOpenningOperation) { m_amplifier.ChangeGain(gainPower); } } AnalogMultiChannelReader reader = new AnalogMultiChannelReader(m_activeTriggeredTask.Stream); try { dataAquired = reader.ReadMultiSample(-1); if (dataAquired.GetLength(1) < settings.GeneralSettings.TotalSamples) { // // If from some reason we weren't able to // receive all data points, ignore and continue; // m_activeTriggeredTask.Stop(); continue; } if (settings.ChannelsSettings.ActiveChannels.Count != dataAquired.GetLength(0)) { throw new SBJException("Number of data channels doesn't fit the recieved data."); } } catch (DaqException ex ) { if (ex.Error == -88709 || ex.Error == -88710) { // // User asked to stop so the task was aborted from the UI thread // break; } else { // // Probably timeout. // Ignore this cycle and rerun. // m_activeTriggeredTask.Stop(); continue; } } // // At this point the reader has returned with all the data // so we can stop the openning of the junction. // m_quitJunctionOpenningOperation = true; m_activeTriggeredTask.Stop(); // // Assign the aquired data for each channel. // First clear all data from previous interation. // ClearRawData(settings.ChannelsSettings.ActiveChannels); AssignRawDataToChannels(settings.ChannelsSettings.ActiveChannels, dataAquired); // // physical channel will include both simple and complex channels. // physicalChannels = GetChannelsForDisplay(settings.ChannelsSettings.ActiveChannels); // // calculate the physical data for each channel // GetPhysicalData(physicalChannels); // // Increase file number by one // Save data if needed // finalFileNumber++; if (settings.GeneralSettings.IsFileSavingRequired) { finalFileNumber = SaveData(settings.GeneralSettings.Path, settings.ChannelsSettings.ActiveChannels, physicalChannels, finalFileNumber); } // // Signal UI we have the data // if (DataAquired != null) { DataAquired(this, new DataAquiredEventArgs(physicalChannels, finalFileNumber)); } } return e.Cancel || isCancelled; }