Bit rotation

Status
Not open for further replies.
Hi Eric,

I have asked Vladimir for a pointer as to whats going on with that first byte in the IEEE 754 conversion. He replied that he couldn't see a problem. I have explained exactly what I feel the problem is and sent him some code. I await a further reply. I have been messing around trying some way of just using LONG variables and maybe loosing a little resolution but this led to nothing

Here is the code as it stands at the moment. There's a lot of tidying up to do. I can see lots of places where I could get rid of a few variables but for now it's working (almost).

The current problem is a real show stopper for me. I'm not sure how I can get round it. Everything is working as it should if I could just get that SINGLE to be the same value as a LONG.

Cheers - Paul
 

Attachments

  • Digital VFO (877A) 10_02_14.bas
    17.4 KB · Views: 548
The important thing is to decide what precision you want. 30 million multiplied by 35 is slightly over 1 billion. This requires 31-bit to represent. If you want the result to come out as 32-bit integer, the best precision you can get is 0.5 if you set up so that one digit represents 0.5 of your final units. This will give you lots of digits for big numbers, but will not be very precise for small ones. Frequency of 1 will be represnted as 34, frequency of 2 - as 68.5.

Is this an acceptable precision for you? Then you can go integer road.

How are you going to use these numbers, what are you doing with them?
 
Hi NorthGuy,

It's a bit long winded t explain but if you look at the last code I posted above it's well commented and i'm sure you'll get the idea.
The project is a Digital VFO using the AD9850 module.

The SINGLE is because of a calculation to provide the frequency. The formula is on the AD9850 data sheet.

Cheers - Paul
 
These are big numbers. You need 31-bit to represent them precisely. The float numbers only keep 24 bits, so you cannot use float if you need full precision.

You need 32-bit arithmetic to deal with this. You need to be able to multiply two 32-bit numbers and get 64-bit result.

I would suggest this: x*34.35973837 = x*34 +x*0.35973837

As a first approximation you can use x*34. If the precision is not enough, then you calculate x*34 first, then you calculate x*0.35973837 and add it to x*34.

How to calculate correction:

x*0.35973837 = x*1545064534/4294967296

x is 32-bit and 1545064534 is 32-bit. You multiply them and you get 64-bit integer. Division by 4294967296 is easy - you simply take the most significant 32 bits and discard the least significant 32 bits. Then you add your result to x*34 that you calculated earlier.

If you do not have 32-bit by 32-bit multiplication, you can create it with 4 16-bit by 16-bit multiplications, or even 16 8-bit by 8-bit multiplications.
 
I don't know if this is a problem, but you can get at most 7 digit precision from a single variable, so 34.3597383 is not accurate to the last digits.
If you need the four bytes from fout, could you convert fout to long and take each byte from it as Eric supposed.
If you look the watch variables, same number as single in hex is different from long as hex

Dim F as long
Dim fout as single
----
fout = 7000000*34.3597383
F=fout
 
I replaced 34.359738 with 34.35974

I checked this and it gives the right hex values in watch window:
Code:
Dim a As Single
Dim fout As Long
Dim w1 As Byte
Dim w2 As Byte
Dim w3 As Byte
Dim w4 As Byte
Dim i As Long
For i = 0 To 3000 Step 1000
a = 34.35974 * (7000000 + i) ' Oshonsoft makes here a small error, less than 0.5Hz at 7MHz
fout = a
w1 = fout.LB
w2 = fout.HB
w3 = fout.3B
w4 = fout.4B
Break
Next i
End
 
hi jjw,
I am also finding limitations with the FP Single.

The manual states that if you prefix a Single with the hash sign '#' it will be available for Uart or LCD as a decimal value ASCII character string.

I have added Hseropen etc, and then displayed the #fout string, above a certain value the upper characters become corrupted.

I will try to determine what the limits of the Single are, will post later.

Eric
 
hi,
This is a sample of the results so far.

Using Hser suggests that #fout SINGLE value has a maximum of 9, 999,999
I will run comparative tests on the Watch window values.

Code:
nxt1:
fout = 100000
Hserout #fout, CrLf

fout = 1000000
Hserout #fout, CrLf

fout = 9999999
Hserout #fout, CrLf

fout = 10000000
Hserout #fout, CrLf

Goto nxt1
 

Attachments

  • AAesp02.gif
    16.2 KB · Views: 383
Hi JJW,
That might just be the answer I'm after. I have just run it in simulation on my laptop here at work (can't do much here) and it looks about right.
I'll try it on the actual setup and frequency counter when I get home later today. That is if the labs still standing. High winds here expected here in the UK today. :-(

Dim fout1 As Single
Dim fout As Long
ad9850_freq = ad9850_mhz + ad9850_khz + hz
fout1 = ad9850_freq * 34.35974 'reduce the accuracy?
fout = fout1
 
You can probably use the original multiplier 34.359738.
Oshonsoft Basic accepts it and with a quick test the accuracy seems to be little better , between -0.15Hz and -0.4Hz
 
I have no idea why this didn't work for me first time around. I tried this and it threw an error so I assumed I couldn't assign the single variable to a long. Thinking back it may have been because I had the resolution too large. What an idiot! - Anyway this looks to be the solution to my problem but there is still something a little weird with he way OSHON handles large floating point numbers. It's beyond my expertise to understand why, i'll leave that to the GURU's

Many thanks. Can't wait to get home now and try it for real

Cheers - Paul
 
hi Paul,
For a LONG which should be long enough [ pun] have you considered raising the 34.3597383 to say 343,597,383 [ == *10,000,000] and just multiplying by ad9850_mhz etc.....

A LONG is 4-byte integers in the range 0 to 4,294,967,295)

Code:
ad9850_mhz = mhz * 1000000
ad9850_khz = khz * 1000

ad9850_freq = ad9850_mhz + ad9850_khz + hz
fout = ad9850_freq * 34.3597383
 
There's some loss of precision when you go through the single. I don't know if it is important to you or not.

C:
#include <stdio.h>
 
float x;
 
void main() {
  int a = 1750000070; // 70 MHz * 35
  int b;
 
  x = a;
  b = x;
 
  printf("in: %d out: %d\r\n", a, b);
}

This produces:

Code:
in: 1750000070 out: 1750000128
 
BIG BIG BIG SMILEY FACE

Woo Hooo. I tried this method in the first place but couldn't get it to compile as looking back at what I've learned the multiplier 34.blah blah was too long and so I just made f0ut a SINGLE. This caused me no end of problems. Switching it back to LONG today and I'm a VERY happy bunny. I do still have a few issues around the lower band limit (not staying at 7.0) and also at power on sometimes the AD9850 doesn't get the frequency properly (I think this is mainly my poor electronics and I need pull ups etc etc). The resolution is fine for what I want and I can tune in 1hz steps

I will start the vero-board prototype tomorrow.

Many, many thanks to all that have helped me thus far. I have learned a lot, lost even more hair, and a lot of sleep. Don't you just love it.

Eric,

I have been documenting things as I've gone along to maybe put in an article (the how's and why's) - I'll probably need your help/approval when I get that far. There's a lot of code tidying and optimisation to do first.

Thanks everyone


Cheers - Paul
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…