Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For Discussion: Inconsistency in the definition of Hz? #1288

Open
kbauer opened this issue Apr 13, 2021 · 8 comments
Open

For Discussion: Inconsistency in the definition of Hz? #1288

kbauer opened this issue Apr 13, 2021 · 8 comments

Comments

@kbauer
Copy link

kbauer commented Apr 13, 2021

Summary

The definition of hertz is inconsistent with common usage, when angles are involved.

1 hertz is usually understood to denote 1 cycle / second, but it is currently defined as 1/second which is implicitly cast to 1 rad/second.

Why is it a problem?

As a user of the package, I was specifying frequencies as, e.g.

>>> f0 = u("50 Hz")

This implies, that one cycle should be 0.02 seconds. For plotting, I had an array of times, say

>>> times = array([0, 0.01, 0.02]) * u.seconds

and wanted to convert it to cycles with regard to f0. I expected

>>> (times * f0).to("cycles").magnitude
[0.000 0.500 1.000] turn

but got

>>> (times * f0).to("cycles").magnitude
[0.000 0.080 0.159] turn

Theoretical considerations

From Physics and Engineering environments I know two quantities describing the frequency of a system. When radians are assumed as natural unit of angles, they are given as

Frequency               f = 1/T,  meassured in Hz = 1/second
Angular Frequency/Rate  ω = 2π/T, meassured in 1/second

The different factor comes from the different in usage of f = 1/T versus sin(ωT)=1, i.e.

ω T = 1 cycle/second

When using angular units, but keeping the period defined as "time for one cycle" in seconds, this leads to

f = 1/T        in  1 Hz = 1/second
ω = 1 cycle/T  in  1 cycles/second
ω = 1 cycle * f

When using angular units, and giving periods as seconds/cycle (which seems to be the more natural choice), the relationships change; In order to maintain the form cos(ωt), the dimension of ω has to change to

f = 1/T  in   1 Hz = 1 cycles/second
ω = 1/T  in   1 cycles/second

The latter version ends up being more consistent and restores the understanding of 1 Hz.

Problems now arise with the current usage, because 1 Hz is currently defined as 1/second, which gets converted to rad/second in angle-units contexts.

How can it be solved?

The obvious way would be redefining Hz as cycles/second. However, this would likely create confusion from the requirement of specifying periods as seconds/cycle, distinguishing their dimension from that of time instants (in seconds).

The unit of Hz has contradicting requirements basically. When specifying a period as 1 second, users will expect the frequency to be

>>> T = u("1 seconds")
>>> ( f := 1/T ).to("hertz")
1.0 hertz

but at the same time expect

>>> (f := 1/T ).to("cycles/second")
1.0 turn/second
# but actually getting 0.159 turn/second

The solution would essentially be to not automatically cast angles to dimensionless numbers, and redefine 1 hertz = 1 cycle/second. But the consequence would be, that angle units have to be used everywhere, and this is simply not what is done in literature and thus will be confusing.

So... probably, it cannot be solved at all, except by documentation.

Affected Version

>>> pip3 list | grep Pint
Pint                          0.17
@jules-ch
Copy link
Collaborator

The SI unit of frequency is hertz, the SI unit of angular velocity and angular frequency is
radian per second, and the SI unit of activity is becquerel, implying counts per second.
Although it is formally correct to write all three of these units as the reciprocal second, the
use of the different names emphasizes the different nature of the quantities concerned. It is
especially important to carefully distinguish frequencies from angular frequencies, because
by definition their numerical values differ by a factor1 of 2π. Ignoring this fact may cause
an error of 2π. Note that in some countries, frequency values are conventionally expressed
using “cycle/s” or “cps” instead of the SI unit Hz, although “cycle” and “cps” are not units
in the SI. Note also that it is common, although not recommended, to use the term
frequency for quantities expressed in rad/s. Because of this, it is recommended that
quantities called “frequency”, “angular frequency”, and “angular velocity” always be given
explicit units of Hz or rad/s and not s−1.

BIPM is pretty clear about it if you mean angular velocity you should use radian/s or rpm.
Hz should be used for frequency.

BIPM recommends to be explicit in this case.

I agree with you it should have better documentation & even warn the user about this kind of error which can be confusing.

@jules-ch
Copy link
Collaborator

jules-ch commented Apr 13, 2021

I think we could resolve this, using contexts in pint.

For example when converting from Hz to angular fequency like rad/s.
This will custom conversion based on the destination units. Though I'm not sure the implications of such behaviour.

@hgrecco
Copy link
Owner

hgrecco commented Apr 13, 2021

If I might add, a long stand discussion is how to consider a radian. In pint, radians are dimensionless. So there is no distinction (in terms of dimensionality) between rad/sec and 1/sec

@andrewgsavage
Copy link
Collaborator

I think we could resolve this, using contexts in pint.

For example when converting from Hz to angular fequency like rad/s.
This will custom conversion based on the destination units. Though I'm not sure the implications of such behaviour.

I'm a bit lost how this would work, the context examples are based on dimensionality and both Hz and rad/s have the same dimensionality.

If I might add, a long stand discussion is how to consider a radian. In pint, radians are dimensionless. So there is no distinction (in terms of dimensionality) between rad/sec and 1/sec

