quartiq / booster

Firmware for the Sinara Booster RF amplifier
Apache License 2.0
13 stars 1 forks source link

document calibration #107

Open hartytp opened 3 years ago

hartytp commented 3 years ago

The calibration script doesn't have enough documentation to be used as is. I think I can figure it out from the issues (see conversation from https://github.com/quartiq/booster/issues/104#issuecomment-747569176) but a few sentences to describe the process would make life much easier.

hartytp commented 3 years ago

Note to self: the term "transforms" is not intuitively obvious to me. AFAICT it refers to the linear-in-dB mapping from input/output power in dBm (x) to detector reading in V (or LSB?) (y). We thus have y=ax+b.

Since the firmware does not expose the detector voltage to the user (wouldn't it be useful to expose this?), only the inferred powers, we need to begin by reading out the current values of the coefficients a and b, from which we can back out the detector voltage. Solving, we find that if input/output powers x0 and x1 are applied, resulting in the firmware reading out powers of p0 and p1, the new coefficients a_f and b_f are related to the old coefficients a_i and b_i by: a_f = a_i *(p0-p1)/(x0-x1) and similarly for the b coefficients (offsets).

hartytp commented 3 years ago

AFACIT, the calibration tool doesn't currently do any of that maths for the user. If a new "transform" (consisting of a slope + offset in units of V/dBm and V respectively?) is not specified, it prints out the current coefficients, otherwise it writes new ones.

This is all sufficiently non-obvious that it needs proper documentation. However, it might be easier to make the tool itself a little more user-friendly (e.g. take in x0, P0 and x1, P1 instead).

We should also make recommendations for sensible values of x0 and x1 (and should ask TS/CTI to use those same values for consistency).

hartytp commented 3 years ago

NB the expression I get for the slope looks non-equivalent to the one @jordens posted here but I may just be misunderstanding his terminology (or making a silly maths slip...) Either way, it will hopefully become obvious once I run the cal.

For completeness I have:

y0 = aP0 + b = a`x0+b`
y1 = aP1 + b = a`x1 + b`

aP0 + b - a`x0 = b = aP1 + b - a`x1
(aP0 + b) - (aP1 + b) = a`(x0-x1)
a` = a(P0-P1)/(x0-x1)

For the offset I get

y0 = aP0 + b = a`x0+b`
y1 = aP1 + b = a`x1 + b`

(aP0+b-b')/x0 = a' = (aP1+b-b')/x1
x1*(aP0+b-b') = x0*(aP1+b-b')
x1*(aP0+b) - x1b' = x0*(aP1+b)-x0*b'
a*(x0*P1 - x1*P0) + b*(x0-x1) = b'*(x0-x1)
a*(x0*P1 - x1*P0)/(x0-x1) + b = b'
hartytp commented 3 years ago

The defaults seem to be: Channel 7: InputPowerTransform slope = 42.857143, offset = -26.699999 Channel 0: OutputPowerTransform slope = 28.571428, offset = -5.799999 Channel 0: ReflectedPowerTransform slope = 42.857143, offset = -5.799999

Where did these come from? Were they calculated on the basis of nominal circuit values to give something sensible?

What's the recommended procedure for calibrating the reflected power. IIRC we're really not aiming for something accurate here so just a rough calibration for safety purposes. Are the default values expected to be good enough for that?

hartytp commented 3 years ago

Let's have a go then...

input power is -20dBm (-18.9dBm on a synth at 100MHz, expect ~+20dBm output given the 40dB gain) gives: input_power:-1.0368036e1, output_power = 2.1114285e1. Measured output power is -9.35dBm + 30dBm = +20.65dBm (G=40.65dB) input power is -10dBm (-8.9dBm synth) gives: input_power:1.207546e1,output_power:3.0285713e1. Measured output power is -0.11dBm + 30dBm = +29.9dBm (G=39.9dB)

Looks like the default for the output power is pretty sensible but the input is quite far off.

hartytp commented 3 years ago

For ~1W output, the reflected power is coming out as reflected_power:1.5542858e1 (i.e. +15dBm) so ~-30dBc output. That's not obviously implausible...

Edit: this is just a sanity check on the default (uncalibrated) value being something sensible.

hartytp commented 3 years ago

Okay, the equations I posted above give garbage, but the ones @jordens posted in that issue seem to give sensible results, so I guess I haven't understood how these transforms are intended to functions. Nonetheless, I think I can now get on with calibrating the device.

hartytp commented 3 years ago

NB

  1. Don't try to calibrate the input detector with the interlock tripped since this seems to add a ~0.3dB error (presumably VSWR-related due to the reflective switch)
  2. The input detector settings on the channel I calibrated ended up being: Channel 0: InputPowerTransform slope = 19.09557361295228, offset = -27.276924682322218 compared with the default of Channel 0: InputPowerTransform slope = 42.857143, offset = -26.699999. Might be worth looking at the default value for the input detector slope.
hartytp commented 3 years ago

Here is the hacky code I used to calculate the calibration data to save. NB I didn't bother with the reflected power yet. Hopefully the default values will be accurate enough for my purposes (the output detector looked pretty good without calibration on the one channel I looked at); next time I'm testing Booster I'll use a 3dB attenuator or so to create some VSWR to check.

# Input power
old_slope = 42.857143  # V/dB?
old_offset = -26.699999  # V?

x0 = -20  # dBm
x1 = -10  # dBm
p0 = -2.0046154e1
p1 = -9.753845e0

new_slope = old_slope*(x0 - x1)/(p0 - p1)
new_offset = (x0 + x1 - new_slope/old_slope*(p0 + p1 - 2*old_offset))/2
print("input power:", new_slope, new_offset)

# Output power
old_slope = 28.571428  # V/dB?
old_offset = -5.799999  # V?

x0 = +20.65  # dBm
x1 = +29.9  # dBm
p0 = 2.1114285e1
p1 = 3.0285713e1

new_slope = old_slope*(x0 - x1)/(p0 - p1)
new_offset = (x0 + x1 - new_slope/old_slope*(p0 + p1 - 2*old_offset))/2
print("output power:", new_slope, new_offset)
hartytp commented 3 years ago

Channel 0: OutputPowerTransform slope = 28.571428, offset = -5.799999

From https://github.com/quartiq/booster/blob/862ce55d6c75e97ae2b1329ecbe1e1dc8a0cd455/src/settings/channel_settings.rs#L33-L48

So the expected transformation is: P_out[dBm] = 28.6dBm/V * V_adc - 5.8dB.

My calibration gave: P_out = 28.8dBm/V * V_adc -6.494859775380661dB. So, by way of example. if we actually have P_out=33dBm then V_adc = (33dBm + 6.5dB)/28.8dBm/V=1.37V. The nominal calibration would then give 33.4dBm so within 0.5dB. That feels well within spec for the various parts.

hartytp commented 3 years ago

For the input, the nominal is P_in[dBm] = 42.857143 dBm/V * V_adc - 26.699999 dB

@ryan-summers is there an operator precedence issue here? We want 1/(1.5*0.035V/dB) = 19dB/V but we seem to be getting 42.86dB/V = 1.5/0.035V/dBm.

hartytp commented 3 years ago

Nope, not that, just an out of date release... https://github.com/quartiq/booster/blob/df89069a61faa4c8e78a248ec4fd217bd9995606/src/settings/channel_settings.rs#L46

@ryan-summers please do flag if releases are way out of date before I spend time debugging issues....

This may also explain the issue I saw with the interlock thresholds.

jordens commented 3 years ago

Summary AFAICT: Setting and getting the transforms is documented as are the transforms themselves. Computing new calibrated transforms for the user or aiding them in choosing test values isn't.

hartytp commented 3 years ago

Summary AFAICT: Setting and getting the transforms is documented as are the transforms themselves

Where are the transforms documented? Do you mean the inline comments, or did I miss something?

Computing new calibrated transforms for the user or aiding them in choosing test values isn't.

Yep.

jordens commented 3 years ago

The help of booster_calibrate_power.py and the API in booster.py. We should add the actual transform expression power_dbm = slope*input_volt + offset to that help string.

Computing new calibrated transforms for the user or aiding them in choosing test values isn't.

Yep.

To be clear: I don't consider that critical. But as always PRs welcome.

hartytp commented 3 years ago

To be clear: I don't consider that critical. But as always PRs welcome.

ryan-summers commented 3 years ago

Nope, not that, just an out of date release...

https://github.com/quartiq/booster/blob/df89069a61faa4c8e78a248ec4fd217bd9995606/src/settings/channel_settings.rs#L46

@ryan-summers please do flag if releases are way out of date before I spend time debugging issues....

Sorry for this - that was one of the few bugs that was patched after v0.1.0 was generated and has not yet made it into a new release. You can view the changelog from the current mainline to a release by clicking on the "X commits to develop since this release" under the Releases page: https://github.com/quartiq/booster/releases

Unfortunately, this change appears to be listed at the very bottom of the change set.

hartytp commented 3 years ago

Don't worry about it. Rust makes building from source so easy that I should probably have just built my own binary rather than using the release anyway.

HarryMakes commented 2 years ago

@hartytp Hi, I appreciate that you shared your notes on the calibration procedures.

I noted that you did not calibrate the reflected power transform. If my understanding is right, when we apply some high-power 50 ohm load plus a short cable at the output, in practice there should still be power reflected back to the transmitter, but the amount should be at minimal.

If we remove the load and cable, using the uncalibrated reflected power readings before and after unplugging the load, can we actually infer the calibrated reflected power with open-circuit load, without the need to probe the output at all? I am taking that forward_power = reflected_power + output_power with closed-circuit load, and forward_power = reflected_power with open-circuit load.

Or alternatively, can we still consider the calibration valid if we assume output_power in presence of the 50 ohm load (and probe) equals reflected_power in open-circuit? In that case, we can simply unplug everything from the RF output, and then take the uncalibrated reflected power readings (as x0, x1), and plug the target output power value (p0, `p1) in the equations to find the new slope and offset.

In any case, I get that the output has better not be probed without a high-power load.

HarryMakes commented 2 years ago

No, sorry I made a wrong statement. The output_power value actually corresponds to the forward power (as the ADL5904 RF detector takes the RF signal from the "CPL F" pin of the SYDC-20-62HP+ coupler and reports its Vrms level).

So, when we probe the output with a dummy load and take the measurement as output_power, we have already assumed reflected_power = 0, and thus the forward power equals the measured output_power. When we disconnect everything from the output SMA, all the forward power is reflected, so we can use the output_power value as reflected_power and recalculate the reflected power transform. In the end, we should expect that, given open-circuit load, the calibrated output_power should be equal or close to the calibrated reflected_power.

If there's some flaw in my logic, I'm all ears. Thanks!

hartytp commented 2 years ago

So, when we probe the output with a dummy load and take the measurement as output_power, we have already assumed reflected_power = 0, and thus the forward power equals the measured output_power. When we disconnect everything from the output SMA, all the forward power is reflected, so we can use the output_power value as reflected_power and recalculate the reflected power transform. In the end, we should expect that, given open-circuit load, the calibrated output_power should be equal or close to the calibrated reflected_power.

Roughly.

This is all from memory and I haven't played with Booster for a while so I might be wrong (others should feel free to comment), but IIRC...

  1. The detectors + couplers are actually pretty accurate even without calibration. In particular, the absolute uncalibrated accuracy is broadly comparable to other factors like frequency / temperature / power dependencies / loss in cabling / impact of VSWR / etc so, depending on what users want for their application, calibration may or may not actually make things better. As a result, I concluded that it's generally not worth doing any calibration at all; just use the numbers from the datasheet and it's good enough. Booster was never intended as a precision piece of T&M equipment, just to give some rough diagnostics and it does that fine without cal.
  2. You're assuming perfect directivity in the couplers. IIRC in practice they don't behave the way you've described. e.g. the measured output power varies with the VSWR. If you start running Booster into significantly mismatched loads, the power measurements become unreliable.
  3. The reflected power was mainly intended as a "nice to have" rather than a precise diagnostic. It's accurate enough to do things like get rough data out on S21 from a modulator, but I wouldn't trust it for more than that