fritzing / fritzing-app

Fritzing desktop application
http://fritzing.org
Other
4.06k stars 838 forks source link

Iterate simulator analysis / show progress windows with cancel button #4122

Open KjellMorgenstern opened 8 months ago

KjellMorgenstern commented 8 months ago

This might wait for quite a long time, and timeout, many devices, especially when using transient analysis.

    int elapsedTime = 0, simTimeOut = 3000; // in ms
    while (m_simulator->isBGThreadRunning() && elapsedTime < simTimeOut) {
        QThread::usleep(1000);
        elapsedTime++;
    }

At least, users should have a choice to increase the timeout. Better: Can we do the calculation stepwise , or fetch intermediate results?

failiz commented 8 months ago

Yes, you can fetch intermediate results. That is not a problem, see this minimum example:

while (m_simulator->isBGThreadRunning() && elapsedTime < simTimeOut) {
        std::cout << "-------- ITER " << elapsedTime << " ------------" << std::endl;
        auto timeInfo = m_simulator->getVecInfo(QString("time").toStdString());
        std::cout << "Time (" << timeInfo.size() << " points): ";
        for (unsigned int i=0; i<timeInfo.size(); i++){
            std::cout << timeInfo[i] << " ";
        }
        std::cout << std::endl;
        QThread::usleep(1000);
        elapsedTime++;
    }
    std::cout << "-------- SIM END ------------" << std::endl;
    auto timeInfo = m_simulator->getVecInfo(QString("time").toStdString());
    std::cout << "Time (" << timeInfo.size() << " points): ";
    for (unsigned int i=0; i<timeInfo.size(); i++){
        std::cout << timeInfo[i] << " ";
    }

However, it requires that we modify the code to take into account that the simulation may not be ready and slow down the effects of the simulation. For example, trying to get the voltage at time 1.5s when ngspice has just given values until 1.49s.

failiz commented 8 months ago

By the way, we are using the asyncronous mode. We could also change to the syncronous mode. See chapter 9.4. GENERAL REMARKS ON USING THE API and 19.4.3 Accessing data of the ngspice manual

"19.4.3.1 Synchronous access

The callback functions SendInitData (19.3.3.5) and SendData (19.3.3.4) allow access to simulator output data synchronized with the simulation progress. Each time a new plot is generated during simulation, e.g. when a sequence of op, ac and tran is used or commands like linearize or fft are invoked, the callback SendInitData is called by ngspice. Immediately after setting up the vector structure of the new plot, the function is called once. Its parameter is a pointer to the structure vecinfoall (19.3.1), which contains an array of structures vecinfo, one for each vector in the actual plot. You may simply use vecname to get the name of any vector. This time the vectors are still empty, but pointers to the vector structure are available. Each time a new data point (e.g. time value and simulation output value(s)) is added to the vector structure of the current plot, the function SendData is called by ngspice. This allows you to immediately access the simulation output synchronized with the simulation time, e.g. to interface it to a runtime plot or to use it for some controlled simulation by stopping the simulation based on a condition, altering parameters and resume the simulation. SendData returns a structure vecvaluesall as parameter, which contains an array of structures vecvalues, one for each vector. Some code to demonstrate the callback function usage is referenced below (19.5).

19.4.3.2 Asynchronous access During simulation, while the background thread is running, or after it is finished, you may use the functions ngSpice_CurPlot (19.3.2.7), ngSpice_AllPlots (19.3.2.8), ngSpice_AllVecs (19.3.2.9) to retrieve information about vectors available, and function ngGet_Vec_Info (19.3.2.5) to obtain data from a vector and its corresponding scale vector. The timing of the caller and the simulation progress are independent from each other and not synchronized. Again some code to demonstrate the callback function usage is referenced below (19.5)."

KjellMorgenstern commented 7 months ago

I think right now we wait until the calculation is fully finished, so it doesn't matter if we use asynchronous or synchronous mode. But since we already use async mode, can't we just fetch the data every second or so, and then run the animation? Of course it is not trivial: If the calculation is slower than the animation, it will result in pauses during the animation. If the calculation is faster, some buffer will fill up? Anyway, this should allow the calculation to run on a different thread (and CPU core) which is desirable.

We need to keep the buffer small, since we want the simulation to be interactive.

failiz commented 7 months ago

Fixed in https://github.com/fritzing/fritzing-app/pull/4076/commits/234eb9a6eed759042f5407dd83aea56c89956a98 It seems to be working well, but I did not test it much. Notice that this is NOT interactive. Interactive simulations are more complex as we have to halt the analysis, change parameters in the spice netlist and resume the analysis. In addition, we need to keep the max sim time to a large number and slow down the analysis if it goes too fast (by halting and resuming the analysis). Let's leave that for the next release and not for 1.0.3.

failiz commented 2 months ago

Not sure if this is in 1.0.3, but at least should be marked as solved