Calibration Troubles with Airspy R2 #airspyr2


BHall
 

Hello,

I ran the Airspy Calibration Tool against a strong, local control channel in my area (852.6625), and the tool set the PPM on my Airspy R2 to 2.81:



Unfortunately, in SDR#, it's off significantly (should probably be around -2.7 PPM):



Is there any way to set the PPM value manually?

Thanks!


jdow
 

Have you any information about the precise frequency source you used for calibration? NFM signals, in general, are not required to be particularly precise.
{o.o}

On 20211130 15:40:36, BHall wrote:
Hello,

I ran the Airspy Calibration Tool against a strong, local control channel in my area (852.6625), and the tool set the PPM on my Airspy R2 to 2.81:



Unfortunately, in SDR#, it's off significantly (should probably be around -2.7 PPM):



Is there any way to set the PPM value manually?

Thanks!


Airspy US
 

Adding to what Joanne said, not only are they often not precise in frequency, but data frequencies rarely transmit on-frequency carriers. They are usually above or below the frequency as shown in your image. The calibration tool probably used one of the peaks as a reference which would be off by several kHz (+/- 1.8 kHz for P25). You need a constant non-shifting carrier for calibration. The results of using shifting carriers are what you are experiencing: a unit that is calibrated a couple kHz off frequency. 

You can try to re-calibrate it to an ATSC pilot carrier if you have a DTV channel in your area. That will be close to the precision your unit shipped with if it came from us, as we calibrate the units we sell to a GPS reference standard. The pilot will be 309.441 kHz above the bottom of the channel (for example, 174.309441 MHz for channel 7). Those are usually fairly precise. 

---------
Airspy.US
Your USA source for quality SDR products!
www.Airspy.US

NOTE: This email address is NOT MONITORED. If you want to email us use our normal email address. 

On Nov 30, 2021, at 6:41 PM, BHall <bhall007@...> wrote:

Hello,

I ran the Airspy Calibration Tool against a strong, local control channel in my area (852.6625), and the tool set the PPM on my Airspy R2 to 2.81:

<Airspy_CalibrationTool.png>


Unfortunately, in SDR#, it's off significantly (should probably be around -2.7 PPM):

<AirspyR2_Detuned.png>


Is there any way to set the PPM value manually?

Thanks!


Airspy US
 

And no, there is no way to enter a specific calibration value for the R2/Mini. 

---------
Airspy.US
Your USA source for quality SDR products!
www.Airspy.US

NOTE: This email address is NOT MONITORED. If you want to email us use our normal email address. 

On Nov 30, 2021, at 6:41 PM, BHall <bhall007@...> wrote:

Hello,

I ran the Airspy Calibration Tool against a strong, local control channel in my area (852.6625), and the tool set the PPM on my Airspy R2 to 2.81:

<Airspy_CalibrationTool.png>


Unfortunately, in SDR#, it's off significantly (should probably be around -2.7 PPM):

<AirspyR2_Detuned.png>


Is there any way to set the PPM value manually?

Thanks!


BHall
 

Thanks all for the replies. Situations like this are probably why the Airspy Calibration Tool is no longer shipped with the most recent SDR# distributions. I just don't have an accurate, reliable enough signal here locally over the air to be able to reliably calibrate it without a GPSDO. 73's


jdow
 

You do not have a digital TV station in sight of your antenna?
{^_^}

On 20211130 20:38:20, BHall wrote:
Thanks all for the replies. Situations like this are probably why the Airspy Calibration Tool is no longer shipped with the most recent SDR# distributions. I just don't have an accurate, reliable enough signal here locally over the air to be able to reliably calibrate it without a GPSDO. 73's


David J Taylor
 

On 01/12/2021 04:38, BHall wrote:
Thanks all for the replies. Situations like this are probably why the Airspy
Calibration Tool is no longer shipped with the most recent SDR# distributions.
I just don't have an accurate, reliable enough signal here locally over the air
to be able to reliably calibrate it without a GPSDO. 73's
Nice Christmas present for you:

http://www.leobodnar.com/shop/index.php?main_page=product_info&products_id=301

https://v3.airspy.us/product/lb-gpsdo-mini/

It's a very useful tool - outputs 400 Hz to 810 MHz, GPS locked.

