Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #93394 > unrolled thread

"normalizing" a value

Started bybvdp <bob@mellowood.ca>
First post2015-07-01 17:12 -0700
Last post2015-07-02 10:05 -0500
Articles 14 — 9 participants

Back to article view | Back to comp.lang.python


Contents

  "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 17:12 -0700
    Re: "normalizing" a value MRAB <python@mrabarnett.plus.com> - 2015-07-02 01:30 +0100
    Re: "normalizing" a value Paul Rubin <no.email@nospam.invalid> - 2015-07-01 17:36 -0700
    Re: "normalizing" a value Denis McMahon <denismfmcmahon@gmail.com> - 2015-07-02 01:06 +0000
    Re: "normalizing" a value random832@fastmail.us - 2015-07-01 21:27 -0400
      Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 18:49 -0700
        Re: "normalizing" a value random832@fastmail.us - 2015-07-01 22:23 -0400
          Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 19:41 -0700
        Re: "normalizing" a value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2015-07-01 23:36 -0400
          Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-02 10:03 -0700
    Re: "normalizing" a value Steven D'Aprano <steve@pearwood.info> - 2015-07-02 12:15 +1000
      Re: "normalizing" a value bvdp <bob@mellowood.ca> - 2015-07-01 19:42 -0700
    Re: "normalizing" a value Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-07-02 05:41 +0100
    Re: "normalizing" a value Skip Montanaro <skip.montanaro@gmail.com> - 2015-07-02 10:05 -0500

#93394 — "normalizing" a value

Frombvdp <bob@mellowood.ca>
Date2015-07-01 17:12 -0700
Subject"normalizing" a value
Message-ID<fd370a7b-ea6a-48e5-90f4-9d86b89a745e@googlegroups.com>
Not sure what this is called (and I'm sure it's not normalize). Perhaps "scaling"?

Anyway, I need to convert various values ranging from around -50 to 50 to an 0 to 12 range (this is part of a MIDI music program). I have a number of places where I do:

   while x < 0: x += 12
   while x >= 12: x -= 12

Okay, that works. Just wondering if there is an easier (or faster) way to accomplish this.

[toc] | [next] | [standalone]


#93395

FromMRAB <python@mrabarnett.plus.com>
Date2015-07-02 01:30 +0100
Message-ID<mailman.229.1435797056.3674.python-list@python.org>
In reply to#93394
On 2015-07-02 01:12, bvdp wrote:
> Not sure what this is called (and I'm sure it's not normalize). Perhaps "scaling"?
>
> Anyway, I need to convert various values ranging from around -50 to 50 to an 0 to 12 range (this is part of a MIDI music program). I have a number of places where I do:
>
>     while x < 0: x += 12
>     while x >= 12: x -= 12
>
> Okay, that works. Just wondering if there is an easier (or faster) way to accomplish this.
>
That's called "modular arithmetic". Use the modulo operator, '%':

     x = x % 12

or just:

     x %= 12

[toc] | [prev] | [next] | [standalone]


#93396

FromPaul Rubin <no.email@nospam.invalid>
Date2015-07-01 17:36 -0700
Message-ID<87a8vfqttm.fsf@nightsong.com>
In reply to#93394
bvdp <bob@mellowood.ca> writes:
>    while x < 0: x += 12
>    while x >= 12: x -= 12
> Okay, that works. Just wondering if there is an easier (or faster) way
> to accomplish this.

x = x % 12

should be the same as the above.  But are you sure that's really what
you want?

[toc] | [prev] | [next] | [standalone]


#93397

FromDenis McMahon <denismfmcmahon@gmail.com>
Date2015-07-02 01:06 +0000
Message-ID<mn22qf$l6g$3@dont-email.me>
In reply to#93394
On Wed, 01 Jul 2015 17:12:36 -0700, bvdp wrote:

