element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Low Power IoT Design Challenge
  • Challenges & Projects
  • Design Challenges
  • Low Power IoT Design Challenge
  • More
  • Cancel
Low Power IoT Design Challenge
Blog Non-Intrusive Load Monitoring #3 - Interfacing Sensors & Calculating Power
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: taifur
  • Date Created: 1 Oct 2021 3:46 PM Date Created
  • Views 1094 views
  • Likes 1 like
  • Comments 1 comment
  • low power iot design challenge
  • psoc 6
  • voltage monitoring
  • machine learning
  • iot
  • continuous current monitoring
  • ad conversion
Related
Recommended

Non-Intrusive Load Monitoring #3 - Interfacing Sensors & Calculating Power

taifur
taifur
1 Oct 2021

Introduction

For detecting & identifying an electrical load using machine learning we will use power pattern as our dataset. Electrical instantaneous power can be calculated from instantaneous voltage and instantaneous current. From both resistive and inductive load voltages, current, and power fluctuates 50/60 times a second as shown in figure 1 and figure 2 below, for us humans we can't keep up with change at this speed and so we have a more useful value for power: the average of the instantaneous power which we call real power! (or active power).

image

image

 

Real power is often defined as the power used by a device to produce useful work. Looking at the graph above the positive bits are power going to the load from the supply and the negative bits are power going back from the load to the supply, the power that was actually used by the load is the power going to minus the power going back is the real power.

Reactive power (or imaginary power) is a measure of the power going back and forth between the load and the supply that does no useful work.

Another useful measure of power is Apparent Power which is the product of the Root-Mean-Squared (RMS) average of the Voltage and the RMS average of the Current. For purely resistive loads real power is equal to apparent power. But for all other loads, real power is less than apparent power. Apparent power is a measure of the real and reactive power but it is not an algebraic sum of the two, as the sum of the two does not take into account phase differences.

Relationship between real, reactive, and apparent power for IDEAL sinusoidal loads:

  • Real Power = Apparent Power x cosΦ
  • Reactive Power = Apparent Power x sinΦ

 

The cosΦ is also known as the power factor. In AC circuits, the power factor is the ratio of the real power that is used to do work and the apparent power that is supplied to the circuit. The power factor can get values in the range from 0 to 1. When all the power is reactive power with no real power (usually inductive load) - the power factor is 0. We can calculate power factor from the following equation:

 

  • Power Factor = Real Power / Apparent Power

 

 

Calculation of Power

AC Voltage and current continually alternate, as the name suggests, if we draw a picture of the voltage and current waveform over time, it will look something like the image below (depending on what's using power - the current waveform - blue in the diagram below - is what you get if you look at a typical laptop power supply. There's an incandescent light bulb in there as well).

image

The image was made by sampling the mains voltage and current at high frequency, which is exactly what we do on our project for calculating power. We will sample instantaneous voltage and current (50 sample per 20ms). Though a higher sampling rate increases the accuracy - we're limited by the speed of the analog conversion).

Calculating real power

Real power is the average of instantaneous power. The calculation is relatively straightforward on the microcontroller program as shown in the following code snippet. First, we calculate the instantaneous power by multiplying the instantaneous voltage measurement with the instantaneous current measurement. We sum this instantaneous power measurement over a given number of samples and divide by that number of samples:

 

for (n=0; n<number_of_sample; n++){
  // inst_voltage and inst_current calculation from raw ADC goes here
  inst_power = inst_voltage * inst_current;
  sum_inst_power += inst_power;
}
real_power = sum_inst_power / number_of_samples;

 

Root-Mean-Square (RMS) Voltage

The root-mean-square is calculated in the way the name suggests first we square the quantity, then we calculate the mean, and finally the square-root of the mean-square, this is how it's done on the program:

for (n=0; n<number_of_sample; n++){
   // inst_voltage calculation from raw ADC input goes here.
    squared_voltage = inst_voltage * inst_voltage;
    sum_squared_voltage += squared_voltage; 
 }
 mean_square_voltage = sum_squared_voltage / number_of_samples;
 root_mean_square_voltage = sqrt(mean_square_voltage);

Root-Mean-Square (RMS) Current Same as the RMS voltage calculation:

 

for (n=0; n<number_of_sample; n++) {
    // inst_current calculation from raw ADC input goes here.
    squared_current = inst_current * inst_current;
    sum_squared_current += squared_current;
 }
mean_square_current = sum_squared_current / number_of_samples;
root_mean_square_current = sqrt(mean_square_current);

Apparent power

 

 apparent_power = root_mean_square_voltage * root_mean_square_current; 

As RMS voltage is generally a fixed value such as: 220V (+10% -6% in the BD) its possible to approximate apparent power without having to make a voltage measurement by setting the RMS voltage to 230V. This is a common practice used by domestic energy monitors.

 

Voltage & Current Sensor

