Minor update to improve documentation and add missing functions.

PowerMeasurement.h

Committer:
WiredHome
Date:
2016-10-17
Revision:
2:7f6a39ec5c01
Parent:
1:d99a72afec32

File content as of revision 2:7f6a39ec5c01:

///
///
/// 

#ifndef POWERMEASUREMENT_H
#define POWERMEASUREMENT_H

#include "mbed.h"


/// The PowerMeasurement class is used to take voltage and current measurements and compute power consumption.
/// 
/// This is done as a process that takes some amount of time, as it will sample two inputs over a number of
/// cycles of the AC line input (typically 60 Hz). In order to avoid blocking the CPU any more than necessary
/// it will be processed with a ticker. So, there will be functions to start an acquisition, monitor the
/// acquisition, and extract the results when it is done.
///
/// The power measurement is performed on virtual channels, which map to real analog inputs. The virtual
/// channels may be direct-wired to the processor analog inputs, or it may be esternally multiplexed.
///
/// Electrically, the voltage measurements are normalized so the A/C swing is biased to mid-range on the
/// A/D and then peak-to-peak is measured from 0 to FFFF.
///
/// @code
///              NumMuxes
///              +----------+   MuxChannels
/// Input 1   ---|0        a|--------------------------------------+
/// Input 2   ---|1        b|--------------------------------------+
/// Input 3   ---|2        c|--------------------------------------+
/// ...       ---|          |                                      |
/// ...       ---|       inh|------------------------------------+ |
/// ...       ---|          |        AinCount                    | |
/// ...       ---|          |        +--------------+            | |
/// Input 8   ---|7        Y|--------|p15           |            | |
///              +----------+        |              |  Select    | |
///                                  |           pxx|------------+ |
///                             - - -|p16           |              |
///                                  |              |              |
///                                  |              |              |
///                                  |              |  MusBus      |
///                                  |           pcc|--------------+
///                                  |           pbb|--------------+
///                                  |           paa|--------------+
///  GetVoltage() ------->           |              |
///                                  +--------------+
///
/// @endcode
///
class PowerMeasurement {
public:
    /// The callback to get the instantaneous value of the voltage time-synchronous with the current measurement.
    ///
    /// The called function should return the instantaneous voltage measurement. The value is an unsigned value
    /// normalized to the range of 0 to FFFF, with a zero-offset of 32768.
    ///
    /// If not voltage measurement system is in place, the user may choose not to define this function, in 
    /// which case the power measurements cannot be made. The current measurements are still valid, and power
    /// can be computed by the users program.
    ///
    /// @returns a value in the range of 0 to FFFF, biased to the mid-point of 32768 which represents 0.0v.
    ///
    typedef uint16_t (* GetVoltage_T)(void);
    
    /// Each raw sample consists of 2 values - the voltage and the current at that moment. The labels 'voltage'
    /// and 'current' are somewhat artificial. The 'current' values are gathers from the analog inputs and 
    /// multiplexers. The 'voltage' is from an external callback, which in turn might be using one of the 
    /// analog inputs, or it might be from an external measurement source.
    typedef struct {
        uint16_t voltage;               ///< The voltage, in A/D units, which are scaled 0 to FFFF
        uint16_t current;               ///< The current, in A/D units, which are scaled 0 to FFFF
    } RawPowerData_T;
    
    #define SAMPLES_PER_CYCLE 100       ///< The number of samples in each cycle
    #define CYCLES_PER_SAMPLE 2         ///< The number of cycles in the sample
    #define PM_ZERO_OFFSET 32767        ///< Zero-Offset applied to A/D values
    #define PM_FULL_SCALE  32767        ///< The full-scale value against the calibration

