Sunday, July 26, 2015

Compensating the difference between FreqCounter and pulseIn measurements

by / Friday, 11 March 2011 / Published in Arduino

When you want to measure frequency in your Arduino project most likely you'll choose FreqCounter Library. However, despite FreqCounter is very precise, it may be unsuitable in some cases - because it affects PWM outputs of Atmega microcontroller, rendering analogWrite() functions inoperable.

In this article I'm going to show how to cope with it. However, an approach described here is not just a copy-and-paste solution, it will require adaptation to your project and you will have to do some things on your own. So this way, unfortunately, is not for beginners.

So, in case you need both frequency measurement and 3+ PWM outputs in your Arduino project, you may want to use another way – pulseIn() function:

pulseIn(pin, value)
pulseIn(pin, value, timeout)

Use LOW as a value – it provides more stable results (that still depends on your case).

PulseIn function returns the length of the pulse (in microseconds) or 0 if no pulse started before the timeout. To get the frequency you can use f = 1 / t equation, however, that depends on duty cycle of the signal.

To get frequency in Hz for a 50% square wave you can use 

freq2 = 500000/pulseIn(5, LOW, 5000);

Notice the value of 500,000 - that means 1,000,000 microseconds divided by 2*pulseIn (for a duty cycle of 50%). The actual period of the signal (red lines) in this case is equal to two pulse lengths:

squarewave

However, that way of measurement frequency with Arduino often gives lesser values than the precise ones.

In case you want to use pulseIn for measurements, you can create a calibration function that will approximate results for more accurate ones (like ones that FreqCounter library provides).

 

A general approach to this looks like:

  1. Create an additional sketch that measures the frequency on a PWM-capable pin (pin 5, for instance) with both ways - FreqCounter and pulseIn() - and sends measurements data to the PC? separated by \t (tab delimiter) for convinence.
    void measureFrequency(){
        FreqCounter::f_comp= 8;              // Set compensation to 12
        FreqCounter::start(1000);            // Start counting with gatetime of 1000ms
        while (FreqCounter::f_ready == 0)    // wait until counter ready 
        long freq=FreqCounter::f_freq;       // read result  
        long freq2=0;
        for(unsigned int j=0;j<1024;j++) 	 // get 1024 samples
    		freq2 += 500000/pulseIn(5, LOW, 5000);
        freq2 = freq2/1024;			 // get average values
        Serial.print(freq);Serial.print("\t");Serial.println(freq2);
    }
  2. Change the frequency source in the widest possible range. Better to do it several times while running the sketch to get more samples and more accuracy.
  3. Open any spreadsheet processor. Microsoft Excel is a good choice.
  4. Copy and paste the data from Console window to Excel
  5. Calculate the difference between FreqCounter and pulseIn values in another column - "difference".
  6. Copy only pulseIn and difference columns to text file, like input.txt.
  7. Calculate the average value of compensation (difference) for each collected sample. (You can use my Ruby program listed below for this)
  8. Paste output.txt to another sheet. Create a chart.hh100d chart
  9. Create approximation mathematical functions. I chose a simple set of linear ( y=ax+b ) functions. (Notice the red lines on a chart above)
  10. Encode those compensation functions to your sketch, like:

 hh100d compensation example

That way you will get more accurate readings while using pulseIn function than the raw ones. However, those results are not very precise, so it's better to use them when you all other frequency measurement methods are unavailable, and you do not need precise readings.

 

Notice that we may have several samples of pulseIn measurements with corresponding compensation values. We need to get only one, average value of compensation for each pulseIn-measured value. You can calculate this on your own, or use this tiny Ruby program that will do that for you:

f = File.open("input.txt")
additions     = Hash.new(0)
count         = Hash.new(0)
f.each do |line|
  tmp = line.split("\t")
  freq = tmp[0].to_i
  correction = tmp[1].to_i
  if (additions.has_key? freq) 
    count[freq] += 1
    additions[freq] += correction
  else
    count[freq]  = 1
    additions[freq]  = correction 
  end
end
f.close
fw = File.new("output.txt", "w");
additions.each do |k,v|
   fw.puts(k.to_s + "\t" + (v/count[k]).to_s )
end
fw.close
Read 327 times Last modified on Saturday, 21 March 2015 10:58

Do you like this? Please share!

Simon Tushev

Simon is IT professional with interests in web design, electronics, photography and astronomy. He writes about PHP, Yii, Joomla!, Arduino and several other topics.

Welcome!

Here I publish articles related to my areas of interest, my brief notes that may save some time to others, as well as some of my works.

This site is a work in progress. I will add more sections in the future, such as

  • More photos to photogallery
  • More Joomla!-related articles
  • ...

 

themeforest

New Posts

Modified script to reduce Wi-Fi transmitter power on schedule/at night (Mikrotik/RouterOS)

Modified script to reduce Wi-Fi transmitter power on schedule/at night (Mikrotik/RouterOS)

There are multiple reasons to switch off your WiFi router at night - from...

11-04-2015 in Linux, BSD, Unix

READ MORE

Correcting T3 framework MegaMenu issues

Correcting T3 framework MegaMenu issues

T3 Framework is one of Joomla! template frameworks. It features responsive design, powerful customization...

25-03-2015 in Joomla! articles & tutorials

READ MORE

How to add custom javascript to Joomla! backend

How to add custom javascript to Joomla! backend

Sometimes you need to add custom javascript to Joomla! backend.  Modifying templates that are shipped...

19-03-2015 in Joomla! articles & tutorials

READ MORE
Scroll to top

We use cookies, just to track visits to our website, we store no personal details Privacy policy