Home AMX User Forum AMX General Discussion

Fuzzy Math?

In the below section of code I do frequency conversion for a direct entry keypad for an AVR module I'm working on (B&K Ref 50). I display the digits as they are entered and the code below is for the enter button. I convert the string to a double and I have tried float but long ago doing this same thing I reaslized an issue with usinf float that using a double fixed. Anyway the line commented out is the "FM" book method that comes with the receiver which works fine on a calculator bbut when I run the code it's always off by one station (.2). The same formula in reverse posted beneath works fine. The line that currently being used is just something that seems to work that I did a few years back.

Why does the commented formula work on a calculator and not through the master?
CASE 14://ENTER / DONE BUTTON
     {
     if([vdvTP_AVR_1,BnK_FB_CH_BAND])// on = FM
	  {
	  STACK_VAR DOUBLE nFreqTemp ;
	    
	  nFreqTemp = ATOF(cFreqStr) ;
	  if (nFreqTemp >= 87.5 && nFreqTemp <= 107.9)
	       {
	       //nFreqTemp = (((nFreqTemp - 87.5)/0.2) + 1); //book method
	       nFreqTemp = (((nFreqTemp - 87.3)/.2) + .000017) //my old version
	       SEND_COMMAND vdvTP_AVR_1,"'Q_HEAD_STRING:(0,S,P1=FF,6=',ITOHEX(nFreqTemp2),';)'" ;
	       SEND_COMMAND vdvTP_AVR_1,"'Q_TAIL_STRING:(0,G,P1=FF,6;)'" ;
	       }           
	  }
     else //off = AM
	  {
	  STACK_VAR INTEGER nFreqTemp ;
	    
	  nFreqTemp = ATOI(cFreqStr) ;
	  if (nFreqTemp > 520 && nFreqTemp <= 1670)
	       {
	       nFreqTemp = (((nFreqTemp - 520)/10) + 2) ;
	       SEND_COMMAND vdvTP_AVR_1,"'Q_HEAD_STRING:(0,S,P1=FF,5=',ITOHEX(nFreqTemp),';)'" ;
	       SEND_COMMAND vdvTP_AVR_1,"'Q_TAIL_STRING:(0,G,P1=FF,5;)'" ;
	       }
	  }
     cFreqStr = '' ;
     fnSendVT(nTPIndx,BnK_VT_AMFM_FREQ,'1','Tuning....') ;//tp index,vt address#,states,text
     }

If my calculator comes up with HEX 3B for the freq I type in and is diplayed on the TP when I hit enter in diagnostics I see it send 3A and they the response form the device will be 3A and then my display will correctly display the frequency using the second conversion for 3A. Some how the formula come up with 3A in the master while the calculator show it should be 3B and the subsquent display is of by .2 from what I typed in.

I'm quite confused and running out of things to try. Although I knew the old formula worked I didn't want to give in and use it but after a couple of hours I couldn't take it anymore.

From the B&K manual:
Note 6: 200 kHz FM step tuning (USA)
if value = 0,
indicates uninitialized ?OPEN? frequency
else,
(((value - 1)* 0.20) + 87.5) = frequency in MHz
((frequency ? 87.5) / 0.20) + 1 = value
For example of FM Frequency of 2Eh:
(((2Eh - 1) * 0.20) + 87.5 = 96.5 MHz
((96.5 MHz ? 87.5) / 0.20) + 1 = 29h
NOTE: If the recalled preset contains an OPEN frequency

Example of strings and freaks:
98.7 MHz - (0,S,P1=FF,6=39;)
98.9 MHz - (0,S,P1=FF,6=3A;)
99.1 MHz - (0,S,P1=FF,6=3B;)
99.3 MHz - (0,S,P1=FF,6=3C;)
99.5 MHz - (0,S,P1=FF,6=3D;)
99.7 MHz - (0,S,P1=FF,6=3E;)
99.9 MHz - (0,S,P1=FF,6=3F;)

Comments

  • annuelloannuello Posts: 294
    I haven't tried your code since maths hurts my brain, and I'm not familiar with the device your trying to control. However, when working with floats I try to make sure all parts of the equation are expressed as a float. The +1 section may be type_casting the result to an integer. Have you tried +1.0 instead?
    nFreqTemp = (((nFreqTemp - 87.5)/0.2) + 1.0);
    
  • jweatherjweather Posts: 320
    First thing is to realize that you don't really want floating point numbers for this application. Instead, you should use fixed point, which is basically just a scaled integer -- use an integer 875 and pretend it's 87.5.

    Here's how I do this particular conversion: nFreqTemp = (((nFreqTemp - 87.5)/0.2) + 1)

    First, keep your temporary digit string in an integer. The user enters "8 7 5", your nFreqTemp should == 875. Now calculate
    STACK_VAR INTEGER bkFreq
    
    bkFreq = ((nFreqTemp-875) / 2) + 1
    

    Is this the same formula? Check it yourself, it works perfectly. Floating point numbers can be a bit squirrely and hard to pin down to precise values (ie, you're likely to get 87.49999999). Note that there's a typo in the example in the Series III manual version 12/14/04 on page 8, the second example shows ((96.5 MHz - 87.5) / 0.20) + 1 = 29h, which should be 2Eh.
  • viningvining Posts: 4,368
    annuello wrote:
    I haven't tried your code since maths hurts my brain,
    I hear ya. I never had any real math classes in school and most of those brain cells are gone now anyway.

    jweather wrote:
    First thing is to realize that you don't really want floating point numbers for this application.
    Thanks, that did the trick. Makes you wonder though why the master can't seem to handle this correctly when a $5 calculator can.
  • jweatherjweather Posts: 320
    vining wrote: »
    Makes you wonder though why the master can't seem to handle this correctly when a $5 calculator can.

    I would guess your code was calculating a value of, 58.999999999999, which you then truncated to an integer (58) and converted to hex (3A). Your $5 calculator was rounding to 59. This is why you don't want to use floating point for discrete quantities. If you absolutely had to, you could round the quantity instead of truncating by using ITOHEX(nFreqTemp+0.5).
  • ericmedleyericmedley Posts: 4,177
    The old-fashioned way (from back when we didn't even have floating point) was to multiply everything by 100 or 1000, and then do the math. Then divide the result back down by whatever you multiplied by in the first place.
  • Floating point numbers are always really annoying for user interaction. Computer simply truncate numbers when dealing with floats, so if the result of a calculation is really 59, but for some reason due to truncation ends up as 58.999999999, then that's what you end up with. A float has some fractional number of significant digits (7.22) since we're mapping base 10 to base 2. So if and when you deal with floats you need to truncate the significant digits yourself, you have to round it to the desired significant digit yourself. This becomes a big problem when comparing two floats (ie: is floatA == floatB) where you have to use something like (is floatA +.1 > floatB && floatA - ,1 < floatB) to compare 2 floats to 1 significant digit.

    Your calculator has all this already programmed in, that's why it can do it, but your amx processor can't.
    You're really almost always better off converting everything to integers like above.
Sign In or Register to comment.