# Help with fscale function

Hello everyone, can someone explain me what does fscale function exactly do?

https://playground.arduino.cc/Main/Fscale/

The description from the link says it all

This function will scale one set of floating point numbers (range) to another set of floating point numbers (range)

It is like the map() function only for floats but with extra abilities. Have you tried any examples ? What do you have in mind to use it for ?

This is the code where i use it. Actually, i would like to understand what the code exactly does with analogRaw value, which is get from a microphone input.

``````#define FASTLED_INTERRUPT_RETRY_COUNT 0
#define FASTLED_ALLOW_INTERRUPTS 0
#include <FastLED.h>
#include <ESP8266WiFi.h>

#define LED_PIN D2
#define NUM_LEDS 144

#define MIC_LOW 0
#define MIC_HIGH 644

#define SAMPLE_SIZE 20
#define LONG_TERM_SAMPLES 250
#define BUFFER_DEVIATION 400
#define BUFFER_SIZE 3

#define LAMP_ID 1

CRGB leds[NUM_LEDS];

struct averageCounter *samples;
struct averageCounter *longTermSamples;
struct averageCounter* sanityBuffer;

float globalHue;
float globalBrightness = 255;
int hueOffset = 120;
float hueIncrement = 0.7;

struct averageCounter{
uint16_t *samples;
uint16_t sample_size;
uint8_t counter;

averageCounter(uint16_t size) {
counter = 0;
sample_size = size;
samples = (uint16_t*) malloc(sizeof(uint16_t) * sample_size);
}

bool setSample(uint16_t val) {
if (counter < sample_size) {
samples[counter++] = val;
return true;
}
else {
counter = 0;
return false;
}
}

int computeAverage() {
int accumulator = 0;
for (int i = 0; i < sample_size; i++) {
accumulator += samples[i];
}
return (int)(accumulator / sample_size);
}

};

void setup()
{
globalHue = 0;
samples = new averageCounter(SAMPLE_SIZE);
longTermSamples = new averageCounter(LONG_TERM_SAMPLES);
sanityBuffer    = new averageCounter(BUFFER_SIZE);

while(sanityBuffer->setSample(250) == true) {}
while (longTermSamples->setSample(200) == true) {}

Serial.begin(115200); // Start the Serial communication to send messages to the computer
delay(10);
Serial.println('\n');
}

void loop()
{
soundReactive(analogRaw);

}

void soundReactive(int analogRaw) {

int sanityValue = sanityBuffer->computeAverage();
if (!(abs(analogRaw - sanityValue) > BUFFER_DEVIATION)) {
sanityBuffer->setSample(analogRaw);
}
analogRaw = fscale(MIC_LOW, MIC_HIGH, MIC_LOW, MIC_HIGH, analogRaw, 0.4);

if (samples->setSample(analogRaw))
return;

uint16_t longTermAverage = longTermSamples->computeAverage();
uint16_t useVal = samples->computeAverage();
longTermSamples->setSample(useVal);

int diff = (useVal - longTermAverage);
if (diff > 5)
{
if (globalHue < 235)
{
globalHue += hueIncrement;
}
}
else if (diff < -5)
{
if (globalHue > 2)
{
globalHue -= hueIncrement;
}
}

int curshow = fscale(MIC_LOW, MIC_HIGH, 0.0, (float)NUM_LEDS, (float)useVal, 0);
//int curshow = map(useVal, MIC_LOW, MIC_HIGH, 0, NUM_LEDS)

for (int i = 0; i < NUM_LEDS; i++)
{
if (i < curshow)
{
leds[i] = CHSV(globalHue + hueOffset + (i * 2), 255, 255);
}
else
{
}

}
delay(5);
FastLED.show();
}

float fscale(float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve)
{

float OriginalRange = 0;
float NewRange = 0;
float zeroRefCurVal = 0;
float normalizedCurVal = 0;
float rangedValue = 0;
boolean invFlag = 0;

// condition curve parameter
// limit range

if (curve > 10)
curve = 10;
if (curve < -10)
curve = -10;

curve = (curve * -.1);  // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output
curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function

// Check for out of range inputValues
if (inputValue < originalMin)
{
inputValue = originalMin;
}
if (inputValue > originalMax)
{
inputValue = originalMax;
}

// Zero Refference the values
OriginalRange = originalMax - originalMin;

if (newEnd > newBegin)
{
NewRange = newEnd - newBegin;
}
else
{
NewRange = newBegin - newEnd;
invFlag = 1;
}

zeroRefCurVal = inputValue - originalMin;
normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float

// Check for originalMin > originalMax  - the math for all other cases i.e. negative numbers seems to work out fine
if (originalMin > originalMax)
{
return 0;
}

if (invFlag == 0)
{
rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;
}
else // invert the ranges
{
rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);
}

return rangedValue;
}
``````
``````analogRaw = fscale(MIC_LOW, MIC_HIGH, MIC_LOW, MIC_HIGH, analogRaw, 0.4);
``````

As the same parameters are used for both input and output ranges there is no mapping as such but the output will presumably be biased towards the high end due to the scale factor of 0.4

How did you arrive at the value of 0.4 for the curve parameter ?

I think is an arbitrary value.

What about the second usage of fscale?

The second use does linear mapping because of the use of a curve value of the curve parameter. You might just as well use the map() function as all of the parameters are integers

I'm sorry but i'm quite inexperienced in this topic. Can you please explain me what is a linear mapping in simple words?

Linear mapping :

Given an input value in the range 0 to 255 you could map it linearly to an output value of say 0 to 7 using the map() function

``````outputValue = map(inputValue, 0, 255, 0, 7);
``````

So it changes the value of the input to another in a different range, and it does that liearly, because the curve parameter is 0. So what happens if i change that value?

If you change the curve value then the output will be biased to one end or the other. Have you read the page that you linked to and tried the examples ?

Ok I think I understand. Thank you very much.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.