Support

If you have a problem or need to report a bug please email : support@dsprobotics.com

There are 3 sections to this support area:

DOWNLOADS: access to product manuals, support files and drivers

HELP & INFORMATION: tutorials and example files for learning or finding pre-made modules for your projects

USER FORUMS: meet with other users and exchange ideas, you can also get help and assistance here

NEW REGISTRATIONS - please contact us if you wish to register on the forum

Help With Ruby Normalization

For general discussion related FlowStone

Help With Ruby Normalization

Postby adamszabo » Tue Jul 02, 2019 8:22 pm

Hey everyone!

I am trying to figure out how to mimic the green "Norm" module with Ruby, so that it normalizes an incoming float array to -1 to 1 range. Its description says "Normalises a float array so that the values are between -1 and 1". I tried looking online for some examples but didnt manage to have the same results as the green module. Does anybody have an idea of a formula how it works?

Thanks!
adamszabo
 
Posts: 657
Joined: Sun Jul 11, 2010 7:21 am

Re: Help With Ruby Normalization

Postby RJHollins » Tue Jul 02, 2019 8:56 pm

Try looking for 'Rational Mapper', or 'Float Scaler'.

I know we had some from the SM toolboxes.
RJHollins
 
Posts: 1568
Joined: Thu Mar 08, 2012 7:58 pm

Re: Help With Ruby Normalization

Postby martinvicanek » Tue Jul 02, 2019 9:27 pm

if a[k] is the array divide each element by max_{k=0...K} |a[k]|
User avatar
martinvicanek
 
Posts: 1318
Joined: Sat Jun 22, 2013 8:28 pm

Re: Help With Ruby Normalization

Postby tulamide » Tue Jul 02, 2019 10:09 pm

martinvicanek wrote:if a[k] is the array divide each element by max_{k=0...K} |a[k]|

That's producing the range 0, 1 if the numbers are all positive (which for example midi numbers would be). So additionally add ... (- 0.5 * 2) in that case.

Adam, normalizing usually means to set the highest value equal to 1. You do that by dividing all numbers by the highest one. That's what Martin wrote above (in case you are like me and enjoy a little explanation over complicated math).

4/4 = 1
2/4 = 0.5
-2/4 = -0.5
-4/4 = -1

It can get more tricky if the range is somewhat odd, like -2 to 13, or 1 to 9.

EDIT: Ok, here's code in case you indeed want the numbers to be exactly matched to -1 and +1, and don't want to be frustrated by trying it for yourself
Code: Select all
#some array
a = [-4, 5, 8]

#range covered in array
amin = a.min
amax = a.max
arange = amax - amin

#range we want the array to map to
rmin = -1.0
rmax = 1.0
rrange = rmax - rmin

#map the numbers
r = a.map { |n| n = rmin + (n - amin) * (rrange / arange)}

##of course you can change rmin and rmax to your liking, should you need
##to normalize differently (like 0 to 1, for example)
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2687
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Help With Ruby Normalization

Postby adamszabo » Tue Jul 02, 2019 11:44 pm

Thanks guys very much appreciated!

Ive tried these but got different results from the Norm module and I started investigating more and with your guys help I figured it out. What the Norm does it finds the largest value, and multiplies it by the difference so that highest value will reach 1. So it does an ABS on all the values, finds the largest, divides 1 by that, and multiplies the entire array like so:

Code: Select all
a = @input

output 0, a.map { |n| n * 1 / ( (a.map { |n| n.abs }).max )}
adamszabo
 
Posts: 657
Joined: Sun Jul 11, 2010 7:21 am

Re: Help With Ruby Normalization

Postby trogluddite » Wed Jul 03, 2019 1:59 am

adamszabo wrote:So it does an ABS on all the values, finds the largest, divides 1 by that, and multiplies the entire array like so:

Yes; for normalising audio signals, that makes sense - you need to scale around zero so that a DC offset doesn't get introduced.

