Group Members:
I would like to take the opportunity to acknowledge the direct and indirect help
of all the people who made this thesis possible.
I would like to thank my parents for always supporting me. Without them this
degree would not have been possible.
Also most importantly thanks and praises to the God almighty for successful
completion of thesis.
Acknowledgements............................................................................................ 1
Table of Contents .............................................................................................. 2
Motivation .......................................................................................................... 5
Abstract .............................................................................................................. 6
A planet where more than 2 billion people don't have any access to electricity,
energy is a key issue in people's lives. It's also an important factor that shapes
the development of any modern day economy. As the demand for energy keeps
on increasing each year, new alternative ways to generate energy are looked
into. It's been estimated the demand for electricity will increase threefold till
2050. So to keep up with the energy demands, renewable energy (RE) plays a
vital role in today's world . The study focuses on importance of Inverters which
are the core part of any modern day power system. It also looks into factors that
affect efficiency, cost and reliability of these systems. Further this study looks
into Space vector algorithm implementation in analysed in Matlab SIMULINK
software and real-time.
1.1 Purpose
As RE technologies are growing at a fast pace worldwide, still vast majority of
people don't have any sufficient knowledge in terms of their need and impact.
Inverters are a key component in any RE technology. Inverter is a device that is
widely used all over the world to convert DC input voltage into AC. The
output typically of an Inverter should be a pure sinusoidal waveform. However,
most of the practical inverters don't have pure sinusoidal output and they also
contain harmonics. This study focuses on these challenges and tries to provide
a solution. Following problems are focused in this thesis:
1.2 Objective
The main objective of our project is to develop a novel highly efficient, cost
effective, compact, reliable three-phase two-level inverter by implementing
Space Vector Modulation (SVPWM) using the programming environment of
MATLAB as its basis. All renewable energy sources are in need of multilevel
power electronics in form of multilevel inverters. The mind behind the pulses
created by the inverters is the SVPWM. This modulation type uses a space
vector, referred to as the reference vector, to locate and create the desired
sinusoidal-shaped waveform. We will also construct a DC-DC Boost Converter
using Push-Pull topology, which will supply 650-700V to the high voltage DC
bus of the multilevel inverter. Finally we will construct a Three-Phase Energy
meter to display the energy being consumed by the inverter. This energy meter
will be capable of saving data and logging it onto to the internet
This chapter gives the introduction about the thesis. Also it describes the need
of the project, objectives that will be achieved and research methodology
regarding the project.
This chapter is about the various research papers used to inquire information
about our project
This chapter is related to all the modules and techniques used to design a PV
Grid-Tie Inverter. Basic characteristics of a PV module are analysed in the start
of chapter. Then single phase and three phase inverter topologies of PV
inverters are compared to each other. Different types of boost DC-DC
converters, MPPT algorithms, AC-DC converters are described ahead in the
chapter. Also different switching modulation techniques are mentioned. In the
end description about protection systems, harmonics in system and different
type of switching semiconductors are described.
This chapter is about the wind systems and its different components. This
chapter begins with different types of wind turbines and generators. Then
different control methods used for wind turbines are mentioned. Also power
converter and grid topologies for wind systems are described. Finally the
typical characteristics of a standard wind turbine are described in the chapter.
The chapter summarizes the entire research project and the outcomes achieved
in it. Also future work regarding the enhancement of the project is discussed in
the end.
Series compensator
Shunt compensator
Combined series compensators
Combined shunt compensators
The simulation for the different modulation strategies are carried out in open
loop, since the purpose is to make a comparison between the performance of
the system with synchronized pulses, shifted pulses and the proposed system
using two-level SVM. In addition, simulation results of the inverter will be
briefly discussed. By running the system in open loop it can be observed what
amount of THD and which harmonics the different strategies will generate.
Simulation Parameters:
Power for each inverter = 2kW
VDC = 700V
Carrier frequency fcarrier = 5000Hz
Modulation index ma = 0.9 (Vref = 280V)
Three-phase load inductor = 7.2mH
Load resistor = 40
4.1 DC to DC Topologies:
A switching mode DC to DC converter is a simple device that converts low
voltage level to high voltage level. Boost convertors are really important part of
any modern day solar invertors. As solar cells alone or even when combined
together in different configurations, cannot provide the sufficient voltage
output levels. Three phase voltage output are usually around 480-500V and to
achieve such voltage levels DC voltage output from the panels must be boosted
accordingly. Boost converter functions by increasing the VDC to a higher value
by controlling the duty cycle of signal generator. There are three types of boost
converters: Buck Boost converter, Boost converter and CUK converter. Basic
circuit all these three converters contain the same four components that are:
capacitor, inductor, diode and a switching component like an MOSFET/IGBT.
The only difference is the arrangement of these components in their respective
circuits.
Buck-Boost Converter
When the switch S is turned on, energy starts to accumulate inside the inductor
L. At this point capacitor C starts supplying energy to the output load. While
CUK Converter
CUK converters are another type of DC-DC converters that can boost the input
voltage levels to the desired level. CUK converters are mostly used in
applications where a battery needs to be charged. CUK converter basic
circuitry consists of two inductors, two capacitors, a diode and switching
component (IGBT/MOSFET). CUK converters output is always inverted,
meaning the voltage is negative at the output. Fig.4.1 shows a CUK converter.
BOOST Converter
Boost converter is the most widely used DC-DC converter to boost the input
DC voltage. The key thing to all the boost converters is the property of an
inductor. As inductor can resist the current changes it undergoes by generating
or destroying a magnetic field. In all boost converters output can never be less
than the input. Fig.4.2 shows basic circuit diagram of a boost converter.
Capacitance=D/2*F*R Equation(4.2)
Mode 1:- when S1 is ON and S2 is OFF, the diode D1 is forward biased and
D2 is reverse biased.
Mode 2:-when S2 is ON and S1 is OF, the diodeD2 is forward biased and D1 is
reverse biased.
Mode 3:- when S1 and S2 are OFF, the diodes D1 and D2 are forward biased.
The frequency on the secondary side voltage pulses twice the switching
frequency of the transistors [4].
Half-bridge:
Full-bridge:-
Four switching transistor use in full-bridge convertor. They are switched
alternately pair wise. Due to high cost and complexity, the full-bridge topology
is used in very high power applications [6].The output is full wave bridge
configuration with approximately half number of secondary turns.
1. Gate driver
2. Ferrite Core Transformer E65/32/27
3. Inductor
4. Capacitor
5. MOSFET IRF3808
6. Ultrafast Rectifier diodes MUR1560
Introduction
The development of semiconductor devices has made converters more
affordable in a large number of applications. This is due to increased power
capabilities, easier control and reduced cost of modern power semiconductors.
Currently the power semiconductors can be classified into three groups
according to their controllability [7]:
1. Diodes controlled by the power circuit
2. Controllable switches turned off and on by a control signal
3. Thyristors, latched on by a control signal but turned off by the power circuit
IRF3808:-
Switching behavior
The switching times of a power MOSFET are
Determined by the speed at which its internal capacitances can be
Charged and discharged by the chosen drive circuit [8].
Therefore the switching characteristics of the power MOSFET are determined
by its
Three internal capacitances. These capacitances are not fixed but are a function
of
The voltages between the MOSFET’s terminals.
Switching performance
Turn-on
During the turn-on phase the following parameters are of relevance [9]:
1. Turn-on time
2. Turn-off loss
3. Peak dv/dt
4. Peak dI/dt
The turn-on time is simply determined by the speed of which the drive circuit
can charge the gate.
Diodes
A diode begins to conduct when it is forward biased. The voltage drop across
the device is small, on the order of 1 V depending on the diode type. When the
diode instead is reversed biased, a small negligibly leakage current will flow
until the reverse breakdown voltage level is reached [10].
A diode can be considered as an ideal component at turn-on because it turns on
more rapidly than the transients in the power circuit. At turn-off the current
instead reverses for a time trr before it falls to zero. This phenomenon occurs
because excessive carriers have to be swept out and block a negative voltage.
The circuit symbol can be seen in figure 4a, the steady-state i-v characteristic
and its idealized characteristics in figure 4.9.
Gate driver:-
We use gate driver for generating high frequency signal and it’s generate two
signals for operating push-pull MOSFET. The frequency of gate driver is 40
kHz and it’s generate two signals of 40 kHz frequency which use for operating
MOSFET.
SG5325:-
SG3525 use for generating PWM. SG3525 has 16 pins IC
Every pin has own function and importance for generating signals.
The frequency of PWM is depend on the timing capacitance and the timing
resistance.
Calculation:-
Timing Capacitor CT= 0.01 µF
Timing Capacitor RT= 3.3 KΩ
Deadtime RD= 0 Ω
Maximum duty cycle Dmax = 49%
Ferrite are ceramic compound which are the mixer ofIron oxide (Fe2O3).
Ferrite cores are used in Transformers where the supply voltage has a high
frequency. Its work near 70MHz.our simple transformer never b handle this
frequency.
Core material
As the purpose of the thesis is to implement a DC/DC converter that operates at
frequencies up to 1 MHz, the ferrite core is chosen to have low losses at those
frequencies. Ferroxcube is a leading supplier of ferrite components [7].
Ferrite has a high permeability which make it suitable for use as a core for
higher frequencies. It also very highly resistivity. This ensures that eddy
currents and hysteresis losses are minimum.
The combination of high permeability and high resistivity make Ferrite ideal
for high frequency transformer core design. The only disadvantage is that being
a ceramic it is brittle and is vulnerable to cracks [2]
What is powerESim?
PowerESim is a tool that allow you to complete a switching power design in
few minutes. It is a tool that allows you to design without looking at
component datasheets or design equations. It is a tool that brings engineers and
components vendors closer together separated only by a click on the web.
Switching power supply design is a tedious process. Although the know-how
and design techniques for popular circuit topology are largely known to design
engineers, the many choices of electronic components make it a very tedious
process for engineers to recalculate for the whole design every time he changes
a component. There are numerous combinations of electronic components that
can be used in a single circuit, and very often the choice of components is
critical to the success of the product both in terms of product performance and
market competitiveness. The design iteration process is time consuming and
can be erroneous if done manually. Now here is a tool that can do all this
automatically in seconds [3]
But for push pull it will be half the primary number of turns.
Where Npi is primary number of turn, Vin( nom) is normal input voltage
Bmax is maximum flux density.
T/2 is switching time and is equal to 23.1x10-6s
Ae is Effective magnetic cross section of ferrite core. We have to refer data
sheet for this value. In this example, we are using ETD39 core. The effective
cross sectional area of E 65/32/27is 540mm2.
Hence Npri = 3
Its mean we can take Npri = 3 for further calculations. Primary number of turns
for push pull ferrite center tap transformer is 3 turns + 3 turns.
J=3.1/540m=5.7A/m2
Take current density of 5 A/mm2
Secondary wire cross section area = 3.1 / 5 = 0.62 mm2
As primary turns are only 3, higher current density may be allowed (9 A/mm2).
Primary wire cross section area = 57 / 9 = 6.3 mm2
Same secondary current flows through this inductor also, so the same 20 SWG
wire may be used.
\
Final Prototype
• Over load, short circuit and over voltage protection using interrupts.
The basic design of our energy meter consists of three current transformer and
voltage transformers connected to the output of the three-phase inverter.
Atmega2560 measures current and voltage and uploads the values to the
internet using ESP8266. Finally energy consumption graph is drawn on the
website hosting our meter values
An RMS value is the square root of the mean value of the squared
instantaneous values, averaged over one complete AC cycle.
From the time difference between these two waves, we calculate the phase
difference. Since we know the crystal frequency is 16MHZ and machine cycle
takes 0.3uS hence we can easily find the phase difference.
7.1Summary &Conclusion
In this thesis, the focus of research work is on the importance of renewable
energy, development of Grid-Tie inverters for PV and wind, development of
utility grid and finally the use of multi-level inverters. Main attention is paid on
development of these technologies on the basis of cost, efficiency and
reliability. The research was also carried in areas of, different control
modulation techniques, development of MPPT controller and different
wind/PV related devices.
Renewable Energy
The Investigation into the importance of renewable energy was done using the
worldwide statistics for wind and PV related devices. The trend clearly is
shifting globally towards the RE technologies. Every year more than 50 percent
of the new energy projects are based on RE. As due to the increase in
development of these technologies over the last decade, cost/watt output
through RE is clearly decreasing. As Europe is far from the equator, it doesn't
receive too many sunny hours yearly. Therefore, wind energy is commonly
used in Europe. As the energy demand continues to grow, fossil fuels cannot
keep up for too long. Also fossil fuels are hindrance in the path of preservation
of environment; governments are investing more in cleaner form of energy. As
due to these facts, it justifies the research being carried on RE technologies.
The design of the 1MW grid tie PV inverter is based on string and multi string
inverter topologies. These topologies were selected to increase the efficiency
and reliability of system. The PV inverter compromised of PV panel, DC-DC
converter and DC-AC converter. Total of 10 PV panels modules were used,
each module compromised of 8 series and 66 parallel solar cells. The power
output from each PV module was 100KW at MPP. Each PV module has its
own DC-DC boost converter with a built-in MPPT controller. This
configuration increased the efficiency of system greatly, as each individual
module can track down its own MPP. The MPPT controller successfully tracks
the MPP point as the irradiation varies. The DC-DC output was regulated at
500V, through a grid side PWM based voltage regulator. For the DC-AC part
three phase three level voltage source converter (VSC) was used. The output of
VSC was attached to a choke and capacitor bank before injecting the power
into the grid. Power was injected by stepping up 260V, 50 Hz voltage to 25KV
(distribution level voltage) by a three phase transformer. The power of 1MW
was successfully transferred into the grid.
The proposed utility grid has all the essential components of a standard grid.
For the distribution level 25 KV voltage level is used. The total transmission
line (Feeders) in the system is 30KM. These feeders act like a bridge between
the distribution and transmission level. Two loads of 30MW and 2MW are
attached to the grid. Transmission level is maintained at 120KV using a three
phase voltage source. A step-up transformer is used to connect the distribution
level of 25KV to 120KV transmission level. Also a grounding transformer is
used to create a neutral point in a three phase system.
7.2Future Work
For the thesis models for PV and wind grid-tie inverters and multi-level
inverter are proposed.For the future development and enhancement of the
models, these factors can be investigated:
The proposed models for wind and PV are only implemented using simulation
software. In actual scenario many of the factors may affect the system. So a
The future work can be carried in enhancing the wind and grid inverters by
using more levels for the inverter design. For this thesis only three level VSC
converters are used for PV and Wind. To improve the output, more levels
based VSC can be adopted.
There are many new modulation techniques such as space vector pulse width
modulation (SVPWM) or multi-level pulse width modulation that can offer
better control and harmonic suppression in the system. For the wind systems,
Matrix Converter Modulation can be used. Matrix Converter Modulation
increases the efficiency of wind systems considerably.
There are new semiconductor devices based silicon carbide (SiC) and gallium
nitrate (GaN). These semiconductors devices can be used in inverters to
improve the efficiency and reliability of system even more. So for the future
work, the proposed models in this thesis could be used with SiC and GaN
based semiconductors.
The proposed models of PV and wind systems can be integrated together for
the future work. These types of systems are called as hybrid systems,
containing different types of power generation elements. This can be helpful to
analyze the behavior of PV and wind systems when combined together.
[8] New and Renewable Energy Authority (NREA). Annual report 2010/2011..
[10] north carlolina solar center. (2011). solar center information. 7401. 2 (3),
p01-06.
[22] David Sanz Morales. (2011). Maximum Power Point Tracking Algorithms
for Photovoltaic Applications. . 1 (1), pg8-p40.
[31] David Whaley. (2012). Low cost small scale wind turbine. . 1 (1), p19-44.
[34] Christian Freitag. (2006). Variable Speed Wind Turbine equipped with a
Synchronous Generator. . 1 (1), p20-45.
[35] Nurul Aisyah Yusof. (2013). A Comparative Study of 5-level and 7-level
Multilevel Inverter Connected to the Grid. . 1 (3), p2-8.
dataType = 'double';
if isempty(Vold)
Vold=0;
Pold=0;
Dold=Dinit;
end
P= V*I;
dV= V - Vold;
dP= P - Pold;
Dold=D;
Vold=V;
Pold=P;
33753, 34728, 35693, 36647, 37589, 38521, 39440, 40347, 41243, 42125,
42995, 43851, 44695, 45524, 46340, 47142, 47929, 48702, 49460, 50203,
50930, 51642, 52339, 53019, 53683, 54331, 54962, 55577, 56174, 56755,
57318, 57864, 58392, 58902, 59395, 59869, 60325, 60763, 61182, 61583,
61965, 62327, 62671, 62996, 63302, 63588, 63855, 64103, 64331, 64539,
64728, 64897, 65047, 65176, 65286, 65375, 65445, 65495, 65525, 65535,
};
float icos(int x)
{
return isin(x + 90);
}
float itan(int x)
{
return isin(x) / icos(x);
}
#endif
#include "FastSin.h"
#include <TimerThree.h>
unsigned int degree = 0; // to count degree: 0, 6, 12, 18, ... 354, 0, 6, 12,...
unsigned int SV_angle = 0; //angle of space vector: from [0 to 360)
float SV_magnitude = 0.8f; //magnitude of space vector: from [0 to 1]
//timer3 interupt
void timer3Int(void) //278us
{
//debug pin high when begin interupt
digitalWrite(debugPin, HIGH);
if (degree == 360){
degree = 0;
}
else{
degree += 6;
}
SV_angle = degree;
SVPWM_run(SV_angle, SV_magnitude);
void setup()
{
pinMode(debugPin, OUTPUT);
Timer3.initialize(278*5); //timer period us
// we divide 360 degree (1 sin wave cycle (~16,667us) into 60 part)
// 16,667 / 60 ~ 278
// real cycle = 278*60 = 16,680 us (~ 60hz)
// pwm freq : 1/ 278us ~ 3.6kHz
//call these func to setup ports to ouput PWM // These are prettly slow
compare to Timer3.setPwmDuty
Timer3.pwm(phaseA, 0);
Timer3.pwm(phaseB, 0);
Timer3.pwm(phaseC, 0);
Serial.begin(9600);
}
void loop()
{
//this func will calculate and output PWM for 3 switches from angle and
magnitude of space vector
void SVPWM_run(unsigned int a, float m)
{
// use "static" to make it a little bit faster. But consume more memory
static float Ualpha, Ubeta;
static float X, Y, Z;
static float PWMa, PWMb, PWMc;
uint8_t sector;
if (a < 60){
sector = 1;
}
else if (a < 120){
sector = 2;
}
else if (a < 180){
sector = 3;
}
else if (a < 240){
sector = 4;
}
else if (a < 300){
//maximum PWM for each pin is 1023. We just need the percentage of
1023
Timer3.setPwmDuty(phaseA, 1023 * PWMa);
Timer3.setPwmDuty(phaseB, 1023 * PWMb);
Timer3.setPwmDuty(phaseC, 1023 * PWMc);
/*
* Adapted: 28/04/2017
* Author: supernova432
*/
//------------------------------------------------------------------------------------
// DEFINES For LCD Display
#define NUMBER_OF_SCREENS 3
#define MAX_AMPS_PER_PHASE 15 // 15 A per phase supply
#define MAX_WATTS_PER_PHASE 3450 // 3450 W per phase supply
// set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x3F,20,4);
LcdBarGraph lbg1(&lcd, 10, 10, 0); // -- creating bargraph line 1
LcdBarGraph lbg2(&lcd, 10, 10, 1); // -- creating bargraph line 2
LcdBarGraph lbg3(&lcd, 10, 10, 2); // -- creating bargraph line 3
char bufferString[25];
int lcdEcranAmp = 1;
boolean activityLed = true;
//------------------------------------------------------------------------------------
// DEFINES For Ethernet
//------------------------------------------------------------------------------------
// ethernet interface mac address
static byte mymac[] = { 0x00,0x01,0x02,0x03,0x04,0x05 };
// ethernet interface ip address
static byte myip[] = { 192,168,0,202 };
// gateway ip address
static byte gwip[] = { 192,168,0,254 };
// server Ip
static byte webServerIp[] = { 192,168,0,200};
static int webServerPort = 80;
// remote website name (for testing ethernet OK)
char website[] PROGMEM = "www.google.com";
#define VERSION 3
#define NODE_TYPE 0x01
//MAX_SHIFT_DEGREE = 240
#define ADC_BUFFER_SIZE 33 //
((((SAMPLES_PER_SECOND/FREQUENCY) * MAX_SHIFT_DEGREE) /
360) +1);
#define PHASE1_OFFSET 16
#define PHASE2_OFFSET 32
*/
/*
Pooling Order:
3-Phase voltages and 3-CT:
Voltage1, Current1, Voltage2, Current2, V3, C3, V1, C1...
1Phase Voltage - 3 Phase CT:
Voltage1 - Current1, Current2, Current3, Voltage1...
*/
struct Config {
byte band;
byte group;
byte nodeID;
byte sendTo;
byte transmitinterval;
float Phase_Calibration[3];
float Current_Calibration[3];
//Temp variables
PayloadTX emontx;
long adcval;
volatile unsigned char AdcIndex = 1; //keeps track of sampled channel
volatile unsigned int SampleCounter, crossCounter, LastSampleCounter;
volatile boolean Cycle_Full; //stores wherever the cycle has been computed
boolean lastVCross, checkVCross; //Used to measure number of times
threshold is crossed.
unsigned char tempidx;
struct CurrentSampleS {
struct VoltageSampleS {
float New, Previous;
float Filtered,PreviousFiltered, PhaseShifted, Calibrated, Sum;
} VoltageSample[3]; //Yes phases here, because we are going to create
the voltage data based on what we have //for now i will maintain 3 here
hardcoded because i dont want to put 300 ifs on the code yet.
struct LastCurrentS {
float Sum, InstPower;
} LastCurrent[3];//for now i will maintain 3 here hardcoded because i
dont want to put 300 ifs on the code yet.
struct LastVoltageS {
float Sum;
} LastVoltage[VOLTAGE_SENSORS];
float AccVrms[3];
float AccIrms[3];
float AccRealPower[3] ;
float AccAparentPower[3];
float AccPowerFactor[3];
//TODO fix if the 3 sensors are on the same phase, puto some code here
#if VOLTAGE_SENSORS == 1 && PHASE_SENSORS > 1
#define ADC_BUFFER 1
//declare voltage buffer
float ADC_V_BUFFER[ADC_BUFFER_SIZE+2];
unsigned char adc_buffer_index = (ADC_BUFFER_SIZE-1);
#endif
boolean temp = 0;
float tempdbl = 0.0;
unsigned char tmpchar;
volatile unsigned long LastInterruptTime;
/*
void initRF(){
byte freq = config.band == 4 ? RF12_433MHZ :
config.band == 8 ? RF12_868MHZ :
RF12_915MHZ;
#ifdef SERIAL
Serial.print("Initialiazing RF: Node:");
Serial.print(config.nodeID);
Serial.print(" Freq:");
Serial.print(freq);
Serial.print(" group:");
Serial.println(config.group);
#endif
rf12_initialize(config.nodeID, freq, config.group);
}
*/
void setup()
{
#ifdef SERIAL
Serial.begin(57600); //begin Serial comm
//Setup LCD
lcd.init(); // initialize the lcd
lcd.backlight();
lbg1.init();
lbg2.init();
lbg3.init();
lcd.createChar(6, sum);
lcd.createChar(7, heart);
lcd.home();
lcd.print("emonTX UP & Running!");
lcd.setCursor(19, 3);
lcd.printByte(7);
lcd.setCursor(0,2);
lcd.print(" Init Ethernet ");
#ifdef SERIAL
Serial.println("Setup Ethernet .......");
#endif
if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0) {
#ifdef SERIAL
ether.staticSetup(myip, gwip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("Google Server: ", ether.hisip);
lcd.setCursor(0, 1);
lcd.print(" Ethernet OK : ");
lcd.setCursor(0, 2);
lcd.print("IP : ");
lcd.print(ether.myip[0]);
lcd.print(".");
lcd.print(ether.myip[1]);
lcd.print(".");
lcd.print(ether.myip[2]);
lcd.print(".");
lcd.print(ether.myip[3]);
loadConfig();
//initRF();
emontx.numV = VOLTAGE_SENSORS;
emontx.numI = PHASE_SENSORS;
// ADC initialization:
// Enable ADC interrupt and use external voltage reference.
// Set multiplexer input to first channel and do not set
// ADC to High Speed Mode. Set Auto Trigger Source to Free Running Mode.
//
// fCLK | ADPS | Prescaler | ADCCLK | Sampl.Rate
// ------+------+-----------+--------+-----------
// 4.000 | 111 | 128 | 125000 | 9615
//put code here to start adc after zero crossing. *TODO* but not a problem,
because we do not pick up first sampled data...
//...
//Start ADC
#ifdef SERIAL
Serial.println("Open Energy Monitor Hack by Pcunha");
Serial.println("Starting ADC in next cycle");
#endif
lcd.setCursor(0, 3);
lcd.print("Starting measuring");
//timer to watch (on serial port) duration of ADC interrupt service routine
timerCalculation = millis();
ADCSRA=0xEF; // Enable ADC, start, auto trigger, int enable, presc = 128
//------------------------------------------------------------------------------------
//ADC INTERRUPT SERVICE ROUTINE
//------------------------------------------------------------------------------------
ISR(ADC_vect){ //ADC interrupt
//unsigned long t1;
unsigned char IndexAtual = 0;
//t1 = micros();
//
if (AdcIndex > 0)
IndexAtual = AdcIndex - 1;
else
IndexAtual = PHASE_SENSORS + VOLTAGE_SENSORS -1;
//IndexAtual = (PHASE_SENSORS + VOLTAGE_SENSORS - 1); // adc is
always 1 nextindex negative
//Voltage1 - First voltage sensor (Open Energy Monitor only have this voltage
sensor)
#ifdef V0
if (IndexAtual == V0){ //Very strange behavior when using ifdef here
with 0 value
// Store Last Values for future use
VoltageSample[0].Previous = VoltageSample[0].New; //Put
last sample on its place
VoltageSample[0].PreviousFiltered = VoltageSample[0].Filtered;
//Put last sample on its place
// Read in raw voltage and current samples
VoltageSample[0].New=ADC; //Read in raw voltage signal
from index sample
// Apply digital high pass filters to remove 2.5V DC offset
(centered on 0V).
VoltageSample[0].Filtered = 0.996 * (
VoltageSample[0].PreviousFiltered + VoltageSample[0].New -
VoltageSample[0].Previous );
// Root-mean-square method Index Channel
// -> sum the square of voltage values
VoltageSample[0].Sum += VoltageSample[0].Filtered *
VoltageSample[0].Filtered;
// Phase calibration
VoltageSample[0].PhaseShifted =
VoltageSample[0].PreviousFiltered + config.Phase_Calibration[0] *
(VoltageSample[0].Filtered - VoltageSample[0].PreviousFiltered);
//If using ADC BUFFERING
//unsigned int ADC_V_BUFFER[ADC_BUFFER_SIZE];
//volatile unsigned char adc_buffer_index;
#ifdef ADC_BUFFER
if (--adc_buffer_index == 255)
adc_buffer_index=(ADC_BUFFER_SIZE-1);
//Current1
#if ((IO == 0) || (IO == 1))//Very strange behavior when using ifdef here with 0
value
if (IndexAtual == I0){ //First CT
//A) Store Last Values for future use
CurrentSample[0].Previous = CurrentSample[0].New; //Put
last sample on its place
CurrentSample[0].PreviousFiltered = CurrentSample[0].Filtered;
//Put last sample on its place
// Read in raw voltage and current samples
CurrentSample[0].New=ADC; //Read in raw voltage signal
from index sample
// Apply digital high pass filters to remove 2.5V DC offset
(centered on 0V).
CurrentSample[0].Filtered = 0.996 * (
CurrentSample[0].PreviousFiltered + CurrentSample[0].New -
CurrentSample[0].Previous );
// Root-mean-square method Index Channel
// -> sum the square of voltage values
CurrentSample[0].Sum += CurrentSample[0].Filtered *
CurrentSample[0].Filtered;
// Instantaneous power calc now that we have I and V
#if VOLTAGE_SENSORS > 0
CurrentSample[0].InstPower +=
VoltageSample[0].PhaseShifted * CurrentSample[0].Filtered; //Instantaneous
Power //mudar pphaseshift
#else
CurrentSample[0].InstPower = CurrentSample[0].Filtered;
#endif
}
#endif
#ifdef V1
if (IndexAtual == V1){
//A) Store Last Values for future use
VoltageSample[1].Previous = VoltageSample[1].New; //Put last sample
on its place
VoltageSample[1].PreviousFiltered = VoltageSample[1].Filtered; //Put
last sample on its place
// Read in raw voltage and current samples
#ifdef I1
if (IndexAtual == I1){ //First CT
//A) Store Last Values for future use
CurrentSample[1].Previous = CurrentSample[1].New; //Put last
sample on its place
CurrentSample[1].PreviousFiltered = CurrentSample[1].Filtered;
//Put last sample on its place
// Read in raw voltage and current samples
CurrentSample[1].New=ADC; //Read in raw voltage signal from
index sample
// Apply digital high pass filters to remove 2.5V DC offset (centered on
0V).
CurrentSample[1].Filtered = 0.996 * (
CurrentSample[1].PreviousFiltered + CurrentSample[1].New -
CurrentSample[1].Previous );
// Root-mean-square method Index Channel
// -> sum the square of voltage values
CurrentSample[1].Sum += CurrentSample[1].Filtered *
CurrentSample[1].Filtered;
// Instantaneous power calc now that we have I and V
#if VOLTAGE_SENSORS > 1
CurrentSample[1].InstPower += VoltageSample[1].PhaseShifted
* CurrentSample[1].Filtered; //Instantaneous Power
#else
#ifdef ADC_BUFFER //if there is adc buffering
tmpchar = (adc_buffer_index + PHASE1_OFFSET) %
ADC_BUFFER_SIZE;
tempdbl = ADC_V_BUFFER[tmpchar];//
(adc_buffer_index + PHASE1_OFFSET)% ADC_BUFFER_SIZE);
//aqui
#ifdef V2
if (IndexAtual == V2){
//A) Store Last Values for future use
VoltageSample[2].Previous = VoltageSample[2].New; //Put last sample
on its place
VoltageSample[2].PreviousFiltered = VoltageSample[2].Filtered; //Put
last sample on its place
// Read in raw voltage and current samples
VoltageSample[2].New=ADC; //Read in raw voltage signal from index
sample
// Apply digital high pass filters to remove 2.5V DC offset (centered on 0V).
VoltageSample[2].Filtered = 0.996 * ( VoltageSample[2].PreviousFiltered +
VoltageSample[2].New - VoltageSample[2].Previous );
// Root-mean-square method Index Channel
// -> sum the square of voltage values
VoltageSample[2].Sum += VoltageSample[2].Filtered *
VoltageSample[2].Filtered;
// Phase calibration
VoltageSample[2].PhaseShifted = VoltageSample[2].PreviousFiltered +
config.Phase_Calibration[2] * (VoltageSample[2].Filtered -
VoltageSample[2].PreviousFiltered);
}
#endif
#ifdef I2
if (IndexAtual == I2){ //First CT
//A) Store Last Values for future use
CurrentSample[2].Previous = CurrentSample[2].New; //Put
last sample on its place
CurrentSample[2].PreviousFiltered = CurrentSample[2].Filtered;
//Put last sample on its place
// Read in raw voltage and current samples
CurrentSample[2].New=ADC; //Read in raw voltage signal
from index sample
// Apply digital high pass filters to remove 2.5V DC offset
(centered on 0V).
if (AdcIndex == 0) SampleCounter++;
SampleCounter = 0;
Cycle_Full = true;
}
/*
void process_rf(){
switch (command){
switch (rf12_data[1]){
case 0x01: //radio band
txbuffer[2] = config.band;
break;
case 0x02: // radio group
txbuffer[2] = config.group;
break;
case 0x03: // radio nodeID
txbuffer[2] = config.nodeID;
break;
case 0x04: // radio nodeID
txbuffer[2] = config.sendTo;
break;
txbuffer[1] = 3;
//send the ack with the data
rf12_sendStart(RF12_ACK_REPLY, &txbuffer, 6);
break;
break;
case 0x12: // Phase Calibration \u2013 Phase 2
config.Phase_Calibration[1] = *( (float*)(rf12_data +3) );
break;
case 0x13: // Phase Calibration \u2013 Phase 3
config.Phase_Calibration[2] = *( (float*)(rf12_data +3) );
break;
void loop()
{
initLcd3Phases();
}
//Print LCD
printLCD();
}
}
Cycle_Full = false;
//Calculation of the root of the mean of the voltage and current squared
(rms)
//Calibration coeficients applied.
#if VOLTAGE_SENSORS > 0
Vrms[0] = config.Voltage_Calibration[0] * sqrt(LastVoltage[0].Sum /
LastSampleCounter);
#ifdef ADC_BUFFER
#if PHASE_SENSORS > 1
Vrms[1] = Vrms[0];
#if PHASE_SENSORS > 2
Vrms[2] = Vrms[0];
#endif
#endif
#else
#if VOLTAGE_SENSORS > 1
Vrms[1] = config.Voltage_Calibration[1] * sqrt(LastVoltage[1].Sum /
LastSampleCounter);
#if VOLTAGE_SENSORS > 2
Vrms[2] = config.Voltage_Calibration[2] * sqrt(LastVoltage[2].Sum /
LastSampleCounter);
#endif
#endif
#endif
#else
Vrms[0] = config.Voltage;
Vrms[1] = config.Voltage;
Vrms[2] = config.Voltage;
#endif
//transmit
if (tcount > config.transmitinterval) {
tcount = 1;
counts++;
emontx.command = 0x20;
emontx.nodeId = config.nodeID;
emontx.txCount = counts;
emontx.totalP = AccRealPower[0]
#if PHASE_SENSORS > 1
+ AccRealPower[1]
#if PHASE_SENSORS > 2
+ AccRealPower[2]
#endif
#endif
;
//calculate kw increment
float whInc = emontx.totalP *((CALC_INTERVAL *
config.transmitinterval)/3600.0);
emontx.cummKw += whInc / 1000;
emontx.V1 = AccVrms[0];
#if (PHASE_SENSORS > 0)
#ifdef SERIAL
Serial.print("Total = ");
Serial.print(emontx.totalP);
Serial.println(" W ");
Serial.print("KwIncrement = ");
Serial.print(emontx.cummKw);
Serial.println(" Kw ");
Serial.print("L1 : ");
Serial.print(emontx.V1);
Serial.print(" V - ");
Serial.print(emontx.Irms1);
Serial.print(" A - ");
Serial.print(emontx.RP1);
Serial.print(" W - ");
Serial.println(emontx.PF_1);
Serial.print("L2 : ");
Serial.print(emontx.V2);
Serial.print(" V - ");
Serial.print(emontx.Irms2);
Serial.print(" A - ");
Serial.print(emontx.RP2);
Serial.print("L3 : ");
Serial.print(emontx.V3);
Serial.print(" V - ");
Serial.print(emontx.Irms3);
Serial.print(" A - ");
Serial.print(emontx.RP3);
Serial.print(" W - ");
Serial.println(emontx.PF_3);
#endif
//Print LCD
printLCD();
//transmit Ethernet
#ifdef SERIAL
Serial.println("\n>>> REQ");
#endif
//build URL with values
String param = "input/post?json={voltage:";
param += floatToString(bufferString, emontx.V1, 2);
param += ",power1:";
param += floatToString(bufferString, emontx.RP1, 2);
param += ",power2:";
param += floatToString(bufferString, emontx.RP2, 2);
param += ",power3:";
param += floatToString(bufferString, emontx.RP3, 2);
param += ",powerSum:";
param += floatToString(bufferString, emontx.totalP, 2);
param += ",current1:";
param += floatToString(bufferString, emontx.Irms1, 2);
param += ",current2:";
param += floatToString(bufferString, emontx.Irms2, 2);
param += ",current3:";
param += floatToString(bufferString, emontx.Irms3, 2);
param += "}&apikey=b4b22e89c0f72a426ae948e97497709c";
param.toCharArray(cParam, 255);
#ifdef SERIAL
Serial.println(cParam);
#endif
//erase data
#if VOLTAGE_SENSORS > 0
AccVrms[0] = 0 ;
#if VOLTAGE_SENSORS > 1
AccVrms[1] = 0 ;
#if VOLTAGE_SENSORS > 2
AccVrms[2] = 0 ;
#endif
#endif
#else
AccVrms[0] = 0;
AccVrms[1] = 0;
AccVrms[2] = 0;
#endif
void printLCD(){
lcd.setCursor(0, 0);
lcd.print("L1 ");
lcd.print(floatToString(bufferString, irms1, 2, 5,true));
lcd.print("A ");
lbg1.drawValue(int(irms1 * 100), MAX_AMPS_PER_PHASE * 100);
lcd.setCursor(0, 1);
lcd.print("L2 ");
lcd.print(floatToString(bufferString, irms2, 2, 5,true));
lcd.print("A ");
lbg2.drawValue(int(irms2 * 100), MAX_AMPS_PER_PHASE * 100);
lcd.setCursor(0, 2);
lcd.print("L3 ");
lcd.print(floatToString(bufferString, irms3, 2, 5,true));
lcd.print("A ");
lbg3.drawValue(int(irms3 * 100), MAX_AMPS_PER_PHASE * 100);
lcd.setCursor(3, 0);
lcd.print(floatToString(bufferString, power1, 0, 6,true));
lcd.print("W ");
lbg1.drawValue(int(power1), MAX_WATTS_PER_PHASE);
lcd.setCursor(3, 1);
lcd.print(floatToString(bufferString, power2, 0, 6,true));
lcd.print("W ");
lbg2.drawValue(int(power2), MAX_WATTS_PER_PHASE);
lcd.setCursor(3, 2);
lcd.print(floatToString(bufferString, power3, 0, 6,true));
lcd.print("W ");
lbg3.drawValue(int(power3), MAX_WATTS_PER_PHASE);
lcd.setCursor(2, 3);
lcd.print(floatToString(bufferString, powersSum, 0, 7,true));
lcd.print("W ");
lcd.print(floatToString(bufferString, voltage, 1, 5,true));
lcd.print("V ");
lcd.setCursor(3, 0);
lcd.print(floatToString(bufferString, power1, 0, 5,true));
lcd.print("W ");
lcd.print(floatToString(bufferString, irms1, 1, 4,true));
lcd.print("A ");
lcd.print(floatToString(bufferString, cosPhi1, 1, 4,true));
lcd.printByte(242);
lcd.setCursor(3, 1);
lcd.print(floatToString(bufferString, power2, 0, 5,true));
lcd.print("W ");
lcd.print(floatToString(bufferString, irms2, 1, 4,true));
lcd.print("A ");
lcd.print(floatToString(bufferString, cosPhi2, 1, 4,true));
lcd.setCursor(3, 2);
lcd.print(floatToString(bufferString, power3, 0, 5,true));
lcd.print("W ");
lcd.print(floatToString(bufferString, irms3, 1, 4,true));
lcd.print("A ");
lcd.print(floatToString(bufferString, cosPhi3, 1, 4,true));
lcd.printByte(242);
void initLcd3Phases(){
lcd.clear();
void initLcdPowerAndAmps(){
lcd.clear();
lcd.setCursor(0, 0);
void initEmptyBargraph(){
for(int i=0; i<10;i++){
lcd.printByte(5);
}
}
char * floatToString(char * outstr, float value, int places, int minwidth, bool
rightjustify) {
// this is used to write a float value to string, outstr. oustr is also the return
value.
int digit;
float tens = 0.1;
int tenscount = 0;
int i;
float tempfloat = value;
int c = 0;
int charcount = 1;
int extra = 0;
// make sure we round properly. this could use pow from <math.h>, but
doesn't seem worth the import
// if this rounding step isn't here, the value 54.321 prints as 54.3209
// first get value tens to be the large power of ten less than value
if (value < 0)
tempfloat *= -1.0;
while ((tens * 10.0) <= tempfloat) {
tens *= 10.0;
if (tenscount > 0)
charcount += tenscount;
else
charcount += 1;
if (value < 0)
charcount += 1;
charcount += 1 + places;
if (tenscount == 0)
outstr[c++] = '0';
outstr[c++] = '\0';
return outstr;
}