help with math

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have code that is trying to make a curve. My product in this case is a usb device. I dont have any form of out put other then that. The results are always 0, and I;m stuck working blind? Does anyone see the error in my ways, or have a debuger that can out put the vales for me?

char v1=0,v2=0;

		for (timer = 1; timer < 256; timer++) 
		{

			if ( PIND & (1<<5) ) 
			{

				v1 = exp(.0301 * timer );
			}

			if ( PIND & (1<<7) ) 
			{
				v2 = exp(.0301 * timer );
			}
		asm("nop\n nop\n nop\n nop\n");
		}

reportBuffer[2] = 0.1775 *v1;
reportBuffer[3] = 0.1775 *v2;

reportBuffer[2] and reportBuffer[3] always show 0. I did try to make v1,2 an int, but it didnt help. in the end the report must be a char.

FYI volatile char reportBuffer[8];

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When the for loop is over, timer will ALWAYS be 255. .0301 * 255 is 7.67. exp(7.67) should be 2154.9. That is WAAAY outside of valid char range. Not surprised it would show zero.

Secondly, that loop is going to go through its full count of 255 in a few microseconds unless you have a PORTD.5 or PORTD.7 high before the loop even starts. If it is a manually operated switch, the loop will be gone before you even get a button pushed. Then, v1 and v2 will only have their initialized values of zero, and that is all you will ever see.

So, there are at least two problems with this bit of code.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you *really* want to be doing floating point math on an AVR? (the answer almost always is "no"...)

exp() wants and returns floats; stuffing a float into a char (or even an int) won't work too well. ftoa() may help here. In any case, check the flow of your code; without any more information about what you are trying to do, it still looks wrong to me.

/mike

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk, yes its designed that way. This is what it normally looks like

		for (timer = 1; timer < 256; timer++) 
		{

			if ( PIND & (1<<5) ) 
			{

				reportBuffer[2] = timer;
			}

			if ( PIND & (1<<7) ) 
			{
				reportBuffer[3] = timer;
			}
		asm("nop\n nop\n nop\n nop\n");
		}

The problem is the device its measuring is way to logarithmic. The code is is model to make it linear. but I dont know how to use the exp with floating point math on an AVR to make it work. I'd like to try ftoa, what include do I need, cant seem to find it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suspect the PIND bits are never set. Otherwise, if I did my analysis properly (unlikely) you will get zero if and only if timer<60.

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

cpluscon wrote:
I suspect the PIND bits are never set. Otherwise, if I did my analysis properly (unlikely) you will get zero if and only if timer<60.
the code works without the exp math. Here is the out put

expected:result 
1	1
8	1
16	1
24	1
32	1
40	1
48	1
56	1
64	1
72	2
80	2
88	3
96	3
104	4
112	5
120	6
128	7
136	8
144	10
152	12
160	15
168	20
176	24
184	31
192	42
200	63
201	91
208	159
216	238
224	240 

With the exp the result is always 0. So it must be the floating point precision.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
timer = 59;
v1 = exp(.0301 * timer ); // so v1=5
reportBuffer[2] = 0.1775 *v1; // = 0

Note: This is based on your original code. Your second listing lost me.