73,
David GM8ARV
--
SatSignal Software - Quality software for you
Web: https://www.satsignal.eu
Email: david-taylor@blueyonder.co.uk
Twitter: @gm8arv


BHall
 

Sounds good, thanks!

Brian


On Wed, Dec 1, 2021 at 4:45 AM David J Taylor via groups.io <david-taylor=blueyonder.co.uk@groups.io> wrote:
On 01/12/2021 04:38, BHall wrote:
> Thanks all for the replies. Situations like this are probably why the Airspy
> Calibration Tool is no longer shipped with the most recent SDR# distributions.
> I just don't have an accurate, reliable enough signal here locally over the air
> to be able to reliably calibrate it without a GPSDO. 73's

Nice Christmas present for you:

   http://www.leobodnar.com/shop/index.php?main_page=product_info&products_id=301

   https://v3.airspy.us/product/lb-gpsdo-mini/

It's a very useful tool - outputs 400 Hz to 810 MHz, GPS locked.

73,
David GM8ARV
--
SatSignal Software - Quality software for you
Web: https://www.satsignal.eu
Email: david-taylor@...
Twitter: @gm8arv






Phil Karn
 

Question: did this calibration tool account for the step size of the fractional-N synthesizer in the tuner? They can be hundreds of Hz off even with a perfect reference.

I have the Airspy R2, Airspy HF+, Funcube Pro+, HackRF and RTL-SDR. None of them compensate for this. They all pretend to tune in exact 1Hz steps. Most SDR applications could easily correct for the problem in subsequent frequency conversions if they only knew the true tuner frequency, but there's no way to know.

I've worked out these corrections for the abovementioned SDRs and put the corrections in my own application code, but this is very inelegant. Each support library needs an accurate frequency readback function, so I've implemented them for the Airspy and RTL-SDR libraries. Would people be interested in my additions?


 

yes.

thanks

Hank


On 12/14/2021 1:13 AM, Phil Karn wrote:
Question: did this calibration tool account for the step size of the fractional-N synthesizer in the tuner? They can be hundreds of Hz off even with a perfect reference.

I have the Airspy R2, Airspy HF+, Funcube Pro+, HackRF and RTL-SDR. None of them compensate for this. They all pretend to tune in exact 1Hz steps. Most SDR applications could easily correct for the problem in subsequent frequency conversions if they only knew the true tuner frequency, but there's no way to know.

I've worked out these corrections for the abovementioned SDRs and put the corrections in my own application code, but this is very inelegant. Each support library needs an accurate frequency readback function, so I've implemented them for the Airspy and RTL-SDR libraries. Would people be interested in my additions?


jdow
 

AirSpy does not include interpolation on its step size the last I knew.
{o.o}

On 20211214 00:13:53, Phil Karn wrote:
Question: did this calibration tool account for the step size of the fractional-N synthesizer in the tuner? They can be hundreds of Hz off even with a perfect reference.

I have the Airspy R2, Airspy HF+, Funcube Pro+, HackRF and RTL-SDR. None of them compensate for this. They all pretend to tune in exact 1Hz steps. Most SDR applications could easily correct for the problem in subsequent frequency conversions if they only knew the true tuner frequency, but there's no way to know.

I've worked out these corrections for the abovementioned SDRs and put the corrections in my own application code, but this is very inelegant. Each support library needs an accurate frequency readback function, so I've implemented them for the Airspy and RTL-SDR libraries. Would people be interested in my additions?


Phil Karn
 
Edited

Here's the current version of the routine I use to convert requested frequency (an integer) into a true frequency (a double) assuming a perfect frequency reference. This applies to the R820T tuner frequency, which is 5 MHz above the requested frequency when I/Q format data is requested from the library driver.

My most recent change is in the computation of the partial step offset - it seems to depend on the VCO range divider. My documentation of the R820T tuner is very incomplete -- it doesn't include any of this partial offset stuff -- so all this is empirical. If anyone wants to check this out, I'd really like to see your results. --Phil