    /// The constructor for the PowerMeasurement class is used to create various hardware assignments.
    ///
    /// @param[in] AinList is a pointer to an array of AnalogIn classes
    /// @param[in] MuxBus is a pointer to a BusOut that is used to select the external multiplexer channel.
    /// @param[in] Select is a pointer to a DigitalOut that is used to enable the external multplexer.
    /// @param[in] v_get is the callback used to get the voltage time synchronous with the current measurement.
    /// @param[in] AinCount is the count of Analog Inputs to use, from 1 to 6, which maps to p15 thru p20. Default: 6.
    /// @param[in] MuxChannels is the count of channels on each external multiplexer. Default: 8.
    ///
    PowerMeasurement(AnalogIn * AinList, BusOut * MuxBus = NULL, DigitalOut * Select = NULL, 
        GetVoltage_T callback = NULL, int AinCount = 6, int MuxChannels = 8);

    /// The destructor.
    ~PowerMeasurement();

    /// Define the frequency of the line voltage, which in turn defines the sample-rate.
    ///
    /// Based on this line frequency, the sample-rate for the measurement is set to achieve
    /// 'SAMPLES_PER_CYCLE' samples per cycle, and 'CYCLES_PER_SAMPLE' cycles.
    /// 
    /// @param[in] Hz sets the line frequency.
    ///
    void frequency(float _Hz);

    /// Define the measuremenbt interval, as an alternative to setting the frequency.
    ///
    /// Instead of defining the measurement interval by specifying the line frequency, the period
    /// can be directly set.
    ///
    /// @param uSec is the number of microseconds between samples.
    /// 
    void period_us(uint32_t uSec);

    /// Set the analog input to current calibration value for a channel.
    ///
    /// Each analog input channel can be configured for the current sensor used on that channel.
    /// If the channel has a 30 A current sensor, that channel should be set to 30.0f.
    /// If the user calibrates the sensor more precisely, an improved calibration factor (e.g. 31.1)
    /// can be defined.
    ///
    /// The calibration is based on the full-scale reading from the A/D. As the A/D is a normalized
    /// uint16_t value, and biased to approximately mid-supply, the full scale range is then
    /// 1/2 of the total range, or approximately 32767. Component tolerances, of the voltage 
    /// reference, the mid-supply divider, and the current sensing component can affect this.
    ///
    /// @param[in] channel defines the channel to calibrate.
    /// @param[in] fullScaleCurrentCalibration is the calibration factor representing the full-scale current.
    /// @returns true if the value is accepted.
    /// @returns false if the channel was incorrect.
    ///
    bool SetFullScaleCurrent(int channel, float fullScaleCurrentCalibration);

    /// Set the voltage value representing the full scale measurement.
    ///
    /// The GetVoltage callback is expecting a uint16_t as the return value. When configured for a 
    /// 120V circuit, which measures approximately 170v peak, the fullScaleVoltageCalibration value 
    /// would be 170.0f.
    /// 
    /// The calibration is based on the full-scale reading from the A/D. As the A/D is a normalized
    /// uint16_t value, and biased to approximately mid-supply, the full scale range is then
    /// 1/2 of the total range, or approximately 32767. Component tolerances, of the voltage 
    /// reference, the mid-supply divider, and the current sensing component can affect this.
    ///
    /// @param[in] fullScaleVoltageCalibration is the full-scale voltage value.
    /// @returns true if the value is accepted, which it will be.
    /// 
    bool SetFullScaleVoltage(float fullScaleVoltageCalibration);

    /// Starts a measurement on the specified channel.
    ///
    /// This starts the measurement on a specified channel. The subsystem will then configure
    /// the external multiplexer and a/d sampling to gather the the samples.
    ///
    /// The actual sampling of the data can be either synchronous, or asynchonous, based on a
    /// #define value.
    ///
    /// @param[in] channel defines the channel to measure. This is in the range of 0 to N-1, where N is 
    ///         AinCount * MuxChannels.
    /// @returns true if the measurement can be started (in async mode), or if the measurement is complete
    ///         when operating in synchonous mode.
    /// @returns false if the measurement cannot be started - likely because of an incorrect channel 
    ///         selection.
    ///
    bool StartMeasurement(int channel);

