This project is read-only.

PMUSimulator Frame Rate

Feb 15, 2012 at 3:37 PM

When I receive data from PMUSimulator, I tend to get frame rates between 58-59 frames per second when the nominal value is 60 frames per second. The frame varies from computer to computer. Faster computers come closer to 60 frames per second but they lag still yet. I've learned that you can hard code in a correction in the "usleep" function in udp_send_data. However, this assumes that all computers are the same which is not true. It also assumes that the processing time of the data frame is always constant also.

The following code will take a running average of the time it takes to send a data frame and adds corrections slowly to come closer to the actual frame rate. After about five seconds, the frame rate is fairly constantly at 60 frames per second on my computer. I've tried this for the tcp_send_data also but with less accurate results. I am not a coder, and most of the changes were done by a Comp Sci Eng.

This code could be improved by accounting for the time after "if(samples<UINT_MAX)" because the two getttimeofday functions do not cover the entire loop. Also, if the "correct" variable could be stored for a specific PMUSimulator, then the frame rate could start out at the last known correction value, which would decrease the time needed to converge to 60 frames per second.

This is important because when sending this data to a PDC, the PDC expects exactly 60fps, if one frame is missing, the PDC will wait anywhere from 50 to 200 milliseconds on that specific data frame and then discard that data frame when it doesn't show up.   

/* ----------------------------------------------------------------------------    */
/* FUNCTION  void* udp_send_data():                        */
/* Function to generate and send the data frame periodically to destination    */
/* address or to PDC or client.                            */
/* ----------------------------------------------------------------------------    */
      
       void* udp_send_data()
       {    struct timeval tim;
        double sumavg=0;
        double correct=100;/*This initialization assumes that it takes 100 microseconds to generate the data             frame*/
              double udp_data_rate = 1000000/df_data_rate, i=1;
        double Per = udp_data_rate/1000000; /*Per is the Period of the frame rate*/
              udp_data_flag = 1;
              udp_data_trans_off = 1;
              udp_send_thrd_id = pthread_self();
        unsigned int samples=1;
              while(1)
              {
            gettimeofday(&tim, NULL);/*t1 is the time at the beginning of the while loop*/
            double t1=tim.tv_sec+(tim.tv_usec/1000000.0);

                 /*printf("%d. ", i);*/
                 if ( i == df_data_rate) i=0;

            /* Call the function generate_data_frame() to generate the Data Frame */
                 generate_data_frame();

                 if (sendto(UDP_sockfd, data_frm, df_data_frm_size, 0, (struct sockaddr *)&UDP_addr,sizeof(UDP_addr)) == -1)
                 {
                    perror("sendto");
                 }
             i++;
                 usleep(udp_data_rate-correct);/*Instead of "sleeping" for udp_data_rate, correct is subtracted to offset the time taken to generate the data frame. Note: udp_data_rate and correct are in microseconds*/
           
/*There is still an assumption that the following code takes 0 seconds to complete, which needs to be corrected in the future*/    
            gettimeofday(&tim, NULL);
            double t2=tim.tv_sec+(tim.tv_usec/1000000.0);/*t2 is the time at the end of the while loop*/
            if(samples<UINT_MAX)           
            {
                sumavg=sumavg*samples/(samples+1)+(t2-t1)/(samples+1);
                samples++;/*This code gives a "running average" of the frame rate*/
            }
            else
            {
                sumavg=Per;
            }
            correct=correct+(sumavg-Per)*10000;/*This makes the adjustments to the corrections. Note: correct is in microseconds and sumavg and Per are in seconds. By multiplying by 1000, the adjustments are more subtle and come to a more accurate result. By increasing that number, the correction will be faster but result in a less stable final value*/
              }

       } /* end of function udp_send_data() */

Coordinator
Feb 17, 2012 at 4:52 AM

Thanks for suggesting the problem in code and thanks for given code, I will go through it.

Feb 17, 2012 at 12:30 PM

I'm in the process of testing the frame rate for a lot of different configurations. I'm noticing that for fast computers the frame rate in the original code may be better than the code I've added. I have some old computers that are really slow that the adjustment helps. Once I get all of the data collected, I'll post the results. Keep up the good work, this program is awesome.