It would be interesting to see whether having an angle dimension causes less issues than not. I can see other issues that would occur.

If you've got a power, dimensionality '[length]': 2, '[mass]': 1, '[time]': -3, and divide by a torque, [length]': 1, '[mass]': -1, you'd expect to get a angular velocity, but there is no angle dimension.

@techdragon
Copy link

techdragon commented May 11, 2021

Having just been bitten by this, and having to manually construct what I feel is a pretty common conversion (hertz/frequency to period) as a workaround for this behaviour of hertz/frequency incorrectly turning into an angular unit and not supporting sensible conversions due to ambiguity.

Could some of the impact of this issue be solved by having a built in definition for "period" which can be used to build a chain like ureg("2 per second").to("period").to("milliseconds") in order to convert from a frequency style definition, to its reciprocal without the incorrect step of treating it as a dimensionless angle?

At the moment the direct conversion will fail. ureg("2 per second").to('milliseconds') throws pint.errors.DimensionalityError: Cannot convert from '1 / second' (1 / [time]) to 'millisecond' ([time]) which while understandable, feels like pint should have been able to handle this. So having a way to explicitly turn a frequency 1 / [time] into its reciprocal [time] would be beneficial. Related to #855 I suppose.

Edit: For anyone else who, like me, trips over this without having worked out the "right way" to do this conversion correctly. (1/ureg("4 per second").to("milliseconds") will return the expected value of 250.0 <Unit('millisecond')>. This keeps everything in pint units preserving uncertainty, etc... Even if it doesn't read quite as nicely as pint's fluent interface chaining normally does.

@andrewgsavage
Copy link
Collaborator

andrewgsavage commented May 11, 2021

I created a branch with angle as a base unit to see how this would work.
master...andrewgsavage:pint:angle#diff-cc2784e7cfe7c2d896ae4ec1ef1563eed99bed539cb02f5a0f00e276dab48fe5

Using a context gives intuitive behaviour:

master

Q_("30 Hz").to("rps")
4.7746482927568605 revolutions_per_second

angle

Q_("30 Hz").to("rps")
DimensionalityError: Cannot convert from 'hertz' (1 / [time]) to 'revolutions_per_second' ([angle] / [time])

with ureg.context('angular'):
    print(Q_("30 Hz").to("rps"))
30.0 revolutions_per_second

master

(Q_("1 rad/s") * Q_("1 N m")).to("W")
1.0 watt

angle

(Q_("1 rad/s") * Q_("1 N m")).to("W")
DimensionalityError: Cannot convert from 'meter * newton * radian / second' ([angle] * [length] ** 2 * [mass] / [time] ** 3) to 'watt' ([length] ** 2 * [mass] / [time] ** 3)

with ureg.context('angular'):
    print((Q_("1 rad/s") * Q_("1 N m")).to("W"))
1.0 watt

code for angular context

c = pint.Context('angular')
# W rad -> W
c.add_transformation('[mass] [length] ** 2 [time] ** -3 [angle]', '[mass] [length] ** 2 [time] ** -3',
                     lambda ureg, x: x / ureg.rad)
# W -> W rad
c.add_transformation('[mass] [length] ** 2 [time] ** -3', '[mass] [length] ** 2 [time] ** -3 [angle]',
                     lambda ureg, x: x * ureg.rad)
# rad/s -> Hz
c.add_transformation('[time] ** -1 [angle]', '[time] ** -1',
                     lambda ureg, x: x / ureg.turn)
# Hz -> rad/s
c.add_transformation('[time] ** -1', '[time] ** -1 [angle]',
                     lambda ureg, x: x * ureg.turn)
ureg.add_context(c)

@jules-ch
Copy link
Collaborator

jules-ch commented Jul 19, 2021

@andrewgsavage
I have mixed feelings about this, BIPM states rad et steradian should be considered as unit one.

I don't know all the implications that could lead to.

Quoting BIPM brochure :

Plane and solid angles, when expressed in radians and steradians respectively, are in effect
also treated within the SI as quantities with the unit one (see section 5.4.8). The symbols rad
and sr are written explicitly where appropriate, in order to emphasize that, for radians or
steradians, the quantity being considered is, or involves the plane angle or solid angle
respectively. For steradians it emphasizes the distinction between units of flux and intensity
in radiometry and photometry for example. However, it is a long-established practice in
mathematics and across all areas of science to make use of rad = 1 and sr = 1.

But in practice, a lot of people are expecting:

1 Hz -> 6.28 rad/s

which tells us 1 Hz here is equivalent to 1 turn/s which violates 1 Hz -> 1/s -> 1 rad/s.

Maybe we should put a warning in the docs in the meantime and recommending to use rad/s or rpm when meaning angular velocity which can lead to ambiguity.
I tend never to use Hz for angular frequency for this.

Context could be used here in the form of redefining Hz in this particular context, but as stated we do not have this feature available with the current implementation.

@hgrecco
Copy link
Owner

hgrecco commented Jul 20, 2021

I definetly think that we should put a warning in the docs. And I think we should not change the definition. While it is true that a lot of people are expecting 1 Hz = 2 pi rad /s, a lot expect 1/s.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants