PDA

View Full Version : Converting milliseconds to frequency



chips123
- 31st August 2007, 22:22
I have code written to measure the time period of a square waveform using pulsin . I measure the low time and the high time and add them together and send it to an LCD. It is quite accurate (comparing to scope) and the refresh time is fast as the frequency varies. Knowing that frequency is 1/time, how can one go about doing the math in PBP to calculate the frequency of this waveform? Thanks.

This is either very easy or a bigger problem than it seems.

Here is the main loop: I found that I needed to do the 4/5ths thing to get the time more accurate.


loop: pulsin PORTA.1,0,x
x = x / 100

pulsin PORTA.1,1,y
y = y / 100

z = x + y
z = z * 4
z = z / 5

LCDOUT $fe, $C0
LCDOUT " "
LCDOUT $fe, $C0
LCDOUT #z

Goto loop

Kamikaze47
- 3rd September 2007, 19:44
i may be able to help, but ive got a few questions:

is the variable z a byte or a word?
what is the unit of z? *edit* Cancel that question... Just read the thread topic :)
what resolution is required? i.e. whats the smallest change in frequency that you would need to detect?
what is the highest and lowest frequency you need to detect?

chips123
- 3rd September 2007, 21:45
Thanks for the reply.

I made all variables words to give myself plenty of room, at least for now.
Ultimately, I want to get to pulses per minute, ie. RPMs with a range from maybe 240 RPM (4 cycles per sec) to maybe 4000 or 5000 (66 Hz to 85 Hz), give or take. I am flexible to a point. As far as resolution goes, something like 100 RPM increments (~2 Hz ?). Make any sense?

weirdjim
- 3rd September 2007, 21:49
Frequency is the reciprocal of time. For example, if you measure your square wave as 16.66...milliseconds, you have a 60 Hz. frequency.

Now, dependent on whether your milliseconds are floating point (many decimal places), you can measure frequency with concomitant resolution. That is, if time is an integer and you only have choices of 16 or 17 milliseconds, the frequency comes out 62 Hz. or 58 Hz. respectively while the actual waveform is 60 Hz..

Jim

chips123
- 3rd September 2007, 22:14
With my millisecond values are integers, I don't expect 100% accuracy. Using PBP, how do I get from say, 16mS to 62Hz ?

Scott

Kamikaze47
- 3rd September 2007, 22:21
You can write a subroutine to determine the RPM from the z value. If to the nearest 100rpm is acceptable, this is the relevant data:


z rpm
-------------------------
<10 out of limits
10 6000
11 5500
12 5000
13 4600
14 4300
15 4000
16 3800
17 3500
18 3300
19 3200
20 3000
21 2900
22 2700
23 2600
24 2500
25 2400
26 2300
27 2200
28-29 2100
30 2000
31-32 1900
33-34 1800
35-36 1700
37-38 1600
39-41 1500
42-44 1400
45-48 1300
49-52 1200
53-57 1100
58-63 1000
64-70 900
71-80 800
81-92 700
93-109 600
110-133 500
134-171 400
172-240 300
241-400 200
401-1200 100
>12000 out of limits

If you need help on how to write a subroutine to do this then let me know and i can help you out.

chips123
- 3rd September 2007, 22:32
I am a bit of a rookie. Some direction would be much appreciated.

Kamikaze47
- 3rd September 2007, 22:33
I had a few spare mins so i wrote up a subroutine that would work. Im sure its not the most elegant piece of code, but it will do what you want just fine.

It will take the z value and store a relavant value into rpm. The value in rpm will be in hundreds of rpms. So if you write the value of the variable rpm to your lcd, followed by "00" it will display in rpms.

If rpm=0 after the subroutine has run then the input was out of range.


convert_to_rpm:
IF z<10 THEN rpm=0
IF z=10 THEN rpm=60
IF z=11 THEN rpm=55
IF z=12 THEN rpm=50
IF z=13 THEN rpm=46
IF z=14 THEN rpm=43
IF z=15 THEN rpm=40
IF z=16 THEN rpm=38
IF z=17 THEN rpm=35
IF z=18 THEN rpm=33
IF z=19 THEN rpm=32
IF z=20 THEN rpm=30
IF z=21 THEN rpm=29
IF z=22 THEN rpm=27
IF z=23 THEN rpm=26
IF z=24 THEN rpm=25
IF z=25 THEN rpm=24
IF z=26 THEN rpm=23
IF z=27 THEN rpm=22
IF z>27 AND z<30 THEN rpm=21
IF z=30 THEN rpm=20
IF z>30 AND z<33 THEN rpm=19
IF z>32 AND z<35 THEN rpm=18
IF z>34 AND z<37 THEN rpm=17
IF z>36 AND z<39 THEN rpm=16
IF z>38 AND z<42 THEN rpm=15
IF z>41 AND z<45 THEN rpm=14
IF z>44 AND z<49 THEN rpm=13
IF z>48 AND z<53 THEN rpm=12
IF z>52 AND z<58 THEN rpm=11
IF z>57 AND z<64 THEN rpm=10
IF z>63 AND z<71 THEN rpm=9
IF z>70 AND z<81 THEN rpm=8
IF z>80 AND z<93 THEN rpm=7
IF z>92 AND z<110 THEN rpm=6
IF z>109 AND z<134 THEN rpm=5
IF z>133 AND z<172 THEN rpm=4
IF z>171 AND z<241 THEN rpm=3
IF z>240 AND z<401 THEN rpm=2
IF z>400 AND z<1201 THEN rpm=1
IF z>1200 then rpm=0
return

chips123
- 3rd September 2007, 22:39
Thanks. A bunch of if-thens came to my mind as well. I just was not sure about it. I think I'll try it.

Kamikaze47
- 3rd September 2007, 22:44
Let us know how it goes

Andy Wood
- 4th September 2007, 04:09
With my millisecond values are integers, I don't expect 100% accuracy. Using PBP, how do I get from say, 16mS to 62Hz ?

Scott

Time and Frequency are reciprocal, so you can use a constant (in this case 1000) and divide you mS value into it. For example:

1000 / 16mS = 62Hz.

Or if you had 40mS -

1000 / 40mS = 25Hz etc.

You are probably kicking yourself right about now :)

Regards,

Andy

Kamikaze47
- 4th September 2007, 07:38
That would work, but that kind of division in PBP would take up a lot more processing time than the IF...THEN statements above.

RussMartin
- 5th September 2007, 01:21
I may not be understanding something here.

For the basic math, I would have said:

rpm=60000/z

where z is in milliseconds.


That would work, but that kind of division in PBP would take up a lot more processing time than the IF...THEN statements above.

My question is: Why would doing that single division take longer than going through multiple IF...THEN statements (40-something of them in the example) until one is found where the condition is satisfied?

Thanks to whomever clarifies this for me!

chips123
- 5th September 2007, 02:22
Thanks Andy.....kick, kick, kick...
And Russ...equally good insight. I'll kick myself once for you too.
Almost too obvious, I have been away from math for too long.

Kamikaze...I tried your solution and ran into an exceeded address 3fff, if I remember correctly. I got sidetracked and have not investigated that further yet.

Appreciate the input.
Scott

GrandPa
- 5th September 2007, 03:44
All this thread bring back a question that I had in mind for a while. I was wondering at which point is that better (faster) to use lookup instead of calculated values?

I know that I can find thread like "Sine wave power inverter" where a lookup table was used to increase calculation's speed. But is this only a trial an error process or can someone bring up guidelines that will lead to use one solution or the other?

J-P

Archangel
- 5th September 2007, 05:48
One more thought . . . instead of 40 IF THEN loops would't SELECT CASE be more appropriate? I throw this out there, having NEVER used select case, because you see, I want to learn too . . .

RussMartin
- 5th September 2007, 19:37
That would work, but that kind of division in PBP would take up a lot more processing time than the IF...THEN statements above.


My question is: Why would doing that single division take longer than going through multiple IF...THEN statements (40-something of them in the example) until one is found where the condition is satisfied?

Thanks to whomever clarifies this for me!

I'm sure that SELECT CASE could be used, or LOOKDOWN (or should it be LOOKUP?), depending on the strategy, and maybe more effectively than IF...THENs. In all of those cases, though, it still looks like a bulky approach. I'm still not convinced that the single 16-bit division isn't going to be not only simpler but faster.

Any thoughts? Is this one of those balancing acts between compact code and speed of operation?

Scott, how often do you need to update the display with new information?

mackrackit
- 5th September 2007, 20:16
Here is all the IF/THENS in ASM


LABEL?L _convert_to_rpm

CMPGE?BCL _z, 00Ah, L00001
MOVE?CB 000h, _rpm
LABEL?L L00001

CMPNE?BCL _z, 00Ah, L00003
MOVE?CB 03Ch, _rpm
LABEL?L L00003

CMPNE?BCL _z, 00Bh, L00005
MOVE?CB 037h, _rpm
LABEL?L L00005

CMPNE?BCL _z, 00Ch, L00007
MOVE?CB 032h, _rpm
LABEL?L L00007

CMPNE?BCL _z, 00Dh, L00009
MOVE?CB 02Eh, _rpm
LABEL?L L00009

CMPNE?BCL _z, 00Eh, L00011
MOVE?CB 02Bh, _rpm
LABEL?L L00011

CMPNE?BCL _z, 00Fh, L00013
MOVE?CB 028h, _rpm
LABEL?L L00013

CMPNE?BCL _z, 010h, L00015
MOVE?CB 026h, _rpm
LABEL?L L00015

CMPNE?BCL _z, 011h, L00017
MOVE?CB 023h, _rpm
LABEL?L L00017

CMPNE?BCL _z, 012h, L00019
MOVE?CB 021h, _rpm
LABEL?L L00019

CMPNE?BCL _z, 013h, L00021
MOVE?CB 020h, _rpm
LABEL?L L00021

CMPNE?BCL _z, 014h, L00023
MOVE?CB 01Eh, _rpm
LABEL?L L00023

CMPNE?BCL _z, 015h, L00025
MOVE?CB 01Dh, _rpm
LABEL?L L00025

CMPNE?BCL _z, 016h, L00027
MOVE?CB 01Bh, _rpm
LABEL?L L00027

CMPNE?BCL _z, 017h, L00029
MOVE?CB 01Ah, _rpm
LABEL?L L00029

CMPNE?BCL _z, 018h, L00031
MOVE?CB 019h, _rpm
LABEL?L L00031

CMPNE?BCL _z, 019h, L00033
MOVE?CB 018h, _rpm
LABEL?L L00033

CMPNE?BCL _z, 01Ah, L00035
MOVE?CB 017h, _rpm
LABEL?L L00035

CMPNE?BCL _z, 01Bh, L00037
MOVE?CB 016h, _rpm
LABEL?L L00037

CMPGT?BCB _z, 01Bh, T1
CMPLT?BCB _z, 01Eh, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00039
MOVE?CB 015h, _rpm
LABEL?L L00039

CMPNE?BCL _z, 01Eh, L00041
MOVE?CB 014h, _rpm
LABEL?L L00041

CMPGT?BCB _z, 01Eh, T1
CMPLT?BCB _z, 021h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00043
MOVE?CB 013h, _rpm
LABEL?L L00043

CMPGT?BCB _z, 020h, T1
CMPLT?BCB _z, 023h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00045
MOVE?CB 012h, _rpm
LABEL?L L00045

CMPGT?BCB _z, 022h, T1
CMPLT?BCB _z, 025h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00047
MOVE?CB 011h, _rpm
LABEL?L L00047

CMPGT?BCB _z, 024h, T1
CMPLT?BCB _z, 027h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00049
MOVE?CB 010h, _rpm
LABEL?L L00049

CMPGT?BCB _z, 026h, T1
CMPLT?BCB _z, 02Ah, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00051
MOVE?CB 00Fh, _rpm
LABEL?L L00051

CMPGT?BCB _z, 029h, T1
CMPLT?BCB _z, 02Dh, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00053
MOVE?CB 00Eh, _rpm
LABEL?L L00053

CMPGT?BCB _z, 02Ch, T1
CMPLT?BCB _z, 031h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00055
MOVE?CB 00Dh, _rpm
LABEL?L L00055

CMPGT?BCB _z, 030h, T1
CMPLT?BCB _z, 035h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00057
MOVE?CB 00Ch, _rpm
LABEL?L L00057

CMPGT?BCB _z, 034h, T1
CMPLT?BCB _z, 03Ah, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00059
MOVE?CB 00Bh, _rpm
LABEL?L L00059

CMPGT?BCB _z, 039h, T1
CMPLT?BCB _z, 040h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00061
MOVE?CB 00Ah, _rpm
LABEL?L L00061

