scaling logarithmic signal for analogRead

I'm having a programming question that's more a mathematical problem:

In my project, my Arduino reads the signal (of a volumepedal) via analogRead and gives a value between 0-1023.

The problem is that this value rises to the maximum very quick (it's logarithmical because it's a volumepedal).

Is there a way to scale the read value so that it doesn't rise that fast and will only rise in a linear way to the maximum value when the pedal is pushed down completely?

Thank you for your help and comments!

Is there a way to scale the read value so that it doesn't rise that fast and will only rise in a linear way to the maximum value when the pedal is pushed down completely?

The analog value will be between 0, when the pedal isn't pressed, and 1023 when it is floored. No amount of programming will change that fact or the fact that the values read will, when plotted, not be linear when plotted against the angle of the pedal.

Now, that isn't to say that you could not use the log() or exp() functions, with the analog value as input to get an output value that, when plotted, resulted in a line.

Emilevh: Is there a way to scale the read value so that it doesn't rise that fast and will only rise in a linear way to the maximum value when the pedal is pushed down completely?

You cannot change the value that analogRead() produces. But you could do some maths on the received values to give less weight to the higher values - i.e. to counteract the effect of the log scale in the volume pedal.

Would it be possible to replace the log potentiometer in the volume pedal with a linear pot?


PS... For the future please keep all questions about one project in the same Thread as that makes it easier for everyone to see all the information

it seems rather impossible, see -

You could use multiMap to have a good approximation. - -

Some ideas from the past -

robtillaart: it seems rather impossible, see -

That link is about using external circuitry to give a log pot a linear response.

Robin is suggesting physically replacing the log pot in the pedal with a linear one, a completely different thing.

If you use only maths, you will have the problem that the quantization (conversion of real to integer) of the input values will be magnified at one end of the scale. This will give you a "choppy" or step response. If you were using an ADC with more bits, like 12 or 16, it would play better. But with the Arduino you only have 10.

Thanks all for your help and feedback.

With this post I want to share the solution I found for my problem.

I could find in the end a somewhat unorthodox solution for my problem with the help of the fscale function, which I found here: (it’s not in the library so the function is copied in my sketch.

With the help of Serial.println I could read the value my pedal is giving in different angles and then just took the part with the smallest difference in respons and rescaled this part in a linear way (with the fscale-function). It’s not precise, but for my application it does the job.

Concerning my setup: I use the arduino motor shield controller, and there the pins for motor control are predefined, so the code should be adapted somewhat if you’re not using the controller shield.

Best wishes

#include <math.h>

 float analogPin = A0;
 int pwmPin = 3; // speed control Channel A

void setup() {
  //Setup Channel A of the motor shield
  pinMode(12, OUTPUT); //Initiates Motor Channel A pin
  pinMode(9, OUTPUT); //Initiates Brake Channel A pin
  digitalWrite(12, HIGH); //Establishes forward direction of Channel A
  digitalWrite(9, LOW); //Disengage brake

void loop() {

   float pwmVal;
   float adcVal;
   float scaled;
   int pwmValInt;
   adcVal = analogRead(analogPin);
   scaled = fscale(1008, 1023, 0, 1023 , adcVal, 0);
   pwmVal = scaled / 4;  // converts 0-1023 to 0-255
   pwmValInt = (int) pwmVal;
   analogWrite(pwmPin, pwmValInt); 
   delay(100); // simple way to limit updates to 10 times per second

   // test reading signal
   int sensorValue = analogRead(A0);
   float sensorValueFloat = (float) sensorValue;

//function fscale 
 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

   Serial.println(curve * 100, DEC);   // multply by 100 to preserve resolution  

  // 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;
    NewRange = newBegin - newEnd;
    invFlag = 1;

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

  Serial.print(OriginalRange, DEC);  
   Serial.print("   ");  
   Serial.print(NewRange, DEC);  
   Serial.print("   ");  
   Serial.println(zeroRefCurVal, DEC);  

  // 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;