// For a requested frequency, give the actual tuning frequency
// Many thanks to Youssef Touil <youssef@...> who gave me most of it
// This "mostly" works except that the calibration correction inside the unit
// shifts the tuning steps, so the result here can be off one
// Not easy to fix without knowing the calibration parameters.
// Best workaround is a GPSDO, which disables the correction
double true_freq(uint64_t freq_hz){
  const int VCO_MIN=1770000000u; // 1.77 GHz
  const int VCO_MAX=(VCO_MIN << 1); // 3.54 GHz
  const int MAX_DIV = 5;

  // Clock divider set to 2 for the best resolution
  const uint32_t pll_ref = 25000000u / 2; // 12.5 MHz
 
  // Find divider to put VCO = f*2^(d+1) in range VCO_MIN to VCO_MAX
  //          MHz             step, Hz
  // 0: 885.0     1770.0      190.735
  // 1: 442.50     885.00      95.367
  // 2: 221.25     442.50      47.684
  // 3: 110.625    221.25      23.842
  // 4:  55.3125   110.625     11.921
  // 5:  27.65625   55.312      5.960
  int8_t div_num;
  for (div_num = 0; div_num <= MAX_DIV; div_num++){
    uint32_t vco = freq_hz << (div_num + 1);
    if (VCO_MIN <= vco && vco <= VCO_MAX)
      break;
  }
  if(div_num > MAX_DIV)
    return 0; // Frequency out of range
 
  // PLL programming bits: Nint in upper 16 bits, Nfract in lower 16 bits
  // Freq steps are pll_ref / 2^(16 + div_num) Hz
  // Note the '+ (pll_ref >> 1)' term simply rounds the division to the nearest integer
  uint32_t r = (((uint64_t) freq_hz << (div_num + 16)) + (pll_ref >> 1)) / pll_ref;
 
  // This is a puzzle; is it related to spur suppression?
  double offset = 0;
  switch(div_num){
  default: // 2, 1, 0
   case 3:
    offset = 0.25;
    break;
  case 4:
    offset = 0.5;
    break;
  case 5:
    offset = 1.0;
    break;
  }

  // Compute true frequency
  return ((double)(r + offset) * pll_ref) / (double)(1 << (div_num + 16));
}


Phil Karn
 

This is very strange. I just retried my frequency measurements with a different (older) Airspy R2 and configuration and found that the PLL offset is a constant 0.25 tuning steps over the entire range of the device!

In my experiments the other night I used a dual-output Leo Bodnar GPS clock to generate both the 10 MHz reference clock and the RF test signal for a recently purchased Airspy R2. Because they are generated by division from a common oscillator, I knew that the frequencies had to be exactly related. That's how I deduced that the PLL offsets varied over part of the tuning range. With that assumption, the RF signal phase was rock stable relative to the 10 MHz reference.

Tonight I used an older R2 and my regular 10 MHz station reference (from a different GPSDO, with a OCXO). I used the Leo Bodnar only to generate the RF test signals. This time the R2 PLL offset was a constant 0.25 steps over its entire tuning range. I saw only the slow, expected random walks in relative phase between the two independent GPS references.

I can't figure this out... Sure doesn't help that the documentation on the 820T/R860 is so sparse. Both Airspy R2s have the same firmware version, but perhaps the tuner chips aren't exactly the same. Back to my experiments...


jdow
 

You may be bumping into the RT820T2 chip's frequency synthesizer limitations. It's minimum step size is (substantially) above 1 Hz.

{^_^}

On 20211216 00:49:39, Phil Karn wrote:
This is very strange. I just retried my frequency measurements with a different (older) Airspy R2 and configuration and found that the PLL offset is a constant 0.25 tuning steps over the entire range of the device!

In my experiments the other night I used a dual-output Leo Bodnar GPS clock to generate both the 10 MHz reference clock and the RF test signal for a recently purchased Airspy R2. Because they are generated by division from a common oscillator, I knew that the frequencies had to be exactly related. That's how I deduced that the PLL offsets varied over part of the tuning range. With that assumption, the RF signal phase was rock stable relative to the 10 MHz reference.

Tonight I used an older R2 and my regular 10 MHz station reference (from a different GPSDO, with a OCXO). I used the Leo Bodnar only to generate the RF test signals. This time the R2 PLL offset was a constant 0.25 steps over its entire tuning range. I saw only the slow, expected random walks in relative phase between the two independent GPS references.

I can't figure this out... Sure doesn't help that the documentation on the 820T/R860 is so sparse. Both Airspy R2s have the same firmware version, but perhaps the tuner chips aren't exactly the same. Back to my experiments...


Phil Karn
 