> Not sure what this is called (and I'm sure it's not normalize). Perhaps
> "scaling"?
> 
> Anyway, I need to convert various values ranging from around -50 to 50
> to an 0 to 12 range (this is part of a MIDI music program). I have a
> number of places where I do:
> 
>    while x < 0: x += 12 while x >= 12: x -= 12
> 
> Okay, that works. Just wondering if there is an easier (or faster) way
> to accomplish this.

Are you sure it works? Do you simply want to reduce it to the arbitrary 
range, or do you want to also retain the relationship between different x 
values such that if x1 < x2, f(x1) < f(x2)?

Consider the following x values:

-11, -12, -13, 11, 12, 13

-11 -> 1
-12 -> 0
-13 -> 11
11 -> 11
12 -> 0
13 -> 1

So -13 gives the same output value as 11 in your current code. Is this 
what you want?

You could try the following:

# step 1, limit x to the range -50 .. 50
if x < -50:
    x = -50.0
ix x >= 50:
    x = 50.0
# step 2, scale x to the range 0 .. 12
x = x * 0.12 + 6.0

If you want an integer value, you need to determine which method is most 
relevant. I would suggest rounding.

-- 
Denis McMahon, denismfmcmahon@gmail.com

[toc] | [prev] | [next] | [standalone]


#93400

Fromrandom832@fastmail.us
Date2015-07-01 21:27 -0400
Message-ID<mailman.230.1435800465.3674.python-list@python.org>
In reply to#93394
On Wed, Jul 1, 2015, at 20:12, bvdp wrote:
> Not sure what this is called (and I'm sure it's not normalize). Perhaps
> "scaling"?
> 
> Anyway, I need to convert various values ranging from around -50 to 50 to
> an 0 to 12 range (this is part of a MIDI music program). I have a number
> of places where I do:
> 
>    while x < 0: x += 12
>    while x >= 12: x -= 12

And this gives you what you want? With e.g. 13=1, 14=2, 22=10, 23=11,
24=0, 25 = 1, etc. Seems unusual that that's what you would want.

Also note this gives an 0 to 11 range for the results, not 0 to 12.

Anyway, x %= 12 will give the same results.

[toc] | [prev] | [next] | [standalone]


#93401

Frombvdp <bob@mellowood.ca>
Date2015-07-01 18:49 -0700
Message-ID<948e2800-e52b-429a-9e00-f268fcff5085@googlegroups.com>
In reply to#93400
On Wednesday, July 1, 2015 at 6:27:57 PM UTC-7, rand...@fastmail.us wrote:
> On Wed, Jul 1, 2015, at 20:12, bvdp wrote:
> > Not sure what this is called (and I'm sure it's not normalize). Perhaps
> > "scaling"?
> > 
> > Anyway, I need to convert various values ranging from around -50 to 50 to
> > an 0 to 12 range (this is part of a MIDI music program). I have a number
> > of places where I do:
> > 
> >    while x < 0: x += 12
> >    while x >= 12: x -= 12
> 
> And this gives you what you want? With e.g. 13=1, 14=2, 22=10, 23=11,
> 24=0, 25 = 1, etc. Seems unusual that that's what you would want.
> 
> Also note this gives an 0 to 11 range for the results, not 0 to 12.
> 
> Anyway, x %= 12 will give the same results.

Thanks guys. Yes, that is exactly what I want. I have a number of places where a MIDI note value is being generated. MIDI should be 0..127, but the process creates notes outside the range. Guess that's another question: if the value I have is <0 or >127 I add/subtract 12 'til it's in range. Don't see using modulo working on this???

As far as the original question: Yes, that's what I need. At times I need to take a note (say 14) and map it into a single octave range. So, the 12 becomes 2. Both 14 and 2 are numeric values for note "d", just an octave apart.

Interesting that negative values translate properly. That's an non-intuitive result to me. Guess I should have studied that math stuff harder way back when!

[toc] | [prev] | [next] | [standalone]


#93405

