Loading...
Searching...
No Matches
Advanced Experiment Logic

This example demonstrates how to create a custom experiment using loops and subexperiments for added complexity.

Experiment Description

The API allows us to build experiments with multiple elements, which can loop individually or as a group. Let's consider building an experimental sequence with the following structure:

  1. Open Circuit Potential (OCP) element
  2. Constant Potential Element (loops 4 times, increasing the voltage by 100 mV each loop)
  3. Galvanostatic EIS element and OCP element (loops 3 times)
  4. Constant Current element that loops 2 times
  • C++
    auto customExperiment = std::make_shared<AisExperiment>();
    AisOpenCircuitElement ocpElement(1, 10);
    success &= customExperiment->appendElement(ocpElement);
    int voltage = 0;
    for (int i = 0; i < 4; i++) {
    AisConstantPotElement cvElement(voltage, 0.1, 5);
    success &= customExperiment->appendElement(cvElement, 1);
    voltage += 0.1; // Adding 100 mV
    }
    AisExperiment eisSubExperiment;
    AisEISGalvanostaticElement galvEISElement(10, 10000, 10, 0.01, 0.1);
    AisOpenCircuitElement ocpElement2(1, 5);
    success &= eisSubExperiment.appendElement(galvEISElement, 1);
    success &= eisSubExperiment.appendElement(ocpElement2, 1);
    success &= customExperiment->appendSubExperiment(eisSubExperiment, 3);
    AisConstantCurrentElement ccElement(0.1, 1, 10);
    success &= customExperiment->appendElement(ccElement, 2);
    if (!success) {
    qDebug() << "Error building experiment";
    return 0;
    }
  • Python
    customExperiment = AisExperiment()
    # Step 1
    ocpElement = AisOpenCircuitElement(1, 10)
    success &= customExperiment.appendElement(ocpElement)
    voltage = 0
    for i in range(0, 4):
    cvElement = AisConstantPotElement(voltage, 0.1, 5)
    success &= customExperiment.appendElement(cvElement, 1)
    voltage = voltage + 0.1
    eisSubExperiment = AisExperiment()
    galvEISElement = AisEISGalvanostaticElement(10, 10000, 10, 0.01, 0.1)
    ocpElement2 = AisOpenCircuitElement(1, 5)
    success &= eisSubExperiment.appendElement(galvEISElement, 1)
    success &= eisSubExperiment.appendElement(ocpElement2, 1)
    success &= customExperiment.appendSubExperiment(eisSubExperiment, 3)
    ccElement = AisConstantCurrentElement(0.1, 1, 10)
    success &= customExperiment.appendElement(ccElement, 2)
    if not success:
    print("Error building experiment")
    sys.exit()

Let's go over the code in more detail:

Building the Experiment

Here, we create the Open Circuit Element and add it to the experiment without specifying the number of loops, so it runs once.

Next, we create the Constant Potential Elements, using a for loop to increment the voltage for each element, and then adding it to the created subExperiment.

  • C++
    int voltage = 0;
    for (int i = 0; i < 4; i++) {
    AisConstantPotElement cvElement(voltage, 0.1, 5);
    success &= customExperiment->appendElement(cvElement, 1);
    voltage += 0.1; // Adding 100 mV
    }
  • Python
    voltage = 0
    for i in range(0, 4):
    cvElement = AisConstantPotElement(voltage, 0.1, 5)
    success &= customExperiment.appendElement(cvElement, 1)
    voltage = voltage + 0.1

For the looped EIS and OCP elements, we create another AisExperiment (eisSubExperiment), add the elements, and use AisExperiment::appendSubExperiment with 3 passed as the loop argument. This makes the two elements loop consecutively 3 times.

  • C++
    AisExperiment eisSubExperiment;
    AisEISGalvanostaticElement galvEISElement(10, 10000, 10, 0.01, 0.1);
    AisOpenCircuitElement ocpElement2(1, 5);
    success &= eisSubExperiment.appendElement(galvEISElement, 1);
    success &= eisSubExperiment.appendElement(ocpElement2, 1);
    success &= customExperiment->appendSubExperiment(eisSubExperiment, 3);
  • Python
    eisSubExperiment = AisExperiment()
    galvEISElement = AisEISGalvanostaticElement(10, 10000, 10, 0.01, 0.1)
    ocpElement2 = AisOpenCircuitElement(1, 5)
    success &= eisSubExperiment.appendElement(galvEISElement, 1)
    success &= eisSubExperiment.appendElement(ocpElement2, 1)
    success &= customExperiment.appendSubExperiment(eisSubExperiment, 3)

Lastly, we create the Constant Current Element, adding it to the main experiment using AisExperiment::appendElement with the loop argument set to 2. This loops the element twice at the end.

  • C++
    AisExperiment eisSubExperiment;
    AisEISGalvanostaticElement galvEISElement(10, 10000, 10, 0.01, 0.1);
    AisOpenCircuitElement ocpElement2(1, 5);
    success &= eisSubExperiment.appendElement(galvEISElement, 1);
    success &= eisSubExperiment.appendElement(ocpElement2, 1);
    success &= customExperiment->appendSubExperiment(eisSubExperiment, 3);
  • Python
    eisSubExperiment = AisExperiment()
    galvEISElement = AisEISGalvanostaticElement(10, 10000, 10, 0.01, 0.1)
    ocpElement2 = AisOpenCircuitElement(1, 5)
    success &= eisSubExperiment.appendElement(galvEISElement, 1)
    success &= eisSubExperiment.appendElement(ocpElement2, 1)
    success &= customExperiment.appendSubExperiment(eisSubExperiment, 3)

Starting the Experiment

The experiment is now ready and can be started like any other experiment.

  • C++
    QObject::connect(tracker, &AisDeviceTracker::newDeviceConnected, [=](const QString& deviceName) {
    qDebug() << "New Device Connected: " << deviceName;
    auto& handler = tracker->getInstrumentHandler(INSTRUMENT_NAME);
    connectSignals(handler);
    AisErrorCode error = handler.uploadExperimentToChannel(CHANNEL, customExperiment);
    if (error) {
    qDebug() << error.message();
    return 0;
    }
    error = handler.startUploadedExperiment(CHANNEL);
    if (error) {
    qDebug() << error.message();
    return 0;
    }
    });
    AisErrorCode error = tracker->connectToDeviceOnComPort(COMPORT);
    if (error != error.Success) {
    qDebug() << error.message();
    return 0;
    }
  • Python
    def startExperiment():
    handler = tracker.getInstrumentHandler(INSTRUMENT_NAME)
    connectSignals(handler)
    error = handler.uploadExperimentToChannel(CHANNEL, customExperiment)
    if error.value() != AisErrorCode.Success:
    print(error.message())
    app.quit()
    error = handler.startUploadedExperiment(CHANNEL)
    if error.value() != AisErrorCode.Success:
    print(error.message())
    app.quit()
    tracker.newDeviceConnected.connect(startExperiment)
    error = tracker.connectToDeviceOnComPort(COMPORT)
    if error.value() != AisErrorCode.Success:
    print(error.message())
    sys.exit()

See the full example here

Now that we have seen how create complex custom experiments, lets move on to the next example, where we will utilize manual mode operations to provide real-time control of the Squidstat.