I think this is different. Yes, the step sizes are substantially more than 1 Hz, and they do depend on the frequency range. I list them in the comments in the code snippet I posted earlier. Even in its lowest range, the step size is 5.96 Hz, increasing to 190.735 Hz in the highest (885 MHz and above). That's the purpose of my true_freq() routine; to take a requested frequency as an unsigned 64 bit integer (same as the device driver), find the 820T PLL divisor (consisting of an integer and fractional part) using the same formulas as in the Airspy firmware, and finally determine the true tuner frequency as a double precision floating point number.

When I first wrote that code it all worked as expected except that the actual frequencies were consistently 1/4 of a step higher than they should have been. E.g., at 146 MHz (where the step size is 23.842 Hz) the synthesizer was 23.842/4 = 5.96 Hz higher than calculated. This was true in every frequency range, so I simply added an empirical bias of 1/4 step. I then got results that exactly matched my measurements, at least within the accuracy of my GPSDO (in the millihertz range at TV channel 8).

I believe this 1/4 step bias is related to some arcane considerations about reducing synthesizer spurs for certain divisor values. That's fine, but it sure would be nice if it were documented somewhere.

But more recently, I saw evidence that the offset wasn't always 1/4 step, but varied with the step size. And then that went away when I tried a different configuration that should have given consistent results. Obviously there's something I don't understand about something...


jdow
 

I'm trying to remember the rtlsdr implementation details. If I recall correctly the computation must be done in the correct order to find the closest set of numbers to feed the chip. The  original code featured an overflow error, to boot. That was fixed.

One thing that exists with the rtlsdr dongles, at least, is the ability to change the nominal sample rate in the realtek chip. The front end had a much larger step size. Adjusting that IF frequency allowed about a 7 Hz frequency precision by fiddling both the R820 chip's synthesizer and the rt2832/2838 chip's synthesizer.

Note that the front end synthesizer will give you somewhat annoying results on some frequencies, typically when they are at small integer ratios away from multiples of the 28.8 MHz clock (on rtlsdr chips). It will spend a long time on one frequency then jump briefly to another giving an average frequency that is right on. There is dithering present that tries to deal with this. The dithering may not be such as to give precisely the correct average.

This might be related to your quarter step. However, you have something that works. So fix it at your own risk.

{^_-}

On 20211219 21:48:03, Phil Karn wrote:
I think this is different. Yes, the step sizes are substantially more than 1 Hz, and they do depend on the frequency range. I list them in the comments in the code snippet I posted earlier. Even in its lowest range, the step size is 5.96 Hz, increasing to 190.735 Hz in the highest (885 MHz and above). That's the purpose of my true_freq() routine; to take a requested frequency as an unsigned 64 bit integer (same as the device driver), find the 820T PLL divisor (consisting of an integer and fractional part) using the same formulas as in the Airspy firmware, and finally determine the true tuner frequency as a double precision floating point number.

When I first wrote that code it all worked as expected except that the actual frequencies were consistently 1/4 of a step higher than they should have been. E.g., at 146 MHz (where the step size is 23.842 Hz) the synthesizer was 23.842/4 = 5.96 Hz higher than calculated. This was true in every frequency range, so I simply added an empirical bias of 1/4 step. I then got results that exactly matched my measurements, at least within the accuracy of my GPSDO (in the millihertz range at TV channel 8).

I believe this 1/4 step bias is related to some arcane considerations about reducing synthesizer spurs for certain divisor values. That's fine, but it sure would be nice if it were documented somewhere.

But more recently, I saw evidence that the offset wasn't always 1/4 step, but varied with the step size. And then that went away when I tried a different configuration that should have given consistent results. Obviously there's something I don't understand about something...


Phil Karn
 

I started with the code snippets that Youssef gave me, then simplified them while getting the same results. It's actually pretty straightforward once you understand how the synthesizer works. That took a while because it's not well documented at all.

I've never seen the frequency jumping you describe on either the Airspy or the RTL-SDR, but that could be because I haven't tried the corner case frequencies you mention. I also haven't seen the frequency shifting you mention on the RTL-SDR; it behaves much the same as the Airspy. This isn't surprising since they use the same tuner. Again, I do not need the front end to give me exactly the frequency I request. It could be a few kilohertz off for all I care. I only need to know its actual frequency, whatever it is, so I can compensate in my own software downconverter.

