Can someone help me figure out why my code is inconsistent?
turbosupra
Posts: 1,088
Attached is my object with a pulse generator and a pulse reader method. On the bench the reader works perfect, but in real life I am getting inconsistent results as shown in the terminal screen capture posted below. I've went through my code for the past week about 50 times, tried everything I know to troubleshoot and I can't figure out what I'm doing wrong so it is time to ask for help. The code always reads a lower value, never reads a higher value, and because of that I do not think it is chatter on the pin?
If anyone has any ideas/suggestions/troubleshooting techniques, I'm looking to learn. Thank you.
Numbers.spin
Float32Full.spin
rpmTest7.spin
FullDuplexSerial64.spin
If anyone has any ideas/suggestions/troubleshooting techniques, I'm looking to learn. Thank you.
Numbers.spin
Float32Full.spin
rpmTest7.spin
FullDuplexSerial64.spin
Comments
Too many IFs! Brain hurts. They look like they are dealing with roll-over, correct? The common trick is replace value1 > value2 with (value1 - value2) > 0. The subtraction before compare allows the naturally clean adder roll-over to produce a number with respect to zero, with which a compare will function cleanly. No need to have any exceptions.
Sadly enough, I thought my debug setup was pretty slick, haha ... but I'm always wanting to learn from the wise, so I will try to implement what you've discussed. How would you implement the debug code saying "I'm here right now" at any specific location, with the method you've proposed? Thank you.
Does this in essence pause the cog? I wanted to have the routine free to run other things if necessary. The frequency is very low at 2hz per (rpm/60) so it would basically disable the cog if I read this correctly.
Indeed, using a function generator, your code reports a linear increase from 1Hz (30rpm) up to 28Hz (840rpm), then at 29Hz it glitches to ~435rpm.
Commenting out all of the debug statements, except the final one that shows the average, and it can show up to 9000rpm at 300Hz input.
Best advice there is to follow Jon's advice and use a dedicated debug cog.
Have you considered using the built in counters? Either an edge detector to count the number of transitions, or a level detector to count the number of clock ticks that the signal remains high or low.
Here're a few ideas:
Because printing to the console is sloowww, when I have precisely timed projects, I will do all of my logging in a single cog. When I need to log a value, I assign it to a global variable. My debug cog then prints the value in that variable at a pre-determined frequency.
As for the "I'm at line ___ now" type of statement... that's slightly harder. You might need two variables for that: previous and current. Initialize both to 0 (does Spin have "null"?). When you hit a point that you want to log, assign `current` to some unique value. Your debug cog then checks the value of `previous` and `current` and, when not equal, prints `current` (or some string related to the value in `current`).
It would be more (I have no idea how much more) accurate to clear phs[ab] immediately after you read it using the post-clear operator x~, instead of after 3 slow divides.
Edited for a second thought.
The above is true if the pulse is symetrical (50% duty) where the calculations not being finished before the next pulse width would glitch regardless of when phsx was re-initialized, however it makes a significant difference at a 1% duty cycle. The signal only has to be high long enough for phsb to be copied and cleared, as it doesn't matter if the signal goes low during the calculations.
With the original code, the readings get glitchy around 175Hz, with Electrodude's modification the readings are stable up to 500Hz.
There's some flickering above 20Hz where the readings might be +/- 3, but aside from that it is stable.
At 29Hz, however, the readings should be 870rpm, are instead being read as 435rpm.
I took another look at it, and it seems you must have a counter rolling over somewhere. It actually does read correctly for about 12 seconds, then it reads low for about 42 seconds.
2^32 x 12.5ns = 53.687 seconds
At 30Hz and up, it is always misreading. Commenting out all of the debug statements up to the "Calculated RPM is:" line allows it to read correctly... within reason.
100Hz produces readings from 2997 to 3003. 300Hz gives 8937 to 9057.
Even with the debugs commented out, this object starts running into problems at about 361Hz - should be 10830rpm, reading 9042 to 10767.
I replaced the function generator with the freq_synth object from the Propeller library demo so you can see what I see.
Your simulateRpm method does indeed appear to give good readings from 24Hz (720rpm) to 76Hz(2280rpm). I suspect that the reason we don't see it glitch is due to the way it is constantly varying, which somehow isn't giving the counters the opportunity of rolling over, or whatever's going wrong. Try a steady signal instead.
rpmTest7a.spin
Another flaw I found today and a hard lesson to learn, which was assuredly causing me issues is that I_Rpm is based on voltage into a voltage divider of 10k and 2.7k, so voltage should be anywhere from 2.34vDc to 2.98vDc with a 11 to 14v input. This was the case when the car was not running, but when it runs the alternator does some craziness to the electrical system. Unknowingly until today, I was plagued by I_Rpm == 0 every once in a while, which puts the code in a lower power state of 1hz per loop and outputs are turned off. This was hosing my timing calculations for a frequency generator (among other things) and I've been chasing this for a few weeks now. Finally driving around with the laptop, the com window open, some additional commenting and my scope I was able to identify it. I mention all of this, because the calculateRpm was also dependent on I_Rpm == 1.
I thought about trying to solve this by using a 3k/10k resistor ladder, but decided to put a 100uF cap inline with the resistor ladder. Do you think this was the best solution? How do you normally tackle these type of automotive issues?
As for connecting to a 14 volt signal, there are level shifters, buffers, optocouplers, current limiters, voltage dividers... whatever works.
See this thread for interfacing to 5V.