NB) The code would work much more efficiently like this...
Code: Select all
scale = 1.0 / array.max_by{|x| x.abs }
output(0, array.map{|x| x * scale })

Having the scale calculation inside the mapping code block gives you a loop within a loop - the number of iterations goes up with the square of the number of array elements. With scaling moved outside, it's only double the number of elements.

The method max_by handily makes it even more efficient because it doesn't need to create a temporary mapped Array before calling max on it; there's also a min_by method, and even a maxmin_by that gets both at once. They come from the Enumerable module, which is a component of most Ruby containers - it's always worth checking if you don't see what you want under the listings for Array or Hash.)
All schematics/modules I post are free for all to use - but a credit is always polite!
Don't stagnate, mutate to create!
User avatar
trogluddite
 
Posts: 1730
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK

Re: Help With Ruby Normalization

Postby tulamide » Wed Jul 03, 2019 5:43 am

trogluddite wrote:
adamszabo wrote:So it does an ABS on all the values, finds the largest, divides 1 by that, and multiplies the entire array like so:

Yes; for normalising audio signals, that makes sense - you need to scale around zero so that a DC offset doesn't get introduced.

NB) The code would work much more efficiently like this...
Code: Select all
scale = 1.0 / array.max_by{|x| x.abs }
output(0, array.map{|x| x * scale })

Having the scale calculation inside the mapping code block gives you a loop within a loop - the number of iterations goes up with the square of the number of array elements. With scaling moved outside, it's only double the number of elements.

The method max_by handily makes it even more efficient because it doesn't need to create a temporary mapped Array before calling max on it; there's also a min_by method, and even a maxmin_by that gets both at once. They come from the Enumerable module, which is a component of most Ruby containers - it's always worth checking if you don't see what you want under the listings for Array or Hash.)


Now that I see Adam's finding and a nice, clean code from Trog, I think I have to apologize to Martin. Doesn't |a[k]| mean the product of (or absolute of) a for k = 0 to array length? Or do I start to drift right now?
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2687
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Help With Ruby Normalization

Postby martinvicanek » Wed Jul 03, 2019 6:19 am

tulamide wrote:Doesn't |a[k]| mean the product of (or absolute of) a for k = 0 to array length?

Yes, I meant the maximum of all absolute values. ;)
User avatar
martinvicanek
 
Posts: 1318
Joined: Sat Jun 22, 2013 8:28 pm

Re: Help With Ruby Normalization

Postby adamszabo » Wed Jul 03, 2019 9:29 am

Thanks you guys are awesome!

Trog your code is great, however I noticed that sometimes my graph was inverted and I noticed that your way of getting abs was givingdifferent results. So if I have a dataset like this:

0
-0.9
0.7

My one "(@input.map { |n| n.abs }).max" gives 0.9
And your one "@input.max_by{|x| x.abs }" gives -0.9

So we have to make another abs on the scale itself, and maybe add a small value to prevent it from getting #IND when dividing by zero?

scale = 1.0 / (@input.max_by{|x| x.abs } + 0.00001)
output(0, @input.map{|x| x * scale.abs })
adamszabo
 
Posts: 657
Joined: Sun Jul 11, 2010 7:21 am

Re: Help With Ruby Normalization

Postby trogluddite » Wed Jul 03, 2019 9:44 pm

Oops! :oops:
Yes, you're quite right, Adam. The max_by method returns the original Array element, not the version transformed by the code block, so you need to abs what it returns.

You don't need the infinity check, though. Infinities are treated as valid number values by the CPU - wherever there is a defined mathematical result, the calculation will work; and dividing by infinity is defined to always return zero (as confirmed by stringing together a couple of float divide primitives.) BTW; strictly speaking, your code doesn't entirely exclude zero - you need to abs before adding the offset, otherwise you get zero if the sample is exactly -0.00001!
All schematics/modules I post are free for all to use - but a credit is always polite!
Don't stagnate, mutate to create!
User avatar
trogluddite
 
Posts: 1730
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK


Return to General

Who is online

Users browsing this forum: No registered users and 13 guests