Countering sigmoid curves from a analog stick

i have recently modded a ps5 controller so that i have a anlog stick soldered to a arduino and then the arduino has a duel channel digi pot outputing analog values to the controllers right stick, so that i can code custom response curves, deadzones, anti deadzones and stuff like that.

but one thing i need to do is convert what i think is a sigmoid curve applyed in game to a linear response on the arduinos side.

i have had succsess removing power curves and exponential curves and have been asking various ai chat things how i might counter a sigmoid curve in game but it never works the way i intend it, usually just making the stick go all over the place but will have small sections in the sticks travel where it behaves as you would think.

basically i am asking how you might counter the in game sigmoid curve from the arduino/controllers side bearing in mind each axis on the right stick has a range going from -125.5 to 125, 0 being the center, or if you know a better place to ask this question i am all ears

Can you show a x y graph?
Where x is input and y is desired output?


if you imagine the point where the red and blue line cross as zero, that's what i think the game is applying, probably more like the red though.

im sorry if that answer seems off i am not to familiar with actuall math side of these graphs or the curves them selfs and only know them as is relevant to analog stick aim, i am thinking of a -1 to 1 x and y grid where the point where those two lines meet would be 0

Have a look at multimap, which does a non linear mapping using two tables of values.
yes it is an approximation, and you can improve accuracy by adding points.
More points is also slower due to searching of the right interval.
Above ~20 points binary search is faster, you can use MultiMapBS

maybe just square the x input (orange) compared to the red curve in post #3

Your "counter" terminology is confusing. Assuming the first equation below, are you asking how to compute f(x) given x or x given f(x)?

image

It seems to me that the shape of the curve is not important - the main thing is that you need to shift the graph down along the y-axis so that the intersection point of the graph with the coordinates is at the 0,0 point.

And not everyone here is a gamer. So you'd do well to explain what terms like "analog stick", "applyed (sic) in a game", and "stick aim" mean.

sorry, the analog stick is just a small joy or flight stick you would use with your thumb it has 2 potentiometers, 1 for left and right and 1 for up and down.

these pots generally come with a linear response curve from the factory and this value is the initial value you would get from the game pad in the game engine that the game was made in and each pot is usually represented as a value going from -1 to 1, -1 being full left on the stick, 1 being full right on the stick for the x axis.

games will often apply different response curves to the analog sticks to try to make it easier to aim the in game camera, but there is no standardized way that game devs will code this, meaning that it is different from game to game and its actually kind of rare that they will get it right.

what i mean by countering the sigmoid curve is converting the sigmoid back to linear

the game in question i am pretty sure has a sigmoid curve applied to the right stick, witch is coded in the game engine,

i want to convert the analog sticks sigmoid response curve that is applied in game from the arduino and digi pot i have modded my controller with

So, you want x given f(x)?

image

Did you start writing the code? Please show your efforts

i dont really understand alot about these functions and only know enough of the mathy symbols to get a extremely basic idea of what the function is doing.

so i dont know exactly what your asking, i have a example of a typical sigmoid function and a example of a inverse sigmoid function but i dont know how to paste them here in a way they are readable

this is the inverse sigmoid in code,

-log((1.0 / y) - 1.0) / k;

but it does not scale properly across the sticks range

 baseX = analogRead(rsInputX) - offsetX;
  baseY = analogRead(rsInputY) - offsetY;
  
  //backButtons = analogRead(A2);
  //Serial.println(backButtons);

  if(baseX > xMax){
    xMax = baseX;
  }
  if(baseX < xMin){
    xMin = baseX;
  }
  if(baseY > yMax){
    yMax = baseY;
  }
  if(baseY < yMin){
    yMin = baseY;
  }
  

  // Normalize the readings to maintain full range
  //baseX = baseX / 512.0;
  //baseY = baseY / 512.0;

  baseX = map(baseX, 93, 913, -stickScale, stickScale);
  baseY = map(baseY, 125, 912, -stickScale, stickScale);

 // baseX = stickCalibration(baseX, offsetX);
  //baseY = stickCalibration(baseY, offsetY);

  ADOutX = map(abs(baseX), 0, stickScale, axialDeadzoneX, axialDeadzoneXMax);
  ADOutY = map(abs(baseY), 0, stickScale, axialDeadzoneY, axialDeadzoneYMax);
//RS Axial Deadzone////////////////////////////////////////
  
  if (abs(baseX) > ADOutX) {
      myX = ((abs(baseX) - ADOutX) / (outerDead - ADOutX) * outerDead) * sign(baseX);


  }
  else {
      myX = 0;

  }
  



  if (abs(baseY) > ADOutY) {
      myY = ((abs(baseY) - ADOutY) / (outerDead - ADOutY) * outerDead) * sign(baseY);


  }
  else{
      myY = 0;
  }

  float magnitude = sqrt(pow(myX, 2) + pow(myY, 2));
  rxDelt = myX - rxLast;
  ryDelt = myY - ryLast;
  Serial.println(rxDelt);
 
 rxLast = myX;
 ryLast = myY;
  
  rawX = myX; // Save the original raw X value
  rawY = myY; // Save the original raw Y value
 //magnitude = getLinearResponse(magnitude/stickScale) * stickScale;
  
  myX = myX + (rxDelt * 20);
  myY = myY + (ryDelt * 20 );
  
  
  if(myX >= 125.5){
    myX = 125.5;
  }
   if(myX <= -125.5){
    myX = -125.5;
  }
   if(myY >= 125.5){
    myY = 125.5;
  }
   if(myY <= -125.5){
    myY = -125.5;
  }
 
 
 if (magnitude > radialDeadzone){
  
     r_out = ((magnitude - radialDeadzone) / (outerDead - radialDeadzone) * outerDead);
    
    r_out = ((abs(r_out) - 0) * (outerDead - antiRadialDeadzone) / (outerDead - 0) + antiRadialDeadzone);
    //r_out = -logf(1.0f / (r_out/125.5) - 1.0f) * 125.5;
    // r_out = inverseSigmoid(r_out / stickScale) * stickScale;
    
 }
 else {

     r_out = 0;
     myX = 0;
     myY = 0;
   
     
 }

  float angle = atan2(myX, myY);
 //if (settings_.radialCalculation) {
     myY = (cos(angle) * r_out);
     myX = (r_out * sin(angle));
// }

     if (rawX != 0) { // Avoid division by zero for X axis
         float scaleFactorX = myX / rawX;
         myX = rawX * scaleFactorX;
     }

     if (rawY != 0) { // Avoid division by zero for Y axis
         float scaleFactorY = myY / rawY;
         myY = rawY * scaleFactorY;
     }

//       float normalized_r_outX = myX / stickScale;
//  float normalized_r_outY = myY / stickScale;
    
//     // Apply the inverse sigmoid function to the normalized r_out
//     float linear_r_outX = inverseSigmoid(normalized_r_outX);
//     float linear_r_outY = inverseSigmoid(normalized_r_outY);
    
//     // Scale back to the original range
//     myX = (linear_r_outX * stickScale);
//     myY = (linear_r_outY * stickScale);
//myX = inverseSigmoid(myX / stickScale) * stickScale;
//myY = inverseSigmoid(myY / stickScale) * stickScale;

 if(magnitude > stickScale * edgeAccStart){
    //tempSens = sens;
  tempSens = interpolate(tempSens, 1, edgeAccRate);
 }
 else{
  tempSens = sens;
 }
 
  myX *= tempSens;
  myY *= tempSens;

  myX = lpfX.update(myX);
  myY = lpfY.update(myY);
  //myX = rxDelt * 20;
  //myY = ryDelt * 20;
 // myX = (inverseSigmoid(abs(myX) / stickScale) * stickScale) * sign(myX);
   //myY = (inverseSigmoid(abs(myY) / stickScale) * stickScale) * sign(myY);
  
  myX = map(myX, -stickScale, stickScale, 255, 0);
  myY = map(myY, -stickScale, stickScale, 255, 0);

  //ULB = digitalRead();
  //URB = digitalRead();
  //LLB = digitalRead();
  //LRB = digitalRead();

  //if(ULB == LOW){digitalWrite(outBP1, HIGH)}else{digitalWrite(outBP1, LOW)}
  //if(URB == LOW){digitalWrite(outBP2, HIGH)}else{digitalWrite(outBP2, LOW)}
  
  //if(LLB == LOW){digitalWrite(outBP3, HIGH)}else{digitalWrite(outBP3, LOW)}
  //if(LRB == LOW){digitalWrite(outBP4, HIGH)}else{digitalWrite(outBP4, LOW)}

 //stick settings//////////////////////////////////////////////////////////////////

 //--------------------------------------------------------------------------------------
  RXOut = myX;
  RYOut = myY;
 

  DigitalPotWrite(POT0_SEL, RXOut);
  DigitalPotWrite(POT1_SEL, RYOut);
float inverseSigmoid(float y, float k) {
  return -log((1.0 / y) - 1.0) / k;
}

i need to apply this function to ether both the myX and myY variables in the code above or to the r_out variable in the code above but that inverseSigmoid() function does not give the desired effect whether it is applied to the individual x and y axis or the r_out

i will come back tomorrow with a better way to ask this question i feel like i am just being confusing

Trying to interpret your words (actually trying to mind read) ... I'm guessing you want the first plots you presented to pass through the origin and run from -1 to -1 on both axes. So the equation you presented needs to be scaled and shifted:
image

That plots as:

image

A little High School Algebra produces the inverse function (what I think you want):

image

That plots as:

image

Note that Eq 1 only approaches +/-1 asymptotically. So you'll want to clip the input (y) value to Eq 2 so that:

image

Why not simply map it, create a look-up table, and interpolate to do the conversion. Simple, and not at all resource intensive.

That's probably the best way. Certainly the simplest.

You need the numbers to put into the map.

Cough! That was sooo long ago!

FWIW the plot is exactly a line, so you got it right as far as I can tell

y\ =\ -\ \frac{\left(\ln\ \left(\frac{\left(1\ -\ \left(2/(1+e^{\left(-5x\right)})-1\right)\right)}{\left(1\ +\ \left(2/(1+e^{\left(-5x\right)})-1\right)\right)}\right)\right)}{5}

Haha, that's cut from Desmos | Graphing Calculator where I put x into the forward function H and that result of that into the inverse function H^(-1) that you showed in pictures.

HTH and thanks for reminding me of how much I have forgottten. :expressionless:

a7