g4ixt / QtTinySA

A Python 'TinySA' GUI programme using Qt5 and PyQt5

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Better calculation of "scanraw" timeout

Ho-Ro opened this issue · comments

commented

Ian,
My 1st heuristic approach was to pessimistic, in the meantime I did some timing checks and improved the calculations. Please mind that this was done on my tinySA3 a.k.a. tinySA Basic.
You should check with your tinySA4 a.k.a. tinySA Ultra, it can take an eternity at RBW = 0.2 KHz.
My checks:

  • I set RBW to auto and then increased the frequency range while watching the RBW reading on the tinySA's display. I found a fairly linear dependence between frequency range and RBW of about 7 kHz per 1 MHz range.
  • The time for a scan is linearly dependent on the frequency range and quadratically dependent on the reciprocal of the RBW.
  • Scan time is doubled when spur removal is activated.
  • Other settings also may increase the scan time.
  • The number of scan points hardly plays a role, it only occurs as USB transmission time, max. 1-2 ms per measured value.
  • 20 MHz scan range with RBW = 3 kHz has a duration of about 83 seconds, so i chose the heuristic constant to 20e3, this gives an overall timeout of 111 s.
  • As tinySA3 as well as tinySA4 transfer blocks of 20 values the timeout must be divided by the number of blocks, i.e. points / 20.

Have fun
Martin

    def sweepTimeout(self, f_low, f_high):  # freqs are in Hz
        if self.rbw == 'auto':
            # rbw auto setting from tinySA: ~7 kHz per 1 MHz scan frequency span
            # TODO: check for tinySA Ultra
            rbw = (f_high - f_low) * 7e-6
        else:
            rbw = float(self.rbw)

        # lower / upper limit
        if rbw < float(resBW[1]):
            rbw = float(resBW[1])
        elif rbw > float(resBW[-1]):
            rbw = float(resBW[-1])
        if self.rbw == 'auto':
            logging.info(f'rbw (auto) = {rbw} kHz')

        # timeout can be very long - use a heuristic approach
        # 1st summand is the scanning time, 2nd summand is the USB transfer overhead
        # TODO: times are for tinySA, check for tinySA Ultra if "20e3" is also correct
        timeout = ((f_high - f_low) / 20e3) / (rbw ** 2) + self.points / 500
        if self.spur: # scan time is doubled
            timeout *= 2
        # transfer is done in blocks of 20 points, this is the timeout for one block
        self.timeout = timeout * 20 / self.points + 1 # minimum is 1 second
        logging.info(f'sweepTimeout = {self.timeout} s')
commented

Hi Martin,

Noted about scan points number having little impact. Using QtTinySA with my SA4, desktop PC, running from a terminal (3D disabled):

At 3kHz RBW 20MHz scan with 290 points takes around 25s for 80MHz fstart.
At 1240MHz start with SPUR=auto it takes 98s and with SPUR=off it takes 49s.

At 1kHz RBW 20MHz scan with 290 points takes around 170s for 80MHz fstart.

At 0.2kHz RBW with a 1MHz scan starting at 80MHz takes 185s
At 0.2kHz RBW with a 1MHz scan starting at 1240MHz with SPUR=auto it takes 370s and with SPUR=off it takes 187s.

Does the timeout value actually matter so long as it's big enough? Provided the expected number of bytes is received it's not invoked, is my understanding. Perhaps an alternative would be to set it high and error-trap a short reply?

I did some measurements yesterday of the serial transaction times which was interesting, using QElapsedTimer nsecsElapsed, around the 'dataBlock = (serialPort.read(3)) # read a block of 3 bytes of data'. I plotted some charts:

100kHz_rbw_scantime_1
100kHz_rbw_scantime_2
100kHz_rbw_scantime_3
30kHz_rbw_scantime_1
![30kHz_rbw_scantime_2](https://git
30kHz_rbw_scantime_3
hub.com/g4ixt/QtTinySA/assets/76836635/1e13ee7b-e9ad-4f52-bc1a-9ced2f004801)

Every 20th read takes a long time - this is expected I guess because of the buffer size. But a lot of intermediate readings take more than 10x the time of the (majority) fastest. The 3 different graphs show the 20-block read times, then exclude those, then the long intermediate times, them the really fast ones. Do you know why this would be?

My original thought on serial port timeout was to set it initially using your algorithm on 'run' and then to measure the highest transaction time during 1 full scan, then to reduce the timeout to (say) 120% of the measured value.

By the way I tried building a Linux executable using pyinstaller and it came out at 600Mb. It won't run but gives a permissions error. I haven't investigated further but its permissions show as exectutable and me as owner.

Fun!

Ian

commented

x axis on charts is 'index' number and y axis is time in mS

commented

Thank you for your measurements, the Ultra is faster than the Basic - I should get a new toy for the wintertime :)

Does the timeout value actually matter so long as it's big enough? Provided the expected number of bytes is received it's not invoked, is my understanding.

Yes, but it should be as short as possible to detect a deadlock of the transfer.

Perhaps an alternative would be to set it high and error-trap a short reply?

No - normally an error means no response when expected to get data.

Every 20th read takes a long time - this is expected I guess because of the buffer size.

Exactly.

But a lot of intermediate readings take more than 10x the time of the (majority) fastest. The 3 different graphs show the 20-block read times, then exclude those, then the long intermediate times, them the really fast ones. Do you know why this would be?

Two reasons come to my mind, USB latences because it is a shared bus and also the threads of the tiny firmware are running on only one core, so the USB transfer may be delayed by another thread.

My original thought on serial port timeout was to set it initially using your algorithm on 'run' and then to measure the highest transbaction time during 1 full scan, then to reduce the timeout to (say) 120% of the measured value.

Interesting approach - but since Erik has assured that the scanraw should be interruptible, I would not sacrifice too much time - better to wait for its correction. Then a hanging transmission can be stopped from your program.

commented

included new timeout fn in code