CMPGT?BCB _z, 03Fh, T1
CMPLT?BCB _z, 047h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00063
MOVE?CB 009h, _rpm
LABEL?L L00063

CMPGT?BCB _z, 046h, T1
CMPLT?BCB _z, 051h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00065
MOVE?CB 008h, _rpm
LABEL?L L00065

CMPGT?BCB _z, 050h, T1
CMPLT?BCB _z, 05Dh, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00067
MOVE?CB 007h, _rpm
LABEL?L L00067

CMPGT?BCB _z, 05Ch, T1
CMPLT?BCB _z, 06Eh, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00069
MOVE?CB 006h, _rpm
LABEL?L L00069

CMPGT?BCB _z, 06Dh, T1
CMPLT?BCB _z, 086h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00071
MOVE?CB 005h, _rpm
LABEL?L L00071

CMPGT?BCB _z, 085h, T1
CMPLT?BCB _z, 0ACh, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00073
MOVE?CB 004h, _rpm
LABEL?L L00073

CMPGT?BCB _z, 0ABh, T1
CMPLT?BCB _z, 0F1h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00075
MOVE?CB 003h, _rpm
LABEL?L L00075

CMPGT?BCB _z, 0F0h, T1
CMPLT?BCB _z, 00191h, T2
LAND?BBW T1, T2, T2
CMPF?WL T2, L00077
MOVE?CB 002h, _rpm
LABEL?L L00077

CMPGT?BCB _z, 00190h, T1
CMPLT?BCB _z, 004B1h, T2
LAND?BBW T1, T2, T2

CMPF?WL T2, L00079
MOVE?CB 001h, _rpm
LABEL?L L00079

CMPLE?BCL _z, 004B0h, L00081
MOVE?CB 000h, _rpm
LABEL?L L00081

GOTO?L _convert_to_rpm


And here is the WORD division in ASM.


LABEL?L _TEST

MOVE?CW 003E8h, _FREQ

MOVE?CW 010h, _SPEED

DIV?WWW _FREQ, _SPEED, _ROTATIONS

GOTO?L _TEST


Do not know about CASE either.

RussMartin
- 5th September 2007, 22:22
Thanks, Dave! That was a lot of extra effort to answer the question, but I appreciate it. I'm sure others will, too!

Scott--what do you think?

mackrackit
- 5th September 2007, 22:43
No problem, PBP did all of the work.:D

chips123
- 6th September 2007, 01:37
Russ...The 60000 math thing worked great. The digits changing on the LCD actually looks quite natural and "smooth". It doesn't look jerky. It is faster that you can read.

I applied all of this to another project where I am driving a stepper motor as a position indicator, ie. a needle on a scale. I am quite satisfied with it.

The only issue I see with my current calculations is that a change in a millisecond at the high end of the scale represents a larger change in RPM than a millisecond does at the lower speeds. This makes the needle seem a bit twitchy at the higher speeds. I plan to see what I can do to improve that somewhat.

I initially attempted this project using COUNT . It worked, but moving the needle was painfully slow.

Thanks for all the input
Scott

RussMartin
- 6th September 2007, 04:52
Scott--Can you give us a better idea of the position indicator circuit and approach? Maybe we can come up with a way to damp the flutter.

Jumper
- 6th September 2007, 11:04
Hi,

What frequency do you run the PIC on? The faster you run it the more resolution you will get. My experience with Pulsin has been between great and failure and in the end I usually end up having to write my own code using a Timer. Timers are not that difficult to use and if you have a built in HPWM with capture and compare function it is not that bad at all :-)

If you don't have that Darryl's instant interupts can be used for this as well. Especially together with external interupt sources. or a simple if-then loop or wend or whatever loop is also ok.....

With a high ocs frequency and a timer you can get even parts of ms. 40 MHz would give you 0.1 ms in resolution. It would of course overflow the timer on low rpm's but then we just check for that and if it happens change the prescaler and try again... or we first do a Pulsin (same as now) to get the basic settings and then we do a new measurement right after using the best possible prescaler and a 16-bit timer to get a great value.


You said you wanted the FQ right? Do the measurement with a timer over a longer time (i.e 16 periods (the ccp can be set up to capture several periods by itself)). Then you will get an even better resolution, the more periods you measure over the better it will be. I guess the stuff you are measuring dont change rpms that crazy fast either. What is spinning?

/me