    /// Determines if the conversion is complete and the results are readable.
    ///
    /// When operating in the asynchronous mode, this API can be used to detect when the conversion
    /// is complete.
    ///
    /// @returns true if the measurement is complete (or if no measurement is in process).
    /// @returns false if the measurement is in process.
    ///
    bool readable();

    /// Get the rms current measurement.
    ///
    /// This retrieves the rms current measurement for the channel which just completed measurement.
    ///
    /// @returns the rm current measurement.
    ///
    float GetRMSCurrent();

    /// Get the rms voltage measurement.
    ///
    /// This retrieves the rms voltage measurement for the channel which just completed measurement.
    ///
    /// @note This is only valid if the user supplied GetVoltage() function was provided.
    ///
    /// @returns the rms voltage measurement.
    ///
    float GetRMSVoltage();

    /// Get the real power measurement.
    ///
    /// This retrieves the real power measurement for the channel which just completed measurement.
    /// This is the average of the instantaneous power.
    ///
    /// @note This is only valid if the user supplied GetVoltage() function was provided.
    ///
    /// @returns the real power measurement.
    ///
    float GetRealPower();

    /// Get the apparent power measurement.
    ///
    /// This retrieves the apparent power measurement for the channel which just completed measurement.
    ///
    /// @note This is only valid if the user supplied GetVoltage() function was provided.
    ///
    /// @returns the apparent power measurement.
    ///
    float GetApparentPower();

    /// Get the power factor
    ///
    /// @note This is only valid if the user supplied GetVoltage() function was provided.
    ///
    /// @returns the power factor measurement.
    ///
    float GetPowerFactor();

    /// Get the peak current measurement values from the recent sample.
    ///
    /// @note if either parameter is null, that data will not be provided.
    ///
    /// @param[inout] negPeak is a pointer to the negative going peak current measured.
    /// @param[inout] posPeak is a pointer to the positive going peak current measured.
    /// @returns true if a measurement was completed and the data was updated.
    /// @returns false if a measurement has not started or is in process.
    ///
    bool GetPeakCurrent(float * negPeak, float * posPeak);

    /// Get the raw sample data for a given sample number.
    ///
    /// If a measurement is complete, or has at least proceeded beyond the desired
    /// sample, then pass that raw data to the calling function.
    ///
    /// @param[in] sample is the sample number of interest, ranging from 0 to N-1.
    /// @param[inout] rawsample is a pointer to where the specified sample will be written.
    /// @returns true if the sample was available for the calling function.
    /// @returns false if the same was not available.
    ///
    bool GetRawSample(int sample, RawPowerData_T * rawsample);

    /// Get the count of raw samples that are being taken,
    ///
    /// @returns count of samples that are taken.
    ///
    int GetRawSampleCount(void);

private:

    void TakeSample(void);          ///< Ticker callback to take a sample
    BusOut * MuxBus;                ///< pointer to the bus used to modify the multiplexer.
    DigitalOut * Select;            ///< pointer to the pin used to enable the multiplexer.
    GetVoltage_T * GetVoltage;      ///< pointer to the GetVoltage callback.
    int AinCount;                   ///< count of direct A/D channels.
    int NumMuxes;                   ///< count of the number of multiplexers.
    int MuxChannels;                ///< count of the number of channels per multiplexer.
    
    AnalogIn * AinList;             ///< This defines the list of AnalogInputs
    int a2dChannel;                 ///< the AnalogIn channel number to sample
    uint32_t uSecInterval;          ///< time in uSec between each sample
    int totalChannels;              ///< total number of input channels
    Ticker sampleTimer;             ///< Timer to schedule the a/d sample.    
    volatile bool inProcess;                 ///< indicates when a sample is in process.
    volatile bool isComplete;                ///< indicates when conversion is complete.
    RawPowerData_T * rawSamples;    ///< points to an array of raw a/d value samples.
    volatile int sampleNum;                  ///< keeps track of the current sample in process.
    float * fullScaleCurrent;       ///< pointer to an array sized based on total number of channels.
    float fullScaleVoltage;         ///< the full scale voltage calibration setting.
};




#endif // POWERMEASUREMENT_H