Fromrandom832@fastmail.us
Date2015-07-01 22:23 -0400
Message-ID<mailman.231.1435803787.3674.python-list@python.org>
In reply to#93401
On Wed, Jul 1, 2015, at 21:49, bvdp wrote:
> Interesting that negative values translate properly. That's an
> non-intuitive result to me. Guess I should have studied that math stuff
> harder way back when!

There are multiple interpretations of the operation, and not all
languages behave the same way as Python does with negative operands.
Python is the odd one out when one considers C/C++, C#, and Java which
all behave a different way.

In general, almost all languages behave in a way so that given q, r = a
// b, a % b; q * b + r == a. However, this simply changes the question
to how division results involving negative operands are rounded.

Here's an article by GvR about why python behaves the way it does:
http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html

[toc] | [prev] | [next] | [standalone]


#93406

Frombvdp <bob@mellowood.ca>
Date2015-07-01 19:41 -0700
Message-ID<7016792e-ac01-4ee5-a644-1bea9a204d8c@googlegroups.com>
In reply to#93405
On Wednesday, July 1, 2015 at 7:23:19 PM UTC-7, rand...@fastmail.us wrote:
> On Wed, Jul 1, 2015, at 21:49, bvdp wrote:
> > Interesting that negative values translate properly. That's an
> > non-intuitive result to me. Guess I should have studied that math stuff
> > harder way back when!
> 
> There are multiple interpretations of the operation, and not all
> languages behave the same way as Python does with negative operands.
> Python is the odd one out when one considers C/C++, C#, and Java which
> all behave a different way.
> 
> In general, almost all languages behave in a way so that given q, r = a
> // b, a % b; q * b + r == a. However, this simply changes the question
> to how division results involving negative operands are rounded.
> 
> Here's an article by GvR about why python behaves the way it does:
> http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html

Interesting link. Thanks. I always thought that modulo was modulo. Guess this is another example of why converting code between languages is hard :)

Anyway, far as shoving my MIDI notes into a single octave, x % 12 seems to be perfect.

[toc] | [prev] | [next] | [standalone]


#93410

FromDennis Lee Bieber <wlfraed@ix.netcom.com>
Date2015-07-01 23:36 -0400
Message-ID<mailman.233.1435808221.3674.python-list@python.org>
In reply to#93401
On Wed, 1 Jul 2015 18:49:34 -0700 (PDT), bvdp <bob@mellowood.ca> declaimed
the following:

>
>Thanks guys. Yes, that is exactly what I want. I have a number of places where a MIDI note value is being generated. MIDI should be 0..127, but the process creates notes outside the range. Guess that's another question: if the value I have is <0 or >127 I add/subtract 12 'til it's in range. Don't see using modulo working on this???
>
>As far as the original question: Yes, that's what I need. At times I need to take a note (say 14) and map it into a single octave range. So, the 12 becomes 2. Both 14 and 2 are numeric values for note "d", just an octave apart.
>

Modulo will give you the "note", but throws out the octave.

Your original post specified -50..50, which spans only 101 values, whereas
MIDI spans 128 values -- so what do you really consider out of range? And
what MIDI value is -50 supposed to map against. Is input 0 supposed to
represent middle-C with negative values being notes on the bass clef and
positive values being treble clef?

MIDI middle-C is note 60. Presuming your 0 is supposed to be middle-C, I'd
do the transformation as:

midiNote = invalue + 60
if midiNote < 0: midiNote = midiNote % 12
if midiNote > 127: midiNote = (midiNote % 12) + 115

which actually means input values of -60..+67 are shifted directly to a
midi note number, and values outside of that range are shadowed as the
lowest or highest octave.