I certainly understand dithering in ADCs but I have yet to see a good discussion of exactly what it is and does in a frequency synthesizer. I have never seen anything other than a fixed frequency from either the RTL-SDR or the Airspy once they've settled down; it's just that the fixed frequency you get is not exactly what you'd expect given the reference frequency and the divider settings. I suppose fractional-N synthesis is itself a form of dithering since the divisor is rapidly "dithered" between N and N+1 to give the actual frequency you want, but this is fast enough that the PLL loop filter takes this out to give the desired average. The mentions of "dithering" seem to refer to something else related to spur suppression.

Again here's the code I use to determine actual PLL frequency as a function of the PLL divisor 'r', a 32-bit integer:

int div_num; // integer between 0 and 5 inclusive, depending on frequency range
int const pll_ref = 12500000; // = 25 MHz / 2 for the Airspy R2
uint32_t r; // PLL divider: integer part in top 16 bits, fraction in lower 16 bits
double true_frequency = ((double)(r + 0.25) * pll_ref) / (double)(1 << (div_num + 16));

So one LSB in 'r' represents the minimum step size of the synthesizer, and my empirical addition of 0.25 steps to get the right result cannot be explained by any errors in the divisor computation, as they would have be multiples of a full step.




jdow
 

Tune one minimum step off from some critical frequencies and you'll see the effect. It's mentioned on rtlsdr.com as the reason it is so hard to make multiple dongles on the same clock behave as if they are on the same clock. (While the GPS phase II B synthesizer, 10.23 in 10.23+tiny delta out, can set to insanely small steps there are pernicious settings that are one minimum step away from an exact setting. It achieves steps between two frequencies it can generate with it's DDS component by effectively alternating between two frequencies such that the average is correct. In the bad settings this can become all too apparent, unfortunately.) (Would you believe something near 2 parts in 10^13 frequency selection?)

The dithering is may be spur suppression. I believe it is simply the effect of the least significant bits that are not actually generated directly by the synthesizer without the N and N-1 (or N+1) alternation which is worse when it is one count of N+/-1 and all the rest at N. For any other form of dithering I am out of the loop due to no documentation and not bothering to perform the serious deep dive to find it.

That math looks wrong. As far as I know the divisors are not 16 bit values.

This is the code in my rtlsdr code:

===8<---
    /* Calculate divider */

    for ( mix_div = 2, div_num = 0; mix_div < 64; mix_div <<= 1, div_num++ )
    {
        if (( freq_khz * mix_div ) >= vco_min )
            break;
    }

    //    The mix_div code above and values for vco_max and vco_min imply that
    //    without overrange the VCO frequency runs from 1750 to 3500 MHz. These
    //    numbers put limits on other numbers below. The full range is available
    //    regardless of mix_div. Thus the tune frequencies can go as high as 1750 +
    //    f_if or about 1756 with Oliver's code. The low end is about 21.3 Mhz

#if 0
    if ( m_rafael_chip == CHIP_R828D )
        vco_power_ref = 1;
    /*    mutability////
    rc = r82xx_read(priv, 0x00, data, sizeof(data));
    if (rc < 0)
        return rc;
    vco_fine_tune = (data[4] & 0x30) >> 4;
    */
    uint8_t vco_fine_tune = 2;

//    if ( CHIP_R828D )
//        vco_power_ref = 1;
//    else
//        vco_power_ref = 2;
    //    828  2  1
    //    oth  2  2
    if ( vco_fine_tune > vco_power_ref )    // vco_power_ref = 1 or 2.
        div_num = div_num - 1;
    else
    if ( vco_fine_tune < vco_power_ref )
        div_num = div_num + 1;
#else
    //    This is the short version of the above.
    if ( m_rafael_chip == CHIP_R828D )
        div_num = div_num - 1;
#endif


    rc = r82xx_write_reg_mask( 0x10, div_num << 5, 0xe0 );
    if ( rc < 0 )
        return rc;

    //    Remember that vco_freq is more or less constrained to the range of
    //    1750 to 3500 MHz above (and below actually).
    vco_freq = (uint64_t) freq * (uint64_t) mix_div;

    /*
     * We want to approximate:
     *  vco_freq / (2 * pll_ref)
     * in the form:
     *  nint + sdm / 65536
     * where nint,sdm are integers and 0 < nint, 0 <= sdm < 65536
     * Scaling to fixed point and rounding:
     *  vco_div = 65536*(nint + sdm/65536) = int( 0.5 + 65536 * vco_freq / (2 * pll_ref) )
     *  vco_div = 65536*nint + sdm         = int( (pll_ref + 65536 * vco_freq) / (2 * pll_ref) )
     */

    //    So 1991111 <= vco_div <= 3982222 in integers.
    //    Note this gives a step size of its own if you reverse the calculation.
    //    It's very close to 879 Hz. That's the VCO step size, though.
    //    Next we divide by 65536. Call this vco_divd.
    //    30.3819427490234375 <= vco_divd <= 60.763885498046875
    //    Of course this is a ridiculous number of decimal points. But it is useful
    //    for looking at the numbers below and some of the tests. I do not know where
    //    these come from. It appears to be ridiculous.
    //
    //    One thing comes out of this discussion. The sdm figure can theoretically
    //    go through its whole range 0..65535 for each step. It is effectively a
    //    divisor that makes the comparison frequency for the PFD equal to about
    //    879 Hz rather than the apparent "real" comparison frequency of 57.6 MHz.
    //    Of course, lock time would be way to long to make this resemble the real
    //    circuit.
        
    vco_div = ( pll_ref + 65536 * vco_freq ) / ( 2 * pll_ref );
    nint = (uint32_t) ( vco_div / 65536 );
    sdm = (uint32_t) ( vco_div % 65536 );

    // nb. it appears nint MUST be between 30 and 60. The test below seems silly.
    if (( nint < 13 )
    ||  ( m_rafael_chip == CHIP_R828D && nint > 127 )
    ||  ( m_rafael_chip != CHIP_R828D && nint > 76 ))
    {
        fprintf(stderr, "[R82XX] No valid PLL values for %u Hz!\n", freq);
        return -1;
    }

    ni = ( nint - 13 ) / 4;
    si = nint - 4 * ni - 13;

    if ( freq_out )
    {
        uint64_t actual_vco = (uint64_t) 2 * pll_ref * nint
                            + (uint64_t) 2 * pll_ref * sdm / 65536;
        *freq_out = (uint32_t) (( actual_vco + mix_div / 2 ) / mix_div );
    }

    rc = r82xx_write_reg( 0x14, ni + ( si << 6 ));
    if ( rc < 0 )
        return rc;
===8<---

{^_^}

On 20211220 16:29:16, Phil Karn wrote:

I started with the code snippets that Youssef gave me, then simplified them while getting the same results. It's actually pretty straightforward once you understand how the synthesizer works. That took a while because it's not well documented at all.

I've never seen the frequency jumping you describe on either the Airspy or the RTL-SDR, but that could be because I haven't tried the corner case frequencies you mention. I also haven't seen the frequency shifting you mention on the RTL-SDR; it behaves much the same as the Airspy. This isn't surprising since they use the same tuner. Again, I do not need the front end to give me exactly the frequency I request. It could be a few kilohertz off for all I care. I only need to know its actual frequency, whatever it is, so I can compensate in my own software downconverter.

I certainly understand dithering in ADCs but I have yet to see a good discussion of exactly what it is and does in a frequency synthesizer. I have never seen anything other than a fixed frequency from either the RTL-SDR or the Airspy once they've settled down; it's just that the fixed frequency you get is not exactly what you'd expect given the reference frequency and the divider settings. I suppose fractional-N synthesis is itself a form of dithering since the divisor is rapidly "dithered" between N and N+1 to give the actual frequency you want, but this is fast enough that the PLL loop filter takes this out to give the desired average. The mentions of "dithering" seem to refer to something else related to spur suppression.

Again here's the code I use to determine actual PLL frequency as a function of the PLL divisor 'r', a 32-bit integer:

int div_num; // integer between 0 and 5 inclusive, depending on frequency range
int const pll_ref = 12500000; // = 25 MHz / 2 for the Airspy R2
uint32_t r; // PLL divider: integer part in top 16 bits, fraction in lower 16 bits
double true_frequency = ((double)(r + 0.25) * pll_ref) / (double)(1 << (div_num + 16));

So one LSB in 'r' represents the minimum step size of the synthesizer, and my empirical addition of 0.25 steps to get the right result cannot be explained by any errors in the divisor computation, as they would have be multiples of a full step.