Computing an average temperature
nickmertin opened this issue · comments
Currently, ThermodynamicTemperature
values cannot be added together; the module documentation does a good job of explaining why. However, that makes it rather difficult to calculate the average of a collection of ThermodynamicTemperature
values. For non-affine quanities, one can just use .sum()
on an iterator then divide by the number of elements.
Is there a recommended way to do this for temperature values?
Not a great answer, but I would convert to temperature interval and then back again: 0 K ThermodynamicTemperature + SUM(ThermodynamicTemperature - 0 K TemperatureInterval)
I hit a similar issue, but subtracting TemperatureInterval
to a ThermodynamicTemperature
yields a ThermodynamicTemperature
, so SUM(ThermodynamicTemperature - 0 K TemperatureInterval)
is not really possible and the only way to do this is by getting the underlying value and creating a new TemperatureInterval with it, right?
More generally speaking, while summing affine quantities makes no sense, computing their mean does. So affine quantities, not just ThermodynamicTemperature
but also anything that might eventually emerge from #289, should support computing means, without forcing the user to hack around the type system in order to achieve something perfectly reasonable.
I've not had the need to use uom
's temperatures yet, so I was expecting to be able to subtract one ThermodynamicTemperature
from another and get a TemperatureInterval
, but that appears not to work:
use uom::si::f32::{TemperatureInterval as dT, ThermodynamicTemperature as T};
fn temp_difference(t1: T, t2: T) -> dT { t2 - t1 }
gives a compilation error or the subtraction `t2 - t1', which prevents these sorts of implementations
fn mean_t(t1: T, t2: T) -> T {
let dt: dT = t2 - t1;
t1 + dt / 2.0
}
fn mean_temp(ts: &[T]) -> Option<T> {
if ts.is_empty() { return None }
let n = ts.len() as f32;
let t0: T = ts[0]; // An arbitrary reference value, any `T` will do
let mean_deviation_from_t0: dT = ts.iter().map(|t| t - t0).sum::<dT>() / n;
Some(t0 + mean_deviation_from_t0)
}
@jacg issue #380 has the explanation for why it is like that. I do wonder if TemperatureKind
is the correct way to go for affine quantities, instead of something else more generic on top of uom
. Position and distance are also different, yet I don't see a LengthKind
for it or a LengthInterval
and the same goes for time and energy. And then how would you account for the fact that Velocity * Time = LengthInterval
and not Length
?
In fact, I believe a similar problem already exists: ThermalConductance
and ThermalConductivity
should only be multipliable with TemperatureInterval
, that's what makes physical sense.
issue #380 has the explanation for why it is like that.
I trust that we agree that this is a restriction imposed by an unfortunate shortcoming of the current implementation details of uom
rather than something fundamental. Put another way ThermodynamicTemperature - ThermodynamicTemperature
should give TemperatureInterval
.
I do wonder if
TemperatureKind
is the correct way to go for affine quantities, instead of something else more generic on top ofuom
. Position and distance are also different, yet I don't see aLengthKind
for it or aLengthInterval
and the same goes for time and energy.
... and for any Quantity
, which is what the aforementioned #289 is all about.
And then how would you account for the fact that
Velocity * Time = LengthInterval
and notLength
?
-
All
Quantities
need an affine (Q<A>
) and a vector (Q<V>
) version. -
The affine versions cannot be added or multiplied, only subtracted (note the
V
s in some of the< >
):Q<A> - Q<A> = Q<V>
Q<A> + Q<V> = Q<A>
Q<A> + Q<A>
- meaninglessQ<A> * <anything>
- meaningless
-
The vector versions support many more operations:
Q<V> - Q<V> = Q<V>
Q<V> + Q<V> = Q<V>
Q<V> + Q<A> = Q<A>
Q1<V> * Q2<V> = Q3<V>
- etc.
When you say that
Velocity * Time = LengthInterval
You mean
Velocity<V> * Time<V> = Length<V>
They cannot possibly be <A>
s because multiplication is not implemented for <A>
s.
Your Length
is really Length<A>
and that cannot be the result of a multiplication: only Q<V>
can be the result of a multiplication; your LengthInterval
is really Length<V>
which is just as well, because Q<V>
s are the only things that can result from multiplying Q
s.
In fact, I believe a similar problem already exists:
ThermalConductance
andThermalConductivity
should only be multipliable withTemperatureInterval
, that's what makes physical sense.
In general, it only makes sense to multiply vector, not affine, quantities.
When it comes to quantities like ThermalConductance
or Mass
there is a stronger tendency to conclude that their affine varieties do not exist, than it is for quantities like Velocity
: any 21st century physicist knows that absolute velocities are expressed in some arbitrary frame of reference. Mass
has an obvious, objective, non-arbitrary frame of reference on which everyone agrees, so it's more difficult to appreciate that said obvious choice of zero for affine mass is not the only possible choice. When you make the obvious choice, you can get away with confounding affine and vector mass, which makes it easy to overlook that Mass
also comes in affine and vector varieties, and that it is important to distinguish between the two:
- Place a bowl on top of some kitchen scales.
- Do NOT press the TARE button.
- Put some rice in the bowl.
- How would you double the amount of rice in the bowl?
If your solution is to keep pouring in rice until the number shown by the display doubles, then you'll get the wrong answer precisely because you performed an operation that is only permitted on vector quantities on an affine quantity: you multiplied an affine mass by 2, and multiplying affine quantities doesn't make sense.