David Megginson wrote:
Julian Foad writes:

> I noticed that the radios had nav. freq. range 108.00 to 117.95 but com. > freq. 0 to 140; this should be 118 to 140. But while playing with that > I noticed that the wrapping is a bit unpredictable. With (min=118, > max=140, step=1, wrap=true) adjusting it up and down, it sometimes skips > 118 and sometimes skips 140. For the nav. frequencies, my 1991 UK > Pooley's Flight Guide confirms that the range is 108.00 to 117.95 > inclusive. But the current implementation that specifies (min=108.00, > max=117.95, step=0.05, wrap=true) tends to cycle (117.85, 117.90, > 108.00, 108.05) skipping 117.95.

Yes, it was a mess. I've done some refactoring of the built-in
property-adjust and property-multiply commands, and things work better
now. I added a 'mask' argument that can take a value "decimal" to
modify only the decimal part or "integer" to modify only the integer
part. That means that the radio tunes more like a real KX-155 (or
similar), at least if your panel is using navcom-radio.xml -- the left
button adjusts the decimal part and the right button adjusts the
integer part. I've also fixed the COM radio frequency range in that
file.
That's good to hear.


 Wrapping should also be simpler and more predictable.
Ah, well ...

It's good to see it factored out into a single place (limit_value).

But I don't think it's predictable because floating-point imprecision can still break it (118.025 - 0.025 is sometimes a bit less than 118.000 and therefore becomes 135.975).

Also, different kinds of "wrap" are wanted in different situations:

(1) A circular value (e.g. heading, 0 to 360 degrees). The "min" value is considered to have the same meaning as the max value (both mean "North"). In this case the old behaviour, addition modulo 360, was correct and appropriate (so that 358 degrees plus a step of 5 becomes 003 degrees), giving a smooth rotation. Floating-point imprecision is not a problem: it doesn't matter whether 359 + 1 becomes 359.99999 or wraps to 000.00001, because they mean the same thing.

In case (1) it is appropriate for the controlled range to be "min <= x < max" (not "min <= x <= max"), so that the specified "min" and "max" values are independent of the adjustment step size. Otherwise you would have to specify max=359 when step=1 but max=355 when step=5, and what when the step isn't known until run time?

(2) A range where the bottom and top values do not mean the same. E.g. radio frequency whole MHz, 118 <= x < 136, which could also be stated as 118 <= x <= 135 when the step size is 1. It is important that the boundary values are stable in the presence of floating-point imprecision: 117.999999 must not wrap to 135.something. The precision limit must be taken into account.

In case (2) I can imagine wanting (in different situations) several different wrapping sequences. E.g. on an arbitrary control range of 100 to 200, step size 10:

- Circular: 190-100-110 / 193-103-113 / 103-193-183 / 110-100-190
- Hit first limit: 190-200-110 / 193-200-110 / 103-100-190 / 110-100-190
- Hit both limits: 190-200-100 / 193-200-100 / 103-100-200 / 110-100-200
- etc.

In the case of an analogue value these all have ambiguities or "flickering" behaviour at their limits and I can think of no realistic requirement for any of them. In the case of a discrete value, I consider that all such sequences could be desirable in some situations, but the "circular" mode with "min <= x < max" covers the present (radio tuning) requirement well and can cover other requirements and is semantically simple.


Discrete Values and Precision

These definitions work for analogue and discrete values. However, when dealing with a property that takes only discrete values (e.g. the comm. radio frequency, usually at a resolution of 0.025 MHz) one could wish that at every step the value would be rounded off. Indeed, that will probably be necessary to prevent cumulative error from becoming larger than the floating-point precision limit "epsilon" and thus messing up the wrapping behaviour. One could always round values in the range (min +/- epsilon) to exactly min, and (max +/- epsilon) to exactly max. But that is only effective when the user takes the value to its limits, which might be never, so I don't think that's worth implementing. To avoid accumulating error, and also to round off grossly-wrong values (like 118.02 up to 118.025) would require the resolution to be specified separately: you can't say the value must be a multiple of the step size, because a control is often adjusted in steps of 5 or 10 times its resolution. Do we need to handle grossly-wrong values? Not when adjusting by pre-programmed increments as we do at present, but if we were to drag an analogue adjuster we would probably want it to click into place. Therefore I think that this method (snapping to (min + N*resolution)) will be necessary sooner or later. (The same semantic effect could also be obtained with a different implementation: storing that integer N instead of the floating-point value.)


Conclusion

The (previously) smooth rotation of angular values is worth restoring and, unless it is tackled, I'm pretty sure floating-point imprecision will result in users sometimes being unable to set an end-point value like 118.000 MHz.

Both use cases (1) and (2) can be accommodated together by applying the more stringent snap-to-valid-value rule if and only if a non-zero "resolution" is specified. (The resolution could be a property of the controlled value and/or a property of the adjustment command.)

I don't like to add more configuration and code, I like to pare things down to the simplest correct implementation. But I think this "snap to valid value" behaviour will be necessary.


I might have a go at an implementation. How do you feel about specifying "max" using the "min <= x < max" rule in all cases?

- Julian


_______________________________________________
Flightgear-devel mailing list
[EMAIL PROTECTED]
http://mail.flightgear.org/mailman/listinfo/flightgear-devel

Reply via email to