00001
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <errno.h>
00025 #include <math.h>
00026
00027 #include "meter.h"
00028 #include "timestamp.h"
00029
00030
00031 #define SYNCS (PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN)
00032
00033
00034 #define TO_HOURS(t) (((double)t) / (3600 * TS_SECOND))
00035
00037
00039
00040 CLASS* meter::oclass = NULL;
00041 CLASS* meter::pclass = NULL;
00042 meter *meter::defaults = NULL;
00043
00044
00045 meter::meter(MODULE *mod) : node(mod)
00046 {
00047
00048 if (oclass==NULL)
00049 {
00050
00051 pclass = node::oclass;
00052
00053
00054 oclass = gl_register_class(mod,"meter",SYNCS);
00055 if (oclass==NULL)
00056 GL_THROW("unable to register object class implemented by %s",__FILE__);
00057
00058
00059 if (gl_publish_variable(oclass,
00060 PT_enumeration,"type",PADDR(type),
00061 PT_KEYWORD,"UNKNOWN",UNKNOWN,
00062 PT_KEYWORD,"SINGLEPHASE",SINGLEPHASE,
00063 PT_KEYWORD,"POLYPHASE",POLYPHASE,
00064 PT_double, "energy[kWh]", PADDR(energy),
00065 PT_double, "power[kW]", PADDR(power),
00066 PT_double, "demand[kW]", PADDR(demand),
00067 PT_complex, "line12_voltage[V]", PADDR(phaseAtoB_V),
00068 PT_complex, "line23_voltage[V]", PADDR(phaseBtoC_V),
00069 PT_complex, "line31_voltage[V]", PADDR(phaseCtoA_V),
00070 PT_complex, "line1_voltage[V]", PADDR(phaseA_V),
00071 PT_complex, "line2_voltage[V]", PADDR(phaseB_V),
00072 PT_complex, "line3_voltage[V]", PADDR(phaseC_V),
00073 PT_complex, "line1_current[A]", PADDR(phaseA_I),
00074 PT_complex, "line2_current[A]", PADDR(phaseB_I),
00075 PT_complex, "line3_current[A]", PADDR(phaseC_I),
00076 PT_set, "phases", PADDR(phases),
00077 PT_KEYWORD, "A",PHASE_A,
00078 PT_KEYWORD, "B",PHASE_B,
00079 PT_KEYWORD, "C",PHASE_C,
00080 PT_KEYWORD, "N",PHASE_N,
00081 PT_KEYWORD, "S",PHASE_S,
00082 PT_enumeration, "status", PADDR(status),
00083 PT_KEYWORD, "NOMINAL", NOMINAL,
00084 PT_KEYWORD, "UNDERVOLT", UNDERVOLT,
00085 PT_KEYWORD, "OVERVOLT", OVERVOLT,
00086 PT_double, "nominal_voltage[V]", PADDR(nominal_voltage),
00087 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00088
00089
00090 memset(this,0,sizeof(meter));
00091 defaults = this;
00092 nominal_voltage = 240;
00093 }
00094 }
00095
00096 int meter::isa(char *classname)
00097 {
00098 return strcmp(classname,"meter")==0 || node::isa(classname);
00099 }
00100
00101
00102 int meter::create()
00103 {
00104 int result = node::create();
00105 memcpy(this,defaults,sizeof(meter));
00106 return result;
00107 }
00108
00109
00110 int meter::init(OBJECT *parent)
00111 {
00112 if (type==UNKNOWN)
00113 {
00114 OBJECT *obj = OBJECTHDR(this);
00115 throw("meter type is not specified");
00116 }
00117 return node::init(parent);
00118 }
00119
00120
00121 TIMESTAMP meter::presync(TIMESTAMP t0, TIMESTAMP t1)
00122 {
00123
00124 if (power>demand) demand=power;
00125 if (t0>0)
00126 energy += power * TO_HOURS(t1 - t0);
00127 if (type==SINGLEPHASE)
00128 {
00129 phaseAtoB_V = phaseA_V - (-phaseB_V);
00130 phaseBtoC_V = -phaseB_V - (phaseC_V);
00131 phaseCtoA_V = phaseC_V - (phaseA_V);
00132
00133 }
00134
00135 return node::presync(t0);
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 }
00160
00161 TIMESTAMP meter::sync(TIMESTAMP t0)
00162 {
00163 complex true_power;
00164
00165 phaseA_I_in += phaseA_I;
00166 phaseB_I_in += phaseB_I;
00167 phaseC_I_in += phaseC_I;
00168
00169
00170 TIMESTAMP t1 = node::sync(t0);
00171
00172
00173 double VApu = phaseA_V.Mag()/nominal_voltage;
00174 double VBpu = phaseB_V.Mag()/nominal_voltage;
00175 double VCpu = phaseC_V.Mag()/nominal_voltage;
00176 if (type==SINGLEPHASE)
00177 {
00178
00179 phaseAtoB_V = phaseA_V - (-phaseB_V);
00180 phaseBtoC_V = -phaseB_V - (phaseC_V);
00181 phaseCtoA_V = phaseC_V - (phaseA_V);
00182
00183 if (VApu<0.4 || VBpu<0.4 || VApu+VBpu<0.8)
00184 status=UNDERVOLT;
00185 else if (VApu>0.6 || VBpu>0.6 || VApu+VBpu>1.2)
00186 status=OVERVOLT;
00187 else
00188 status=NOMINAL;
00189
00190 }
00191 else if (type==POLYPHASE)
00192 {
00193
00194
00195
00196
00197
00198
00199 if (VApu<0.8 || VBpu<0.8 || VCpu<0.8)
00200 status=UNDERVOLT;
00201 else if (VApu>1.2 || VBpu>1.2 || VCpu>1.2)
00202 status=OVERVOLT;
00203 else
00204 status=NOMINAL;
00205
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 return t1;
00222 }
00223
00224 TIMESTAMP meter::postsync(TIMESTAMP t0)
00225 {
00226
00227
00228
00229
00230
00231 complex true_power;
00232
00233
00234
00235 if (type==1){
00236 true_power = phaseA_V * phaseA_I_in -phaseB_V * phaseB_I_in +phaseC_V * phaseC_I_in;
00237 power = true_power.Re()/1000;
00238 if (type=SINGLEPHASE)
00239 {
00240 phaseAtoB_V = phaseA_V - (-phaseB_V);
00241 phaseBtoC_V = -phaseB_V - (phaseC_V);
00242 phaseCtoA_V = phaseC_V - (phaseA_V);
00243 }
00244 }
00245 else if (type==2){
00246 true_power = phaseA_V * phaseA_I_in +phaseB_V * phaseB_I_in +phaseC_V * phaseC_I_in;
00247 power = true_power.Mag()/1000;
00248 }
00249 else{
00250
00251 true_power = 0.0;
00252 power = true_power.Mag()/1000;
00253 }
00254
00255 return TS_NEVER;
00256 }
00257
00259
00261
00262 EXPORT int isa_meter(OBJECT *obj, char *classname)
00263 {
00264 return OBJECTDATA(obj,meter)->isa(classname);
00265 }
00266
00267 EXPORT int create_meter(OBJECT **obj, OBJECT *parent)
00268 {
00269 *obj = gl_create_object(meter::oclass,sizeof(meter));
00270 if (*obj!=NULL)
00271 {
00272 meter *my = OBJECTDATA(*obj,meter);
00273 gl_set_parent(*obj,parent);
00274 my->create();
00275 return 1;
00276 }
00277 return 0;
00278 }
00279
00280 EXPORT int init_meter(OBJECT *obj)
00281 {
00282 meter *my = OBJECTDATA(obj,meter);
00283 try {
00284 return my->init(obj->parent);
00285 }
00286 catch (char *msg)
00287 {
00288 GL_THROW("%s (meter:%d): %s", my->get_name(), my->get_id(), msg);
00289 return 0;
00290 }
00291 }
00292
00293 EXPORT TIMESTAMP sync_meter(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00294 {
00295 meter *pObj = OBJECTDATA(obj,meter);
00296 try {
00297 TIMESTAMP t1 = TS_NEVER;
00298 if (pass==PC_PRETOPDOWN)
00299 {
00300 t1 = pObj->presync(obj->clock,t0);
00301 obj->clock = t0;
00302 return t1;
00303 }
00304 else if (pass==PC_BOTTOMUP)
00305 return pObj->sync(t0);
00306 else if (pass=PC_POSTTOPDOWN)
00307 return pObj->postsync(t0);
00308 else
00309 throw "invalid pass request";
00310 } catch (const char *error) {
00311 GL_THROW("%s (meter:%d): %s", pObj->get_name(), pObj->get_id(), error);
00312 return 0;
00313 } catch (...) {
00314 GL_THROW("%s (meter:%d): %s", pObj->get_name(), pObj->get_id(), "unknown exception");
00315 return 0;
00316 }
00317 }
00318