josdejong / mathjs

An extensive math library for JavaScript and Node.js
https://mathjs.org
Apache License 2.0
14.41k stars 1.24k forks source link

Dimensionless units (e.g. angular) together with other units #1585

Closed waspo closed 1 year ago

waspo commented 5 years ago

If I type the following into the math.js expression parser:

(kg m )/s^2 to N 
--> 1 N

But if I type:

(kg m rad)/s^2 to N
--> Error: Units do not match ('N' != '(kg m rad) / s^2')

But [N] should be possible and should be correct because rad = m/m = 1 (according to SI). Is there a chance to solve this?

ericman314 commented 5 years ago

That is a very interesting question: whether rad should be loosely matched when converting between units. You are correct that rad is dimensionless and that, mathematically, using rad and not using rad will give the same answer to any problem. So one argument for loose matching is that if a user explicitly requests removing or ignoring a rad, we should technically be able to do that.

But one argument against, is that rad has its place in physics and engineering as a way to help describe angular quantities. Indeed, that's the purpose of all units, is to just help humans keep track of physical quantities. In my experience, whenever I have used rad in solving an engineering problem, the rad's don't just disappear at will, they hang around and continue to be meaningful all the way through the problem. So either I 1) keep the rad's around, or 2) don't use them at all. And I usually find that 1) works as long as I'm mindful about where the rad's are going at each step of the problem. An example is if you're working with torque, which is usually in newton meters, but it can also be expressed in joules/radian. Then if a motor imparts x joules/radian on an object that rotates through y radians, x * y joules of work has been done. So keeping the radians around is sometimes best.

That's the only example I could think of at the moment. Maybe the best way to decide this question is to look at more examples and see what makes sense. Do you have any others to share?

waspo commented 5 years ago

Interesting point ericman314. I totally agree with you that keeping a dimensionless unit makes it easier to understand a physical problem. And I think there is no need to decide whether to keep a unit or not. There maybe 2 options: 1) Math.js could differentiate between implicit and explicit conversions. So if I want to do an explicit conversion (like in my first example) it should just ignore dimensionless units. But as long as I do not ask for explicit conversion it should keep the dimensionless unit, as it does now. 2) Math.js should differentiate between the physical quantity and the unit. Then the conversion could be done based on the physical quantity. This would result in ignoring/removing the dimensionless unit on every conversion.

I prefer option 1 because it keeps the unit and helps me understand the physical problem and at the same time gives me the possibility to check a result by checking if the physical quantity fits. This could look like:

1 J / 10 rad
--> 0.1 J/rad

1 J / 10 rad to N m
--> 0.1 N m
harrysarson commented 5 years ago

This is a good question! I think that maths should treat radians the same as any other unit. If folk wish to convert J / rad to N m then they can divide by 1 rad. It is better to he explicit I think :)

waspo commented 5 years ago

You're right, dividing by rad is a workaround. But the "problem" is still there: Returning an error for rad/s to Hz is not correct.

ericman314 commented 5 years ago

I don't think this is a terrible idea, I just worry that implicitly adding/removing/ignoring rad would cause too much chance for error. Your latest example, rad/s to Hz, brings to mind a possible issue.

For example, let's say I wanted to compute the angular speed of a 2-pole AC induction motor running on a 60 Hz supply in RPM. Wikipedia gives the formula as 2 f / p, where f is the frequency and p is the number of poles. I define a new unit with createUnit('RPM', 360 deg / minute), and then I do 2 * (60 Hz) / 2 to RPM, and get the error: Units do not match.

At that point I realize that there is something wrong with my formula. Thinking about it more, I realize that one cycle of the AC current would rotate the motor a full 360 degrees, so I change my formula to 60 cycles/second * 360 deg/cycle. The cycles cancel in my formula, so I just type 60 / second * 360 deg to RPM and get 3600 RPM, the correct result.

Now say that math.js implicitly added a rad to my formula to make the units agree (one would suppose that if math.js could remove unnecessary rads, it could also add them when needed). Then instead of getting an error when typing 2 * 60 Hz / 2 * to RPM, I would get 572.9577951308232 RPM, and if I didn't know better I might think that was the right answer.

So by that example, Hz should convert to and from 2 pi rad / s rather than 1 rad / s. But Hz is 1 / s, and 1 Hz cannot be equal to both 2 pi rad / s and 1 rad / s at the same time. I'm afraid there might not be an easy way to accomplish what you are suggesting.

waspo commented 5 years ago

Good example. A few comments on that:

  1. If you would have defined RPM as createUnit("RPM", 1/minute) your result would be correct and as expected:

    createUnit("RPM", 1/minute)
    --> RPM
    60Hz to RPM
    --> 3600 RPM
  2. If the target unit contains dimensionless units in its definition like createUnit("RPM", 360deg/minute) then it should not be ignored, of course. Otherwise it should be ignored in explicit conversion by ... to .... By ignoring I mean dividing the dimensionless unit by itself [m]rad/rad. With this distinction you would still get an error when doing 60Hz to RPM and you will not get an error when doing kg m rad / s^2 to N.

  3. You say

    ... 1 Hz cannot be equal to both 2 pi rad / s and 1 rad / s at the same time.

And actually it is not (it is 2pi Hz and 1 Hz).

So what do you think about my second point (selective neutralization of dimensionless units)?

ericman314 commented 5 years ago

If the target unit contains dimensionless units in its definition like createUnit("RPM", 360deg/minute) then it should not be ignored, of course.

Yeah, I did have to stretch a little in my example as I was converting to an angular unit rather than from an angular unit. You are right that if we did implement this, only conversion to angular-less units would remove the rad.

If you would have defined RPM as createUnit("RPM", 1/minute) your result would be correct and as expected

Very true. In that case, the angular units are never introduced into the equation at all. Which is, I think, another satisfactory resolution to this issue: if radians are treated as just being equal to 1, then why use them at all?

You have given several example conversions where the source unit has a rad and the target unit does not. Can you take us through an example problem where you would use radians, and then later perform a conversion to a unit without radians? Altering the behavior of unit conversions will require a pretty strong justification as to its potential use cases.

waspo commented 5 years ago

Yes I totally agree that such a fundamental change needs a strong justification. I supposed that incorrect results (rad/s is Hz) should be strong enough. ;) You need this evertime when you handle with angular motion and the corresponding force/momentum. The input is of kind rad/s or deg/s^2 (acceleration) and the resulting forces are N or N m. I could omit the angular units, but for me it's very convenient to use Mathjs's capabilities to convert between arcsec, deg, rad, ....

josdejong commented 5 years ago

Interesting discussion!

On a side note: I've always doubted whether I should let mathjs functions like asin return a unit in radians or a number. Right now asin(sin(0.5 rad)) evaluates to 0.5, but it could possibly evaluate to 0.5 rad. If we would do the latter, it's every inconvenient if you want to use it in a calculation not using units but just numbers, like say you do asin(0.1) + 2. This would be solved if we allow silently dropping the rad unit. But as Eric explains that kind of behaviour can cause ambiguity. Or do any of you see possibilities here?

waspo commented 5 years ago

Unfortunately I don't have a better idea than the one I described before. I know it's holiday time, so maybe there will be a descission in a few weeks?

gwhitney commented 1 year ago

At this point, this is really a Discussion for https://github.com/ericman314/unitmath; but in any case, it is not an issue for mathjs, so moving it to mathjs discussions to preserve the thoughts here.