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

Implement meaningful error for Float -asHoaOrder ? #119

Open
dyfer opened this issue Mar 2, 2022 · 13 comments
Open

Implement meaningful error for Float -asHoaOrder ? #119

dyfer opened this issue Mar 2, 2022 · 13 comments

Comments

@dyfer
Copy link
Contributor

dyfer commented Mar 2, 2022

In case when one miscalculates the number of parameters in Hoa* ugens, one might pass a float to the order argument. The resulting error ERROR: Message 'asHoaOrder' not understood. was confusing to me at first.

I'm not saying that floats should be allowed (e.g. using .asInteger), since this could lead to silently erroneous behavior. However, I was wondering if -asHoaOrder could be implemented for Floats to throw a more meaningful message? (like HoaOrder needs to be an Integer).

Example:

x.free; x = {HoaEncodeDirection.ar(DC.ar(0), 0, 0, AtkHoa.refRadius, 1)}.play;
//                                              ^ one parameter too many
// we end up with AtkHoa.refRadius as the "order"

Result:

ERROR: Message 'asHoaOrder' not understood.
RECEIVER:
   Float 1.500000   00000000 3FF80000
ARGS:
(...)
^^ ERROR: Message 'asHoaOrder' not understood.
RECEIVER: 1.5

@joslloand I'd be happy to submit a PR adding an Error message for Float -asHoaOrder if you think this is a desired feature.

@mtmccrea
Copy link
Member

mtmccrea commented Mar 2, 2022

We might consider a test like

// pseudocode
Float:-asHoaOrder
if(myFloat == myFloat.asInteger) {^myFloat} {error("Fractional orders aren't supported")} 

If fractional orders make sense in other contexts (analyzing effective decoder orders, for example), there may need to be more plumbing involved to isolate cases where fractional orders are not allowed.

@dyfer
Copy link
Contributor Author

dyfer commented Mar 2, 2022

Hm... I like the idea of accepting float representations of (integer) order as general, but I also remember that comparing equality of floats is generally not a good idea. Maybe something along the lines of what UnitTest -assertArrayFloatEquals do would be more accurate?

if((myFloat - myFloat.asInteger).abs <= someSmallNumber) {^myFloat} {error("Fractional orders aren't supported")} 

Actually... looking at this I see that HoaOrder can be instantiated with a float:

HoaOrder(1.2); // no error

Of course it would error out later on when trying to access other methods.

With this in mind, I think that it would be better to move the check for float to HoaOrder, so that any possible future handling of floats is resolved there, and move -asHoaOrder to SimpleNumber instead of Integer. What do you think?

@mtmccrea
Copy link
Member

mtmccrea commented Mar 5, 2022

if((myFloat - myFloat.asInteger).abs <= someSmallNumber) {^myFloat} {error("Fractional orders aren't supported")}

good idea!

I suppose the rest of the implementation question comes down to the fundamental question: should HoaOrder support float representations for order? What do you think @joslloand ?

@mtmccrea
Copy link
Member

mtmccrea commented Mar 5, 2022

Somewhat relatedly, we have used float tolerance elsewhere:

<>floatWithin = 1e-8; // float error tolerance

Maybe we should promote this value to an Atk class var?

@dyfer
Copy link
Contributor Author

dyfer commented Mar 5, 2022

I suppose the rest of the implementation question comes down to the fundamental question: should HoaOrder support float representations for order? What do you think @joslloand ?

Just to be clear, I'm not saying it should support it necessarily, but if it won't work properly with a float (i.e. the current situation), it should check for it at the initialization time...

@mtmccrea
Copy link
Member

mtmccrea commented Mar 6, 2022

Yep, you're right to point out the inconsistency between instantiating HoaOder with a float, and -asHoaOrder not responding to a float, it's just brought up higher level question :)

I'm suggesting that we might want to support fractional/float orders, but I haven't thought much about use cases for fractional orders. If the use cases are few, then maybe it's supported only in those contexts (effective decoder order, as mentioned before, or franctional-order beam patterns).

@dyfer
Copy link
Contributor Author

dyfer commented Mar 7, 2022

I'm suggesting that we might want to support fractional/float orders,

I think that's good, and IMO this future direction would also support my suggestion to check for float inside HoaOrder (we would remove that check once HoaOrder is ready for floats) and have both Integers and Floats respond to -asHoaOrder.

@joslloand
Copy link
Contributor

Argh! Thanks @dyfer ;-)

Actually, this brings up a few things to consider that can probably be divided into practical / theoretical AND authoring / analyzing.

On the practical side, for instantiating HOA streams, we can only have integer orders (in terms of number of coefficients... weighting is another matter... see below). Theoretically, these directly relate to a boxcar, e.g., truncation, windowing. In our practical system, we want to know how big the signal set should be, so having a check for @dyfer's original error would be a good idea:

x.free; x = {HoaEncodeDirection.ar(DC.ar(0), 0, 0, AtkHoa.refRadius, 1)}.play;
//                                              ^ one parameter too many
// we end up with AtkHoa.refRadius as the "order"

OK, so you asked for it ;-)

Having a closer look at HoaOrder and -asHoaOrder:

~orderTest = 1.5.asHoaOrder  // fails, only works for Integer

whereas:

~orderTest = HoaOrder.new(1.5)  // instantiates, but bad...(unless you know what you're doing)

Where the latter fails makes good sense:

~orderTest.indices  // fails
~orderTest.sph  // fails
~orderTest.normalisation  // fails
~orderTest.proxWeights(440, 1.0, AtkHoa.speedOfSound)  // fails