>>> for i in range(-70, 80, 4):
... 	midiNote = i + 60
... 	if midiNote < 0: midiNote = midiNote % 12
... 	if midiNote > 127: midiNote = ((midiNote - 5) % 12) + 113
... 	print i, midiNote, "CcDdEFfGgAaB"[midiNote % 12], divmod(midiNote,
12)
... 
-70 2 D (0, 2)
-66 6 f (0, 6)
-62 10 a (0, 10)
-58 2 D (0, 2)
-54 6 f (0, 6)
-50 10 a (0, 10)
-46 14 D (1, 2)
-42 18 f (1, 6)
-38 22 a (1, 10)
-34 26 D (2, 2)
-30 30 f (2, 6)
-26 34 a (2, 10)
-22 38 D (3, 2)
-18 42 f (3, 6)
-14 46 a (3, 10)
-10 50 D (4, 2)
-6 54 f (4, 6)
-2 58 a (4, 10)
2 62 D (5, 2)
6 66 f (5, 6)
10 70 a (5, 10)
14 74 D (6, 2)
18 78 f (6, 6)
22 82 a (6, 10)
26 86 D (7, 2)
30 90 f (7, 6)
34 94 a (7, 10)
38 98 D (8, 2)
42 102 f (8, 6)
46 106 a (8, 10)
50 110 D (9, 2)
54 114 f (9, 6)
58 118 a (9, 10)
62 122 D (10, 2)
66 126 f (10, 6)
70 118 a (9, 10)
74 122 D (10, 2)
78 114 f (9, 6)
>>> 

The oddity for the >127 case is that 127 is not an even octave break point.
divmod() gives you the "octave" and the note.
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

[toc] | [prev] | [next] | [standalone]


#93445

Frombvdp <bob@mellowood.ca>
Date2015-07-02 10:03 -0700
Message-ID<4c0721c0-b5f5-4e0d-9db4-822f838f3708@googlegroups.com>
In reply to#93410
On Wednesday, July 1, 2015 at 8:37:18 PM UTC-7, Dennis Lee Bieber wrote:
> On Wed, 1 Jul 2015 18:49:34 -0700 (PDT), bvdp <bob@mellowood.ca> declaimed
> the following:
> 
> >
> >Thanks guys. Yes, that is exactly what I want. I have a number of places where a MIDI note value is being generated. MIDI should be 0..127, but the process creates notes outside the range. Guess that's another question: if the value I have is <0 or >127 I add/subtract 12 'til it's in range. Don't see using modulo working on this???
> >
> >As far as the original question: Yes, that's what I need. At times I need to take a note (say 14) and map it into a single octave range. So, the 12 becomes 2. Both 14 and 2 are numeric values for note "d", just an octave apart.
> >
> 
> Modulo will give you the "note", but throws out the octave.
> 
> Your original post specified -50..50, which spans only 101 values, whereas
> MIDI spans 128 values -- so what do you really consider out of range? And
> what MIDI value is -50 supposed to map against. Is input 0 supposed to
> represent middle-C with negative values being notes on the bass clef and
> positive values being treble clef?
> 
> MIDI middle-C is note 60. Presuming your 0 is supposed to be middle-C, I'd
> do the transformation as:
> 
> midiNote = invalue + 60
> if midiNote < 0: midiNote = midiNote % 12
> if midiNote > 127: midiNote = (midiNote % 12) + 115
> 
> which actually means input values of -60..+67 are shifted directly to a
> midi note number, and values outside of that range are shadowed as the
> lowest or highest octave.
> 
> >>> for i in range(-70, 80, 4):
> ... 	midiNote = i + 60
> ... 	if midiNote < 0: midiNote = midiNote % 12
> ... 	if midiNote > 127: midiNote = ((midiNote - 5) % 12) + 113
> ... 	print i, midiNote, "CcDdEFfGgAaB"[midiNote % 12], divmod(midiNote,
> 12)
> ... 
> -70 2 D (0, 2)
> -66 6 f (0, 6)
> -62 10 a (0, 10)
> -58 2 D (0, 2)
> -54 6 f (0, 6)
> -50 10 a (0, 10)
> -46 14 D (1, 2)
> -42 18 f (1, 6)
> -38 22 a (1, 10)
> -34 26 D (2, 2)
> -30 30 f (2, 6)
> -26 34 a (2, 10)
> -22 38 D (3, 2)
> -18 42 f (3, 6)
> -14 46 a (3, 10)
> -10 50 D (4, 2)
> -6 54 f (4, 6)
> -2 58 a (4, 10)
> 2 62 D (5, 2)
> 6 66 f (5, 6)
> 10 70 a (5, 10)
> 14 74 D (6, 2)
> 18 78 f (6, 6)
> 22 82 a (6, 10)
> 26 86 D (7, 2)
> 30 90 f (7, 6)
> 34 94 a (7, 10)
> 38 98 D (8, 2)
> 42 102 f (8, 6)
> 46 106 a (8, 10)
> 50 110 D (9, 2)
> 54 114 f (9, 6)
> 58 118 a (9, 10)
> 62 122 D (10, 2)
> 66 126 f (10, 6)
> 70 118 a (9, 10)
> 74 122 D (10, 2)
> 78 114 f (9, 6)
> >>> 
> 
> The oddity for the >127 case is that 127 is not an even octave break point.
> divmod() gives you the "octave" and the note.
> -- 
> 	Wulfraed                 Dennis Lee Bieber         AF6VN
>     wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