We will use the ZMPT101B voltage sensor module for measuring the AC voltage and the ZMCT103C current sensor module for measuring the load current. Both sensors provide analog data. For interfacing the sensors with PSoC 6 MCU board we will use the analog channel for data collection. We should and will use the same type of sensors for real-time detection for accurate results.

image

Figure: Voltage Sensor

image

Figure: Current Sensor

 

Sample Program for Sensor reading and Power Calculation

As we already know both current and voltage sensors we are using in our project provide analog data. We need to write program for PSoC 6 microcontroller to read the analog data and calculate the power. We will use P10_0 and P10_1 (Arduino A0, A1) pins respectively for reading voltage and current. This is a sample program for testing the sensors:

 

#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include "cy_retarget_io.h"


/* ADC input pin */
#define VOLTAGE_CHANNEL             (P10_0)
#define CURRENT_CHANNEL             (P10_1)


/* Number of scans every time ADC read is initiated */
#define NUM_SCAN                    (1)


/* ADC Channel constants*/
enum ADC_CHANNELS
{
  CHANNEL_0 = 0,
  CHANNEL_1,
  NUM_CHANNELS
} adc_channel;


/* Multi-channel initialization function */
void adc_multi_channel_init(void);


/* Function to read input voltage from multiple channels */
void adc_multi_channel_process(void);


/* ADC Event Handler */
static void adc_event_handler(void* arg, cyhal_adc_event_t event);


/*******************************************************************************
* Global Variables
*******************************************************************************/
/* ADC Object */
cyhal_adc_t adc_obj;


/* ADC Channel 0 Object */
cyhal_adc_channel_t adc_chan_0_obj;
/* ADC Channel 1 Object */
cyhal_adc_channel_t adc_chan_1_obj;


/* Default ADC configuration */
const cyhal_adc_config_t adc_config = {
        .continuous_scanning=false, // Continuous Scanning is disabled
        .average_count=1,           // Average count disabled
        .vref=CYHAL_ADC_REF_VDDA,   // VREF for Single ended channel set to VDDA
        .vneg=CYHAL_ADC_VNEG_VSSA,  // VNEG for Single ended channel set to VSSA
        .resolution = 12u,          // 12-bit resolution
        .ext_vref = NC,             // No connection
        .bypass_pin = NC };         // No connection


/* Asynchronous read complete flag, used in Event Handler */
static bool async_read_complete = false;


/* Variable to store results from multiple channels during asynchronous read*/
int32_t result_arr[NUM_CHANNELS * NUM_SCAN] = {0};


int main(void)
{
    /* Variable to capture return value of functions */
    cy_rslt_t result;


    /* Initialize the device and board peripherals */
    result = cybsp_init();
    
    /* Board init failed. Stop program execution */
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }


    /* Enable global interrupts */
    __enable_irq();


    /* Initialize retarget-io to use the debug UART port */
    result = cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX,
                                 CY_RETARGET_IO_BAUDRATE);


    /* retarget-io init failed. Stop program execution */
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }


    /* Print message */
    /* \x1b[2J\x1b[;H - ANSI ESC sequence for clear screen */
    printf("\x1b[2J\x1b[;H");
    printf("-----------------------------------------------------------\r\n");
    printf("PSoC 6 MCU: ADC using HAL\r\n");
    printf("-----------------------------------------------------------\r\n\n");




    /* Initialize Channel 0 and Channel 1 */
    adc_multi_channel_init();


    /* Update ADC configuration */
    result = cyhal_adc_configure(&adc_obj, &adc_config);
    if(result != CY_RSLT_SUCCESS)
    {
        printf("ADC configuration update failed. Error: %ld\n", (long unsigned int)result);
        CY_ASSERT(0);
    }


    for (;;)
    {




        /* Sample input voltage at channel 0 and channel 1*/
        adc_multi_channel_process();


        /* 200ms delay between scans */
        cyhal_system_delay_ms(200);
    }
}




/*******************************************************************************
 * Function Name: adc_multi_channel_init
 *******************************************************************************
 *
 * Summary:
 *  ADC Multichannel initilization. This function initializes and configures
 *  channel 0 and channel 1 of ADC.
 *
 * Parameters:
 *  void
 *
 * Return:
 *  void
 *
 *******************************************************************************/