Where the latter succeeds makes some sense (if you know what you're doing):

~orderTest.size  // useful?
~orderTest.radiusAtFreq(440, AtkHoa.speedOfSound)  // useful?
~orderTest.spreadE  // useful?

I believe I left in the ability to declare floating point fractional orders as a way for expert users (actually, me) to have access to rule of thumb comparisons when designing crossovers, frequency dependent radial filters, etc.


More theory...

In practice, the idea of fractional orders are not super standardized in a general way... which makes some sense, as what we're really doing is smoothing in the spatial domain. What we're really talking about is different kinds of LP filtering of the SH.

We DO have two standardized LP frequency independent (truncated, fractional order) filters:

  • energy weighting
  • controlled opposites weighting

We ALSO have some specialized LP frequency dependent (fractional order) filters. These are the focalisation filters:

  • Regularised
  • (Butterworth) High Pass
  • Cosine
  • Sine

More practice...

If there is a limited use for expert users to instantiating a fractional instance of HoaOrder, why aren't we throwing a warning? Well... if we're attempting to design a custom focalisation filter (bin by bin), we'll have the post window filled with warnings... which won't be pretty. I'm fairly sure that's whey I didn't put one in.

And... my assumption was that novices would never go into the deep water.

So... some possible solutions:

  1. for pseudo-UGens, check and throw an error for floats
  2. update the SCHelp for HoaOrder to state fractional orders are accepted, but WARN not all instance methods are supported and/or throw in checks where not. (I think the checks could become more tedious... and I think I'd prefer to just warn users that they being handed a length of rope, which may result in their own hanging.)

@dyfer
Copy link
Contributor Author

dyfer commented Mar 7, 2022

Thanks @joslloand
My main point is that -asHoaOrder should be implemented for either SimpleNumber or for both Integer and Float, Afterwards we can deal with floating point orders as we see fit.

So... some possible solutions:

  1. for pseudo-UGens, check and throw an error for floats
  2. update the SCHelp for HoaOrder to state fractional orders are accepted, but WARN not all instance methods are supported and/or throw in checks where not. (I think the checks could become more tedious... and I think I'd prefer to just warn users that they being handed a length of rope, which may result in their own hanging.)

Either would be fine, with different caveats/amount of work.

I'd also suggest a possible 3rd option (not necessarily better, but different):
3. HoaOrder.new(order, allowFloat: false);
which would throw an error if the order is float and the flag is default (false). Advanced users could then instantiate the class with the flag set to true if needed (in which case there would be no error and probably no warning either). SimpleNumer -asHoaOrder would call the default option and thus throw on float orders.

@joslloand
Copy link
Contributor

I'd also suggest a possible 3rd option (not necessarily better, but different):
3. HoaOrder.new(order, allowFloat: false);
which would throw an error if the order is float and the flag is default (false). Advanced users could then instantiate the class with the flag set to true if needed (in which case there would be no error and probably no warning either). SimpleNumer -asHoaOrder would call the default option and thus throw on float orders.

@dyfer, I'm feeling an allowFloat flag would be the most attractive option, as it makes everything explicit.

If moved to SimpleNumber, -asHoaOrder for a Float will end up being nearly as verbose. E.g.:

  • HoaOrder.new(3.2, true)
  • 3.2.asHoaOrder(true)

More verbose is fine for expert users, though!!


As an aside, by adding an allowFloat flag to HoaOrder, we'll lose the explicit symmetry w/ the related classes:

Another side thought, while it would be great to support mixed orders (another kind of fractional order) like the ADT does for decoding, practically this is a headache best left to the ADT!!!

@dyfer
Copy link
Contributor Author

dyfer commented Mar 7, 2022

As an aside, by adding an allowFloat flag to HoaOrder, we'll lose the explicit symmetry w/ the related classes:

Again, not necessarily a better option, but we could consider having *allowFloat as a class variable for HoaOrder.
Pros:

  • set once for a project etc
  • -asHoaOrder would not need a flag
  • symmetry with aforementioned classes

Cons:

  • lack of granularity
  • less explicit interface (i.e. if one sets it globally and forgets it, there are no checks in place)

@mtmccrea
Copy link
Member

mtmccrea commented Mar 8, 2022

Having been away from SC for a while and returning now, I have to say the proliferation of method arguments or state flags to fork functionality doesn't feel great (looking back at some of my more elaborate class methods) making future development more cumbersome, especially with experimental/expert functionality like fractional orders.

Distilling a bit here, we know now that fractional/tapered orders is something to support. Am I correct that an implementation as SimpleNumber would mean all current functionality is retained and we can patch in context-specific safeguards?

@joslloand's helpful theory discussion points toward a division of instantiating stream channels and beam pattern design... For example, a new method could be added: SimpleNumber:-asHoaSignalOrder, which performs

if((myFloat - myFloat.asInteger).abs <= someSmallNumber) {^myFloat} {error("Fractional orders aren't supported")}

Not yet a fully flushed out idea, but seems like it's a good direction?

@mtmccrea
Copy link
Member

mtmccrea commented Mar 8, 2022

Relatedly:

  1. While looking into this, i noticed that given the use of HoaUGen:*confirmOrder, it may be better called *confirmSignalOrder.
  2. We may be bumping into a limit of a definition, and perhaps it's asking too much of the concept of 'order', as is widely understood, to be fractional. There may be room for a new concept/term that draws from factional polynomial degrees, etc., the representation for which in the ATK would be more sandboxed in the 'expert' corners of the library. ... but that's a wider research topic ;)

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

3 participants