(I'm assuming reportBuffer is an integral type.)

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Note: This is based on your original code. Your second listing lost me.
the original works?

Quote:
(I'm assuming reportBuffer is an integral type.)
See above its a char array.

I use a sprintf and that seems to do the trick

Last Edited: Mon. Feb 1, 2010 - 11:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
the original works?
Not sure if you are asking or telling with that statement. With your original code the result in reportBuffer[2] and [3] will be zero if your PIND events occur only for any value of timer<60.

And, as (the other) Jim pointed out, rollover occurs well before 255.

Edit:

I compiled it and reportBuffer[2] goes negative at 162. Besides timer<60 zero results for timer=184 and timer=207.

(I'm using gcc version 4.3.2 (WinAVR 20090313))

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes the original code woks, just didnt know why you questioned it. Granted more info would be needed but that was not the issue. I used this to see the results

sprintf(reportBuffer[2], "%.2f", 0.1775 *v1 );
sprintf(reportBuffer[3], "%.2f", 0.1775 *v2 );

I will have to find a c compiler to see whats its doing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
sprintf(reportBuffer[2], "%.2f", 0.1775 *v1 ); 

Now that certainly doesn't do what you think it does. I'm surprised it compiles since the first argument to sprintf should be a char* not a char.

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right you are, not sure why it looked like it was working, but it most certainly is not ;) I can not find a way to get a float to a char to save my life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't really know what you are accomplishing with the exp() but you should likely be able to achieve a similar result by using integer arithmetic based on using 2 as the base (instead of 2.718).

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or simply use a lookup table with interpolation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Or simply use a lookup table with interpolation.
I though of this but would that not get expensive on the region text? I like the base 2 logic idea, that should work but going to take a bit before I get it working, tricky math.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1- If you need to report FP data through a byte array, you will need to encode it. Either BCD or whatever else works.

2- Considering the huge amount of memory lost to floating point libraries being compiled in with your project, a lookup table would almost certainly be better. It would definitely be a LOT faster.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thx guys, going to try a look up of 256 levels. Guessing a case would be better then an if.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S_K_U_N_X wrote:
thx guys, going to try a look up of 256 levels. Guessing a case would be better then an if.

or an indexed array. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I still dont understand 'a device thats going to make a curve'. I THINK you are describing a 'transfer function' or an output vs input graph where a linear input would give an exponential output? Like a square wave input gives a charging-discharging capacitor 'sharkfin' waveform? If so, this does it: you have demand and position variables, and the equation is position=position+(1/16th)*(dem-pos); In other words you always add a 16th of the difference between demand and position to position. The control theory guys call this a 'first order lag'. Hope this helps??

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey bobgardner, I thinking doing this in the code is actually not the best idea.. As for the "question" the indexed array was perfect! but now that its linear I'm realizing I lost too much data..

So here is what I have.. Please any and all idea welcome!

1) I have an atari paddle, its a pot connected like a voltage regulator. From what I know this was done so that the atari system could use a timer instead of measuring resistance, in so that the jumpy-ness is eliminated. Or so I'm told. At any rate.. This is what I'm tiring to do as well..

I'm using a 556 timer to measure the time it take to fill a cap. The problem is my result are vary logarithmic. Sort make its hard to use...

Here is the code that samples the timer.

//paddle reader..
		DDRB &= ~(1<<5);//the analog of paddle
		PORTB |= (1<<5);

		DDRD &= ~(1<<3);//the analog2 of paddle
		PORTD |= (1<<3);

		DDRD &= ~(1<<7);//set read lead to high
		PORTD |= (1<<7);

		DDRD &= ~(1<<5);//set read2 lead to high
		PORTD |= (1<<5);

		DDRC  |= (1<<0);//+5 pin.
		PORTC |= (1<<0);


		DDRD	|= (1<<6);
		PORTD	&= ~(1<<6);// trigger low, starts timer
		PORTD	|= (1<<6);// trigger high again

for (timer = 0; timer < 255; timer++) 
{

	if ( PIND & (1<<5) ) 
	{

		reportBuffer[3] = timer;
	}

	if ( PIND & (1<<7) ) 
	{
		reportBuffer[2] = timer;
	}

asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");

}

The schematic for the timer is here

http://denki.world3.net/retroadapter/sch-ataripaddles.png I had to change out the 1nf cap to a 10nf to get the results. With the 1nf I was not able to sample it as it was way to fast.. Although with the 1nf its still logarithmic.

Now here is the kick in the arss.. I'm told from the author of this schematic and many other source that this method should be linear.. Yet I have 3 paddles all doing the same thing. Yes these paddle are 30 some years old, and I have opened a few and cleaned them. But still the same results. I'm not sure why I have such a dramatic exponential result.

here is some data to show what I mean.

position on the paddle / results in [timer] / results in [timer] with a 250k resistor across the 1 meg ohm vr
1	16	16
2	126	120
3	180	169
4	201	186
5	218	201
6	229	209
7	236	215
8	241	220	
9	245	223
10	248	225
11	250	227
12	252	229
13	253	230
14	254	231
15	254	232
16	254	233
17	254	233
18	..	234
19	..	234
20	..	235
21	..	235
22	..	236
23	..	236
24	..	236
25	..	236
26	..	237
27	..	237
28	..	237
29	..	237
30	..	237