Trough Detector

With the sketch that follows, I’m trying to toggle the output pins for the sine output such that it goes from dim to bright and back to dim on one pin and then do likewise on the other, …

byte transistorPin;
byte x;
float previousVal;

void setup()
{
  pinMode(transistorPin, OUTPUT); 
  transistorPin = 9;
  x = 1;  // freq of the ramping
}

void loop()
{ 
  float val = (exp(sin(millis()/1500.0*x*PI)) - 0.36787944)*108.0;
  if((previousVal > 0) && (val == 0))  // trough detector
  {
    if(transistorPin == 9)
    {
      transistorPin = 10;
    }
    else
    {
      transistorPin = 9;
    }
  }
  analogWrite(transistorPin, val);
  previousVal = val;
}

Viz. my “trough detector”,
if((previousVal > 0) && (val == 0))
I’m looking for when the previous value was greater than zero, but the current value is 0, indicating that it’s bottomed out.
However, at times the output pin (“transistorPin”) doesn’t change.

I don’t know if it’s not changing, or it’s doing a double-take, or it’s not making it to 0.
Care to open my eyes (or maybe kick sand in my face)?

You cannot reasonably expect a floating point computed value to equal zero, since your calculations will have
rounding errors. Perhaps you meant to test for the value being very small?

Show in the sketch that you are working with floats, by using “0.0”.
Like this: if((previousVal > 0.0) && (val < 0.2))
A value of just “0” indicates integers.

As MarkT wrote, val can not be expected to be 0.0, it might be 0.00001.

OK, well it does alternate, but every several times it woofs it.
I'll try to incorporate your suggestions and report back.

if((previousVal > 0.0) && (val < 0.2))
made it worse.

I can see that as consistent with the code now doing what it is being told - albeit it is not told to do what you want.

If you want to test for 0 in a situation where you are content with “close to 0” I suggest you create and extra calculation something like

boolean nearZero = false;
if (val > -0.2 && val < 0.2) {
    nearZero = true;
}

and then use that in the test where you are now testing val == 0

…R

I think the result of this:

val = (exp(sin(millis()/1500.0*x*PI)) - 0.36787944)*108.0;

is a value between -40 and 68.
I have actually no idea what those numbers are and what they do and why.
But with a value of -40 and 68, the 0.2 might be too small.

Start with this:

boolean nearZero = false;
if (val > -1.0 && val < 1.0) {
    nearZero = true;
}

not that it matters, but I am curious why you set up (pin0?) as an output. Is this part of larger code?

byte transistorPin;
byte x;
float previousVal;

void setup()
{
  pinMode(transistorPin, OUTPUT);
  transistorPin = 9;
  x = 1;  // freq of the ramping
}
    if(transistorPin == 9)
    {
      transistorPin = 10;
    }
    else
    {
      transistorPin = 9;
    }

Is a very long-winded way of writing transistorPin = 19 - transistorPin;