Thanks. I like your solution for values <0 >127. Makes more sense than mindlessly adding/subtracting 12 to bring into range. In this case I'm just trying to take an out-of-range note to the top/bottom of the valid midi range.

[toc] | [prev] | [next] | [standalone]


#93404

FromSteven D'Aprano <steve@pearwood.info>
Date2015-07-02 12:15 +1000
Message-ID<55949eaf$0$1642$c3e8da3$5496439d@news.astraweb.com>
In reply to#93394
On Thu, 2 Jul 2015 10:12 am, bvdp wrote:

> Not sure what this is called (and I'm sure it's not normalize). Perhaps
> "scaling"?


Could be normalising, could be scaling.
 
> Anyway, I need to convert various values ranging from around -50 to 50 to
> an 0 to 12 range (this is part of a MIDI music program). I have a number
> of places where I do:

You say "around" -50 to 50. Can you get 51? 151? How do you want to treat
such out of range numbers?

Are the values integer valued, or can they include fractional values like
27.356?

>    while x < 0: x += 12
>    while x >= 12: x -= 12
> 
> Okay, that works. Just wondering if there is an easier (or faster) way to
> accomplish this.


One approach is to just re-scale the numbers from the range -50...50 to
0...12 inclusive. That is:

    before => after
    -50 => 0
    0 => 6
    50 => 12


and everything in between is scaled equivalently. Given x between -50 and 50
inclusive, calculate:

    y = (x+50)/100.0*12


(Note that in Python 2, you need to make at least one of those values a
float, otherwise you may get unexpected results.)

That will give you y values from the range 0.0 to 12.0 inclusive. If x is
less than -50.0 or more than +50.0 y will likewise be out of range. You can
clip the result:

    y = min(12.0, max(0.0, y))

If your x values are integer values (no fractional values) between -50 and
+50 you can use clock arithmetic. Think of a clock marked 0 to 12 (so there
are 13 values), once you reach 12 adding 1 takes you back to 0.

    0, 13, 26, 39 => 0
    1, 14, 27, 40 => 1
    2, 15, 28, 41 => 2
    ...
    12, 25, 38, 51 => 12


Extending that to negative values in the most obvious fashion:

    -1, -14, -27, -40 => 12
    ...
    -12, -25, -38, -51 => 1
    -13, -26, -39, -52 => 0
    

We can do that easily with the % (modulo) operator:

    y = x % y


Modulo even works with non-integer values:

py> 13.5 % 13
0.5



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#93407

