FunkyAP
Posts: 3
Joined: Fri Apr 08, 2016 10:29 am

Measuring duty cycle

Sun Apr 24, 2016 7:03 pm

Hi,

I have a project going on that requires me to measure duty cycle of a 100 Hz square wave signal. The duty cycle changes but the frequency stays constant. The amplitude of the signal is 15 volts and I have used a resistor and zener to get it down to 3 volts so I can use one of the GPIO pins to measure the duty cycle.

For some reason once in a while when the duty cycle changes there is a huge error in the measurement. For example when it changes from 50 % to 55 % raspberry might show that it is 3 % or 87 % or something else. I'm guessing that the problem comes from the fact when the duty cycle changes it sometimes screws up the timing calculations for the next pulse. Since I'm fairly new to raspberry and python I don't know how to solve this.

I tried to do the same with arduino and it works perfectly when I'm using the pulseIn function and the exact same circuit. The signal is generated from my function generator and I have check it with my scope that it is correct. But if I connect arduino to pi and send the data over tx and rx or over usb there is some weird error on the measurement that I don't get with my pc.

Here is the code that I have used with my Pi and the resistor and zener circuit (basic overvoltage circuit).

Code: Select all

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

while True:
  try:
    GPIO.wait_for_edge(25, GPIO.RISING)
    startTime = time.time()
    GPIO.wait_for_edge(25, GPIO.FALLING)
    print "%.1f" % ((time.time() - startTime) * 10000)
  except KeyboardInterrupt:
    GPIO.cleanup()
GPIO.cleanup()
I also tried this code but I get the same problem

Code: Select all

import time
import RPi.GPIO as GPIO

dutyPin = 25
GPIO.setmode(GPIO.BCM)
GPIO.setup(dutyPin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

while True:
  try:
    while GPIO.input(dutyPin)
      pass
    start = time.time()
    while not GPIO.input(dutyPin)
      pass
    width = time.time() - start

    print "%.1f" % (width * 10000)
  except KeyboardInterrupt:
    GPIO.cleanup()
GPIO.cleanup()


boyoh
Posts: 1486
Joined: Fri Nov 23, 2012 3:30 pm
Location: Selby. North Yorkshire .UK

Re: Measuring duty cycle

Sun Apr 24, 2016 8:05 pm

The problem of eratic duty cycles might be due the the timing of the duty cycles
Starting and stopping, If the timing is random you will , you might get problem
Try starting and stopping the duty cycles at the rising and falling edge of the pulses
This will give you some synchronization between the pulse generator and the pulse
Modulater
BoyOh ( Selby, North Yorkshire.UK)
Some Times Right Some Times Wrong

User avatar
liudr
Posts: 687
Joined: Sat Jun 01, 2013 12:11 am
Location: Central MN, USA
Contact: Website

Re: Measuring duty cycle

Mon Apr 25, 2016 8:11 pm

1% of the 100Hz duty is 0.1 millisecond accuracy. Use an arduino for that and return average duty cycle via USB serial port. How often do you need to measure?
Arduino data loggers, user interface, printed circuit board designer since 2009, RPI 3B 2B 2B Zero Jessie, assembly/C/C++/java/python programmer since the 80's

FunkyAP
Posts: 3
Joined: Fri Apr 08, 2016 10:29 am

Re: Measuring duty cycle

Sat Apr 30, 2016 11:27 pm

boyoh wrote:The problem of eratic duty cycles might be due the the timing of the duty cycles
Starting and stopping, If the timing is random you will , you might get problem
Try starting and stopping the duty cycles at the rising and falling edge of the pulses
This will give you some synchronization between the pulse generator and the pulse
Modulater
I was trying to do something like that with my code. Just reading the positive pulse of the PWM signal and calculating the duty cycle since it is a fixed frequency, but for some reason since the duty cycle is changing it gives a few bad readings from time to time (1/10 - 1/20 is bad). This is a control circuit so it would be good the ged rid of the bad readings and since I don't need to read every pulse, every other is just fine I was wondering if there is an accurate delay function on python that I could use and skip one or two pulses and then read one again or is there a better way to skip every other pulse so I get more time to process the readings / timing wont be such an issue?
liudr wrote:1% of the 100Hz duty is 0.1 millisecond accuracy. Use an arduino for that and return average duty cycle via USB serial port. How often do you need to measure?
I tried to read it with arduino and it works perfectly if the arduino is connected to my PC and I send the data over serial, but when I connect it to raspberry I get a really odd error on the readings, 50% duty cycle will be 44% and it is linear error. The lower the duty cycle, bigger the error about 10 - 12 units and higher the duty cycle the lower the error is about 0 - 1 units.

Avarage readings work on raspberry alone but since this is a control circuit the reading can't be an avarage or the behaviour will change and it won't control the system correctly. I don't need to read every pulse, it can skip few pulses to get the timing correct for the one it actually read. So if it reads one pulse it can skip the next four pulses and then read one again.

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4257
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Measuring duty cycle

Sun May 01, 2016 12:14 am

Python is not fast enough to get the speed you require and it will show systematic and random errors due to the Python interpreter and other processes and interrupts that Linux is executing.

It is possible to do this on the Pi, but you need to get much closer to the hardware to do it. Joan has a library that does it and has pointed it out to you above.

User avatar
liudr
Posts: 687
Joined: Sat Jun 01, 2013 12:11 am
Location: Central MN, USA
Contact: Website

Re: Measuring duty cycle

Mon May 02, 2016 10:33 pm

What data do you send from arduino to PC, the duty cycle or raw data?
Arduino data loggers, user interface, printed circuit board designer since 2009, RPI 3B 2B 2B Zero Jessie, assembly/C/C++/java/python programmer since the 80's

andies
Posts: 144
Joined: Mon Nov 11, 2013 8:12 pm
Location: Berlin

Re: Measuring duty cycle

Thu Dec 29, 2016 6:52 pm

rurwin wrote:Python is not fast enough to get the speed you require and it will show systematic and random errors due to the Python interpreter and other processes and interrupts that Linux is executing.
I have a comparable problem as OP. I want to sent a AM-signal (via 433MHz) with a frequency around 10kHz using the "typical" 433-transmitter (GPIO connected to DATA pin gets me this AM 433-signal). I am struggling with python and just came through your post. Do I understand it correctly that using simple python is a very bad idea to achieve this?

I also tried an arduino but was also not lucky. But this might be due to the fact that I programmed it badly (arrays instead of straightforward writing down the short pulse train, complicated if-then-else etc). I am new to arduino - would you still recommend to dug deeper into it?
raspberry B, Noir camera, Mac Book Air, iPhone, Bezzera

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4257
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Measuring duty cycle

Fri Dec 30, 2016 5:54 pm

Using the Pi to generate a radio signal is a subject that will be closed down fast on this forum. It is illegal to do this unless one is an expert on radio engineering because the signal coming out of the Pi is not just 433MHz but has many strong harmonics. The primary user of the 433MHz band is the UK military.

I strongly suggest that you look for the many cheap radio transmitter and receiver modules that are available. They are ready to use and legal. They simply accept a digital pulse-train, transmit it to the receiver and output it there.

A 10kHz signal would be difficult to receive using Python, but you could use the UART to send and receive through a pair of radio modules, probably faster than that.

Return to “Automation, sensing and robotics”