(there's no need to set the pinMode of a PWM pin, and if there were, it would be best to set the mode of both pins used)

Robin2:

boolean nearZero = false;

if (val > -0.2 && val < 0.2) {
   nearZero = true;
}

Bit clumsy? Why not:

  if (abs (val) < 0.2)
  { 
    ..
  }

Peter_n:
I think the result of this:

val = (exp(sin(millis()/1500.0*x*PI)) - 0.36787944)*108.0;

is a value between -40 and 68.
I have actually no idea what those numbers are and what they do and why.
But with a value of -40 and 68, the 0.2 might be too small.

Start with this:

boolean nearZero = false;

if (val > -1.0 && val < 1.0) {
    nearZero = true;
}

The equation is the work of another. He had trouble with it “not working”, but after a lot of post and counter-post, “not working” turned out how to seamlessly change the rate of change (with x derived from a “sensor reading”.)
I liked the effect and thought it would be kind of novel to have it go out on alternating outputs.

I, too, thought about using a Flag (“nearZero”)

BulldogLowell:
not that it matters, but I am curious why you set up (pin0?) as an output. Is this part of larger code?

Maybe you meant why I didn’t set up pin 10 as an output?
I didn’t know that analogWrite didn’t require a pinMode. (now I’m wise - to that.)

No, there’s no “larger code”, this is all that there is.

cheers,

one can never assume…

nice problem you are working out.

val “is a value between -40 and 68.”

I got the “original” version of the sketch, just one output, and did
Serial.println(val,DEC);
before ea. analogWrite
and val ranges from mouse-nuts to > 250 and change.
It starts out right around “68” though.

The value of val at the trough:

1
0.04219
A 0.0055
B 0.0042 ***
C 0.11304

2
A 0.025189
B 0.0000901 ***
C 0.014728

3
A 0.0589
B 0.012546 ***
C 0.0139
D 0.0282

So I need to keep rolling track of values of val
and test for when (A > B) && (B < C)
Then I would know that the trend had just begun upward again.

In that case keep track of the difference between successive samples and watch for the sign changing. Using your first data set

curr - prev = 0.0042 - 0.0055 = -0.0013
curr - prev = 0.11304 - 0.0042 = 0.10884

if (curr - prev > 0) { // signifies the values are rising

...R

I think tht I understand what you’re saying.
If the preceding current-previous were negative (<0) and the immediate current-previous were positive then that would indicate that the progress is pulling out of the trough.

I tried this

byte transistorPin;
byte x;
float previousVal;
float formerDiff;  // preceding  (current - previous)
float currentVal;

void setup()
{
  pinMode(transistorPin, OUTPUT); 
  transistorPin = 9;
  x = 1;  // freq of the ramping
  previousVal = 100.0;  // starter value, magic number
  formerDiff = -20.0;   // starter value, magic number
}

void loop()
{ 
  currentVal = (exp(sin(millis()/1500.0*x*PI)) - 0.36787944)*108.0;
  if(((currentVal-previousVal)>0) && (formerDiff>0)) // trough det.
  {
    // to swap pins
    if(transistorPin == 9)
    {
      transistorPin = 10;
    }
    else
    {
      transistorPin = 9;
    }
  }
  analogWrite(transistorPin, currentVal);
  formerDiff = currentVal - previousVal;
  previousVal = currentVal;
}

but it doesn’t change (it’s stuck on pin 9.).

If I change the “trough detector” to
if(((currentVal-previousVal)>0) && (formerDiff>=0)) // trough det
then it kind of does it weird like on both pins, hard to describe.

I wonder if this line should be as follows

(currentVal-previousVal)>0) && (formerDiff<0

…R

Yes - it was getting late, that’s how I had it, but I started grasping at straws and just chucked the >.
So, sorry for any mix up.

This isn’t happening (but should):

byte transistorPin;
byte x;
float currentVal;
float previousVal;
float formerDiff;  // old    currentVal - previousVal
float currentDiff; // latest currentVal - previousVal

void setup()
{
  pinMode(transistorPin, OUTPUT); 
  transistorPin = 9;
  x = 1;                // freq of the ramping
  previousVal = 100.0;  // starter value, rubbishy
  formerDiff = -20.0;   // starter value, rubbishy
}

void loop()
{ 
  currentVal = (exp(sin(millis()/1500.0*x*PI)) - 0.36787944)*108.0;
  currentDiff = currentVal - previousVal;
  if( (currentDiff>0) && (formerDiff < 0) ) // 
  {
    // trough detected, so swap pins
    swap_pins();
  }
  analogWrite(transistorPin, currentVal);
  formerDiff = currentVal - previousVal;
  previousVal = currentVal;
}

void swap_pins ()
{
  if(transistorPin == 9)
  {
    transistorPin = 10;
  }
  else
  {
    transistorPin = 9;
  }
}

So, I said “Rats! Why not??”
Then I punched in some Serial.prints to get some data (currentVal, currentDiff, formerDiff)

byte transistorPin;
byte x;
float currentVal;
float previousVal;
float formerDiff;  // old    currentVal - previousVal
float currentDiff; // latest currentVal - previousVal

void setup()
{
  pinMode(transistorPin, OUTPUT); 
  transistorPin = 9;
  x = 1;                // freq of the ramping
  previousVal = 100.0;  // starter value, rubbishy
  formerDiff = -20.0;   // starter value, rubbishy
  Serial.begin(9600);
  delay(1000);
}

void loop()
{ 
  currentVal = (exp(sin(millis()/1500.0*x*PI)) - 0.36787944)*108.0;
  currentDiff = currentVal - previousVal;

  Serial.print(currentVal,DEC);
  Serial.print(" _ ");
  Serial.print(currentDiff,DEC);
  Serial.print(" _ ");
  Serial.println(formerDiff,DEC);

  if( (currentDiff>0) && (formerDiff < 0) ) // 
  {
    // trough detected, so swap pins
    swap_pins();
  }
  analogWrite(transistorPin, currentVal);
  formerDiff = currentVal - previousVal;
  previousVal = currentVal;
}

void swap_pins ()
{
  if(transistorPin == 9)
  {
    transistorPin = 10;
  }
  else
  {
    transistorPin = 9;
  }
}

And all that data looked right.
And then I noticed - it was working perfectly !

I deleted all of the Serial.prints and it bombs.
If I leave just one of those in then it works.
So, What Gives?

analogWrite( ) is expecting an integer between 0 and 255, not a float.

Rather than relying on some implicit conversion to occur in the function call, I would be converting the value beforehand and checking it's limits.

The fading up/down works.
(This is a pretty easy circuit to set up.)

The conundrum has been in steering the fading action into alternating outputs.
In the original version, that didn't go consistently.
With the latest Trough Detector's comparing trends, it stayed stuck (stuck on 1 output ) till I introduced some Serial.,print statements whereupon (mysteriously?) it works.

Clarification - "stuck on 1 output"

Is this a fringe benefit of float? you can't dive right when you want to?

Serial.print() is a good substitute for a short delay().

I wonder if analogWrite() doesn't like being asked to switch pins at too short intervals.

I would try substituing all the Serial.print()s with the shortest delayMicroseconds() that works (assuming the substitution does work) and then I would see if it matters where within loop() the delay is placed.

...R