Frombvdp <bob@mellowood.ca>
Date2015-07-01 19:42 -0700
Message-ID<29e00fb7-ac8f-41d7-b59b-4e0a39c77496@googlegroups.com>
In reply to#93404
On Wednesday, July 1, 2015 at 7:15:28 PM UTC-7, Steven D'Aprano wrote:
> On Thu, 2 Jul 2015 10:12 am, bvdp wrote:
> 
> > Not sure what this is called (and I'm sure it's not normalize). Perhaps
> > "scaling"?
> 
> 
> Could be normalising, could be scaling.
>  
> > Anyway, I need to convert various values ranging from around -50 to 50 to
> > an 0 to 12 range (this is part of a MIDI music program). I have a number
> > of places where I do:
> 
> You say "around" -50 to 50. Can you get 51? 151? How do you want to treat
> such out of range numbers?
> 
> Are the values integer valued, or can they include fractional values like
> 27.356?
> 
> >    while x < 0: x += 12
> >    while x >= 12: x -= 12
> > 
> > Okay, that works. Just wondering if there is an easier (or faster) way to
> > accomplish this.
> 
> 
> One approach is to just re-scale the numbers from the range -50...50 to
> 0...12 inclusive. That is:
> 
>     before => after
>     -50 => 0
>     0 => 6
>     50 => 12
> 
> 
> and everything in between is scaled equivalently. Given x between -50 and 50
> inclusive, calculate:
> 
>     y = (x+50)/100.0*12
> 
> 
> (Note that in Python 2, you need to make at least one of those values a
> float, otherwise you may get unexpected results.)
> 
> That will give you y values from the range 0.0 to 12.0 inclusive. If x is
> less than -50.0 or more than +50.0 y will likewise be out of range. You can
> clip the result:
> 
>     y = min(12.0, max(0.0, y))
> 
> If your x values are integer values (no fractional values) between -50 and
> +50 you can use clock arithmetic. Think of a clock marked 0 to 12 (so there
> are 13 values), once you reach 12 adding 1 takes you back to 0.
> 
>     0, 13, 26, 39 => 0
>     1, 14, 27, 40 => 1
>     2, 15, 28, 41 => 2
>     ...
>     12, 25, 38, 51 => 12
> 
> 
> Extending that to negative values in the most obvious fashion:
> 
>     -1, -14, -27, -40 => 12
>     ...
>     -12, -25, -38, -51 => 1
>     -13, -26, -39, -52 => 0
>     
> 
> We can do that easily with the % (modulo) operator:
> 
>     y = x % y
> 
> 
> Modulo even works with non-integer values:
> 
> py> 13.5 % 13
> 0.5
> 
> 
> 
> -- 
> Steven

Thanks for this Steven. However, I think it's not correct in this case. Like I said in another message X%12 is working just fine. No matter what the value is.

[toc] | [prev] | [next] | [standalone]


#93411

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-07-02 05:41 +0100
Message-ID<mailman.234.1435812108.3674.python-list@python.org>
In reply to#93394
On 02/07/2015 01:12, bvdp wrote:
> Not sure what this is called (and I'm sure it's not normalize). Perhaps "scaling"?
>
> Anyway, I need to convert various values ranging from around -50 to 50 to an 0 to 12 range (this is part of a MIDI music program). I have a number of places where I do:
>
>     while x < 0: x += 12
>     while x >= 12: x -= 12
>
> Okay, that works. Just wondering if there is an easier (or faster) way to accomplish this.
>

Further to other answers have you tried looking for a library, or even 
just a recipe, that has already been written and tested that does this 
for you?

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#93426

FromSkip Montanaro <skip.montanaro@gmail.com>
Date2015-07-02 10:05 -0500
Message-ID<mailman.244.1435849550.3674.python-list@python.org>
In reply to#93394
This looks like a straightforward linear transformation issue to me
(like Fahrenheit to Celsius). Add 50 to all input values, giving you
values in the range 0 to 100. Then scale them into your 0 to 12 range
by multiplying them by 12/100:

>>> for n in range(-50, 50, 3):
...   print n, n + 50, (n + 50) * 12 / 100
...
-50 0 0.0
-47 3 0.36
-44 6 0.72
-41 9 1.08
-38 12 1.44
...
34 84 10.08
37 87 10.44
40 90 10.8
43 93 11.16
46 96 11.52
49 99 11.88

Did I misread your request in some way?

Skip

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web