void adc_multi_channel_init(void)
{
    /* Variable to capture return value of functions */
    cy_rslt_t result;


    /* Initialize ADC. The ADC block which can connect to pin 10[0] is selected */
    result = cyhal_adc_init(&adc_obj, VOLTAGE_CHANNEL, NULL);
    if(result != CY_RSLT_SUCCESS)
    {
        printf("ADC initialization failed. Error: %ld\n", (long unsigned int)result);
        CY_ASSERT(0);
    }


    /* ADC channel configuration */
    const cyhal_adc_channel_config_t channel_config = {
            .enable_averaging = false,  // Disable averaging for channel
            .min_acquisition_ns = 1000, // Minimum acquisition time set to 1us
            .enabled = true };          // Sample this channel when ADC performs a scan


    /* Initialize a channel 0 and configure it to scan P10_0 in single ended mode. */
    result  = cyhal_adc_channel_init_diff(&adc_chan_0_obj, &adc_obj, VOLTAGE_CHANNEL,
                                          CYHAL_ADC_VNEG, &channel_config);
    if(result != CY_RSLT_SUCCESS)
    {
        printf("ADC voltage channel initialization failed. Error: %ld\n", (long unsigned int)result);
        CY_ASSERT(0);
    }


/* Initialize a channel 1 and configure it to scan P10_0 in single ended mode. */
    result  = cyhal_adc_channel_init_diff(&adc_chan_1_obj, &adc_obj, CURRENT_CHANNEL,
                                          CYHAL_ADC_VNEG, &channel_config);
    if(result != CY_RSLT_SUCCESS)
    {
        printf("ADC current channel initialization failed. Error: %ld\n", (long unsigned int)result);
        CY_ASSERT(0);
    }




    /* Register a callback to handle asynchronous read completion */
     cyhal_adc_register_callback(&adc_obj, &adc_event_handler, result_arr);


     /* Subscribe to the async read complete event to process the results */
     cyhal_adc_enable_event(&adc_obj, CYHAL_ADC_ASYNC_READ_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true);


     printf("ADC is configured in multichannel configuration.\r\n\n");
     printf("Voltage channel is configured in single ended mode, connected to pin \r\n");
     printf("P10_0. Provide input voltage at P10_0\r\n");
     printf("Current channel is configured in single ended mode, connected to pin \r\n");
     printf("P10_1. Provide input voltage at P10_1\r\n");
}


/*******************************************************************************
 * Function Name: adc_multi_channel_process
 *******************************************************************************
 *
 * Summary:
 *  ADC single channel process function. This function reads the input voltage
 *  from channel 0 and channel 1. Prints the input voltage on UART.
 *
 * Parameters:
 *  void
 *
 * Return:
 *  void
 *
 *******************************************************************************/
void adc_multi_channel_process(void)
{
    /* Variable to capture return value of functions */
    cy_rslt_t result;


    /* Variable to store ADC conversion result from channel 0 */
    int32_t adc_result_0 = 0;


    /* Variable to store ADC conversion result from channel 1 */
    int32_t adc_result_1 = 0;


    /* Initiate an asynchronous read operation. The event handler will be called
     * when it is complete. */
    result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);
    if(result != CY_RSLT_SUCCESS)
    {
        printf("ADC async read failed. Error: %ld\n", (long unsigned int)result);
        CY_ASSERT(0);
    }


    /*
     * Read data from result list, input voltage in the result list is in
     * microvolts. Convert it millivolts and print input voltage
     *
     */
    adc_result_0 = result_arr[CHANNEL_0]/1000;
    adc_result_1 = result_arr[CHANNEL_1]/1000;
    printf("Voltage channel input: %4ldmV \t Current channel input: %4ldmV\r\n", (long int)adc_result_0, (long int)adc_result_1);


    /* Clear async read complete flag */
    async_read_complete = false;
}




/*******************************************************************************
 * Function Name: adc_event_handler
 *******************************************************************************
 *
 * Summary:
 *  ADC event handler. This function handles the asynchronous read complete event
 *  and sets the async_read_complete flag to true.
 *
 * Parameters:
 *  void *arg : pointer to result list
 *  cyhal_adc_event_t event : ADC event type
 *
 * Return:
 *  void
 *
 *******************************************************************************/
static void adc_event_handler(void* arg, cyhal_adc_event_t event)
{
    if(0u != (event & CYHAL_ADC_ASYNC_READ_COMPLETE))
    {
        /* Set async read complete flag to true */
        async_read_complete = true;
    }
}




void calculate_real_power(int16_t no_of_sample){


    cy_rslt_t adc_result;
    int32_t ins_voltage = 0;
    int32_t ins_current = 0;
    int32_t actual_ins_voltage = 0;
int32_t actual_ins_current = 0;
int32_t ins_power = 0;
    int16_t real_power = 0;


for(int16_t i=0; i<no_of_sample; i++)
{
adc_result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);
        if(adc_result != CY_RSLT_SUCCESS)
          {
               printf("ADC async read failed. Error: %ld\n", (long unsigned int)adc_result);
               CY_ASSERT(0);
          }
        ins_voltage = result_arr[CHANNEL_0]/1000;
        ins_current = result_arr[CHANNEL_1]/1000;
        actual_ins_voltage = ins_voltage * 400; //multiplied by scale factor of sensor
    actual_ins_current = ins_current * 100;
    ins_power = ins_power + actual_ins_voltage * actual_ins_current;
    async_read_complete = false;
}


real_power = ins_power/no_of_sample;
ins_power = 0;
//int16_t power = real_power;
printf("Power input: %4ldW\r\n", (long int)real_power);
}

  • Sign in to reply
  • shabaz
    shabaz over 4 years ago

    Hi Khairul,

     

    Extremely useful blog post! This is a great project.

    I'd really like to build this sometime.. I'll have to look for a smaller PSoC62 board.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube