Fuzzy Math?
vining
X Member
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?
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:
Example of strings and freaks:
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
-
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);
-
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 calculateSTACK_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. -
annuello wrote:
I hear ya. I never had any real math classes in school and most of those brain cells are gone now anyway.I haven't tried your code since maths hurts my brain,
jweather wrote:
Thanks, that did the trick. Makes you wonder though why the master can't seem to handle this correctly when a $5 calculator can.First thing is to realize that you don't really want floating point numbers for this application. -
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). -
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. -
Categories
- All Categories
- 2.5K AMX General Discussion
- 922 AMX Technical Discussion
- 514 AMX Hardware
- 502 AMX Control Products
- 3 AMX Video Distribution Products
- 9 AMX Networked AV (SVSI) Products
- AMX Workspace & Collaboration Products
- 3.4K AMX Software
- 151 AMX Resource Management Suite Software
- 386 AMX Design Tools
- 2.4K NetLinx Studio
- 135 Duet/Cafe Duet
- 248 NetLinx Modules & Duet Modules
- 57 AMX RPM Forum
- 228 MODPEDIA - The Public Repository of Modules for Everyone
- 943 AMX Specialty Forums
- 2.6K AMXForums Archive
- 2.6K AMXForums Archive Threads
- 1.5K AMX Hardware
- 432 AMX Applications and Solutions
- 249 Residential Forum
- 182 Tips and Tricks
- 146 AMX Website/Forums