00001
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007 #include <errno.h>
00008 #include <math.h>
00009 #include "evcharger_det.h"
00010
00012
00014 CLASS* evcharger_det::oclass = NULL;
00015 CLASS* evcharger_det::pclass = NULL;
00016
00017 evcharger_det::evcharger_det(MODULE *module) : residential_enduse(module)
00018 {
00019
00020 if (oclass==NULL)
00021 {
00022
00023 oclass = gl_register_class(module,"evcharger_det",sizeof(evcharger_det),PC_BOTTOMUP);
00024 if (oclass==NULL)
00025 throw "unable to register class evcharger_det";
00026
00027
00028 if (gl_publish_variable(oclass,
00029 PT_INHERIT, "residential_enduse",
00030 PT_double,"charge_rate[W]", PADDR(ChargeRate),PT_DESCRIPTION, "Current demanded charge rate of the vehicle",
00031
00032 PT_double,"variation_mean[s]", PADDR(variation_mean),PT_DESCRIPTION, "Mean of normal variation of schedule variation",
00033 PT_double,"variation_std_dev[s]", PADDR(variation_std_dev),PT_DESCRIPTION, "Standard deviation of normal variation of schedule times",
00034
00035 PT_double,"variation_trip_mean[mile]", PADDR(variation_trip_mean),PT_DESCRIPTION, "Mean of normal variation of trip distance variation",
00036 PT_double,"variation_trip_std_dev[mile]", PADDR(variation_trip_std_dev),PT_DESCRIPTION, "Standard deviation of normal variation of trip distance",
00037
00038 PT_double,"mileage_classification[mile]", PADDR(mileage_classification),PT_DESCRIPTION, "Mileage classification of electric vehicle",
00039 PT_bool,"work_charging_available", PADDR(Work_Charge_Available), PT_DESCRIPTION, "Charging available when at work",
00040
00041 PT_char1024,"data_file", PADDR(NHTSDataFile), PT_DESCRIPTION, "Path to .CSV file with vehicle travel information",
00042 PT_int32,"vehicle_index", PADDR(VehicleLocation), PT_DESCRIPTION, "Index of vehicles in file this particular vehicle's data",
00043
00044 PT_enumeration,"vehicle_location", PADDR(CarInformation.Location),
00045 PT_KEYWORD,"UNKNOWN",(enumeration)VL_UNKNOWN,
00046 PT_KEYWORD,"HOME",(enumeration)VL_HOME,
00047 PT_KEYWORD,"WORK",(enumeration)VL_WORK,
00048 PT_KEYWORD,"DRIVING_HOME",(enumeration)VL_WORK_TO_HOME,
00049 PT_KEYWORD,"DRIVING_WORK",(enumeration)VL_HOME_TO_WORK,
00050 PT_double,"travel_distance[mile]",PADDR(CarInformation.travel_distance), PT_DESCRIPTION, "Distance vehicle travels from home to home",
00051 PT_double,"arrival_at_work",PADDR(CarInformation.WorkArrive), PT_DESCRIPTION, "Time vehicle arrives at work - HHMM",
00052 PT_double,"duration_at_work[s]",PADDR(CarInformation.WorkDuration), PT_DESCRIPTION, "Duration the vehicle remains at work",
00053 PT_double,"arrival_at_home",PADDR(CarInformation.HomeArrive), PT_DESCRIPTION, "Time vehicle arrives at home - HHMM",
00054 PT_double,"duration_at_home[s]",PADDR(CarInformation.HomeDuration), PT_DESCRIPTION, "Duration the vehicle remains at home",
00055 PT_double,"battery_capacity[kWh]",PADDR(CarInformation.battery_capacity), PT_DESCRIPTION, "Current capacity of the battery in kWh",
00056 PT_double,"battery_SOC[%]",PADDR(CarInformation.battery_SOC), PT_DESCRIPTION, "State of charge of battery",
00057 PT_double,"battery_size[kWh]",PADDR(CarInformation.battery_size), PT_DESCRIPTION, "Full capacity of battery",
00058 PT_double,"mileage_efficiency[mile/kWh]",PADDR(CarInformation.mileage_efficiency), PT_DESCRIPTION, "Efficiency of drive train in mile/kWh",
00059 PT_double,"maximum_charge_rate[W]",PADDR(CarInformation.MaxChargeRate), PT_DESCRIPTION, "Maximum output rate of charger in kW",
00060 PT_double,"charging_efficiency[unit]",PADDR(CarInformation.ChargeEfficiency), PT_DESCRIPTION, "Efficiency of charger (ratio) when charging",
00061 NULL)<1)
00062 GL_THROW("unable to publish properties in %s",__FILE__);
00063 }
00064 }
00065
00066 int evcharger_det::create()
00067 {
00068 int create_res = residential_enduse::create();
00069
00070 ChargeRate = 0.0;
00071 load.power_factor = 0.99;
00072 load.heatgain_fraction = 0.0;
00073
00074 variation_mean = 0.0;
00075 variation_std_dev = 0.0;
00076
00077 variation_trip_mean = 0.0;
00078 variation_trip_std_dev = 0.0;
00079
00080 mileage_classification = 33;
00081
00082 Work_Charge_Available = false;
00083
00084 NHTSDataFile[0] = '\0';
00085 VehicleLocation = 0;
00086
00087
00088 CarInformation.battery_capacity = -1.0;
00089 CarInformation.battery_size = -1.0;
00090 CarInformation.battery_SOC = -1.0;
00091 CarInformation.ChargeEfficiency = 0.90;
00092 CarInformation.HomeArrive = 1700.0;
00093 CarInformation.HomeDuration = 41400.0;
00094 CarInformation.HomeWorkDuration = 1800.0;
00095 CarInformation.Location = VL_HOME;
00096 CarInformation.MaxChargeRate = 1700.0;
00097 CarInformation.mileage_efficiency = 3.846;
00098 CarInformation.next_state_change = 0;
00099 CarInformation.travel_distance = 15.0;
00100 CarInformation.WorkArrive = 500.0;
00101 CarInformation.WorkDuration = 41400.0;
00102 CarInformation.WorkHomeDuration = 1800.0;
00103
00104 prev_time = 0;
00105
00106 off_nominal_time = false;
00107
00108 return create_res;
00109 }
00110
00111 int evcharger_det::init(OBJECT *parent)
00112 {
00113 if(parent != NULL){
00114 if((parent->flags & OF_INIT) != OF_INIT){
00115 char objname[256];
00116 gl_verbose("evcharger_det::init(): deferring initialization on %s", gl_name(parent, objname, 255));
00117 return 2;
00118 }
00119 }
00120 OBJECT *hdr = OBJECTHDR(this);
00121 int TempIdx;
00122 int init_res;
00123 int comma_count, curr_idx, curr_comma_count;
00124 char temp_char;
00125 char temp_char_value[33];
00126 char temp_buff[128];
00127 char *curr_ptr, *end_ptr;
00128 double home_arrive, home_durr, temp_miles, work_arrive, work_durr, glob_min_timestep_dbl, temp_val;
00129 double temp_hours_curr, temp_hours_curr_two, temp_hours_A, temp_hours_B, temp_hours_C, temp_hours_D;
00130 double temp_sec_curr, temp_sec_curr_two, temp_sec_A, temp_sec_B, temp_sec_C, temp_sec_D;
00131 double temp_amps;
00132 FILE *FPTemp;
00133 TIMESTAMP temp_time;
00134 DATETIME temp_date;
00135
00136
00137
00138 gl_global_getvar("minimum_timestep",temp_buff,sizeof(temp_buff));
00139
00140
00141 TempIdx = 0;
00142 glob_min_timestep_dbl = 0.0;
00143
00144
00145 while ((TempIdx < 128) && (temp_buff[TempIdx] != '\0'))
00146 {
00147 glob_min_timestep_dbl *= 10;
00148 temp_val = (double)(temp_buff[TempIdx]-48);
00149 glob_min_timestep_dbl += temp_val;
00150
00151 TempIdx++;
00152 }
00153
00154
00155 glob_min_timestep = (TIMESTAMP)glob_min_timestep_dbl;
00156
00157 if (glob_min_timestep > 1)
00158 {
00159 off_nominal_time=true;
00160 gl_verbose("evcharger_det:%s - minimum_timestep set - problems may emerge",hdr->name);
00161
00162
00163
00164
00165
00166 }
00167
00168
00169
00170 if (CarInformation.MaxChargeRate > 1700)
00171 {
00172 if (load.config != EUC_IS220)
00173 {
00174 gl_warning("evcharger_det:%s - The max charge rate is over 1.7 kW (Level 1), but the load is still 110-V connected.",hdr->name ? hdr->name : "unnamed");
00175
00176
00177
00178
00179 }
00180 }
00181
00182
00183
00184 if (load.config == EUC_IS220)
00185 {
00186 temp_amps = floor(((CarInformation.MaxChargeRate * 1.1) / (2.0 * default_line_voltage)) + 0.5);
00187 }
00188 else
00189 {
00190 temp_amps = floor(((CarInformation.MaxChargeRate * 1.1) / default_line_voltage) + 0.5);
00191 }
00192
00193
00194 if (temp_amps > load.breaker_amps)
00195 {
00196 gl_warning("evcharger_det:%s - the breaker rating may be too low for this maximum charge rate.",hdr->name ? hdr->name : "unnamed");
00197
00198
00199
00200
00201 }
00202
00203
00204 init_res = residential_enduse::init(parent);
00205
00206
00207 temp_char_value[32] = '\0';
00208
00209
00210 if (NHTSDataFile[0] != '\0')
00211 {
00212
00213 if (VehicleLocation==0)
00214 {
00215 gl_warning("Vehicle location not set, using defaults");
00216
00217
00218
00219
00220 }
00221 else
00222 {
00223
00224 FPTemp = fopen(NHTSDataFile,"rt");
00225
00226
00227 if (FPTemp == NULL)
00228 {
00229 gl_warning("NHTS data file not found, using defaults");
00230
00231
00232
00233
00234 }
00235 else
00236 {
00237
00238 comma_count = (int)(VehicleLocation)*9;
00239
00240
00241 curr_idx = 0;
00242 curr_comma_count = 0;
00243
00244
00245 temp_char = fgetc(FPTemp);
00246
00247 while ((temp_char > 0) && (curr_comma_count < comma_count))
00248 {
00249
00250 if (temp_char == ',')
00251 curr_comma_count++;
00252
00253
00254 temp_char = fgetc(FPTemp);
00255 }
00256
00257
00258 while ((temp_char > 0) && (temp_char != '\n'))
00259 {
00260
00261 temp_char = fgetc(FPTemp);
00262 }
00263
00264
00265 if (temp_char == '\n')
00266 {
00267 curr_comma_count = 0;
00268
00269
00270 temp_char = fgetc(FPTemp);
00271
00272
00273 while (temp_char > 0)
00274 {
00275
00276 if (temp_char==',')
00277 {
00278
00279 curr_comma_count++;
00280
00281
00282 if (curr_comma_count>=3)
00283 {
00284
00285 break;
00286 }
00287 }
00288
00289
00290 temp_char = getc(FPTemp);
00291 }
00292
00293
00294 if (curr_comma_count == 3)
00295 {
00296
00297 temp_char = fgetc(FPTemp);
00298
00299
00300 while ((temp_char > 0) && (curr_idx < 32))
00301 {
00302 if (temp_char == ',')
00303 {
00304
00305 break;
00306 }
00307 else
00308 {
00309
00310 temp_char_value[curr_idx] = temp_char;
00311
00312
00313 curr_idx++;
00314
00315
00316 if (curr_idx>31)
00317 {
00318 GL_THROW("NHTS entry exceeded 32 characters");
00319
00320
00321
00322
00323 }
00324 }
00325
00326
00327 temp_char = fgetc(FPTemp);
00328 }
00329
00330
00331 temp_char_value[curr_idx]='\0';
00332
00333
00334 curr_ptr = temp_char_value;
00335
00336
00337 home_arrive = strtod(curr_ptr,&end_ptr);
00338
00339
00340 curr_idx = 0;
00341
00342
00343 temp_char = fgetc(FPTemp);
00344
00345
00346 while ((temp_char > 0) && (curr_idx < 32))
00347 {
00348 if (temp_char == ',')
00349 {
00350
00351 break;
00352 }
00353 else
00354 {
00355
00356 temp_char_value[curr_idx] = temp_char;
00357
00358
00359 curr_idx++;
00360
00361
00362 if (curr_idx>31)
00363 {
00364 GL_THROW("NHTS entry exceeded 32 characters");
00365
00366 }
00367 }
00368
00369
00370 temp_char = fgetc(FPTemp);
00371 }
00372
00373
00374 temp_char_value[curr_idx]='\0';
00375
00376
00377 curr_ptr = temp_char_value;
00378
00379
00380 home_durr = strtod(curr_ptr,&end_ptr);
00381
00382
00383 temp_char = fgetc(FPTemp);
00384
00385
00386 while (temp_char > 0)
00387 {
00388 if (temp_char == ',')
00389 {
00390
00391 break;
00392 }
00393
00394
00395 temp_char = fgetc(FPTemp);
00396 }
00397
00398
00399
00400 curr_idx = 0;
00401
00402
00403 temp_char = fgetc(FPTemp);
00404
00405
00406 while ((temp_char > 0) && (curr_idx < 32))
00407 {
00408 if (temp_char == ',')
00409 {
00410
00411 break;
00412 }
00413 else
00414 {
00415
00416 temp_char_value[curr_idx] = temp_char;
00417
00418
00419 curr_idx++;
00420
00421
00422 if (curr_idx>31)
00423 {
00424 GL_THROW("NHTS entry exceeded 32 characters");
00425
00426 }
00427 }
00428
00429
00430 temp_char = fgetc(FPTemp);
00431 }
00432
00433
00434 temp_char_value[curr_idx]='\0';
00435
00436
00437 curr_ptr = temp_char_value;
00438
00439
00440 temp_miles = strtod(curr_ptr,&end_ptr);
00441
00442
00443 curr_idx = 0;
00444
00445
00446 temp_char = fgetc(FPTemp);
00447
00448
00449 while ((temp_char > 0) && (curr_idx < 32))
00450 {
00451 if (temp_char == ',')
00452 {
00453
00454 break;
00455 }
00456 else
00457 {
00458
00459 temp_char_value[curr_idx] = temp_char;
00460
00461
00462 curr_idx++;
00463
00464
00465 if (curr_idx>31)
00466 {
00467 GL_THROW("NHTS entry exceeded 32 characters");
00468
00469 }
00470 }
00471
00472
00473 temp_char = fgetc(FPTemp);
00474 }
00475
00476
00477 temp_char_value[curr_idx]='\0';
00478
00479
00480 curr_ptr = temp_char_value;
00481
00482
00483 work_arrive = strtod(curr_ptr,&end_ptr);
00484
00485
00486 curr_idx = 0;
00487
00488
00489 temp_char = fgetc(FPTemp);
00490
00491
00492 while ((temp_char > 0) && (curr_idx < 32))
00493 {
00494 if (temp_char == ',')
00495 {
00496
00497 break;
00498 }
00499 else
00500 {
00501
00502 temp_char_value[curr_idx] = temp_char;
00503
00504
00505 curr_idx++;
00506
00507
00508 if (curr_idx>31)
00509 {
00510 GL_THROW("NHTS entry exceeded 32 characters");
00511
00512 }
00513 }
00514
00515
00516 temp_char = fgetc(FPTemp);
00517 }
00518
00519
00520 temp_char_value[curr_idx]='\0';
00521
00522
00523 curr_ptr = temp_char_value;
00524
00525
00526 work_durr = strtod(curr_ptr,&end_ptr);
00527
00528
00529 CarInformation.HomeArrive = home_arrive;
00530 CarInformation.HomeDuration = home_durr * 60.0;
00531 CarInformation.WorkArrive = work_arrive;
00532 CarInformation.WorkDuration = work_durr * 60.0;
00533 CarInformation.travel_distance = temp_miles;
00534 }
00535 else
00536 {
00537 GL_THROW("Invalid entry in NHTS file - may have exceeded file length!");
00538
00539
00540
00541
00542
00543 }
00544 }
00545 else
00546 {
00547
00548 fclose(FPTemp);
00549
00550 GL_THROW("Invalid entry in NHTS file - may have exceeded file length!");
00551
00552 }
00553
00554
00555 fclose(FPTemp);
00556 }
00557 }
00558 }
00559 else
00560 {
00561 gl_warning("NHTS data file not found, using defaults");
00562
00563 }
00564
00565
00566 prev_time = gl_globalclock;
00567
00568
00569 temp_time = gl_globalclock;
00570
00571
00572 gl_localtime(temp_time,&temp_date);
00573
00574
00575
00576
00577 temp_hours_curr = floor(CarInformation.HomeArrive / 100);
00578
00579 temp_hours_curr_two = (CarInformation.HomeArrive - temp_hours_curr*100) / 60.0;
00580 temp_hours_A = temp_hours_curr + temp_hours_curr_two;
00581 temp_hours_B = temp_hours_A + CarInformation.HomeDuration/3600.0;
00582
00583 temp_sec_curr = temp_hours_curr * 3600.0;
00584 temp_sec_curr_two = (CarInformation.HomeArrive - temp_hours_curr*100) * 60.0;
00585 temp_sec_A = temp_sec_curr + temp_sec_curr_two;
00586 temp_sec_B = temp_sec_A + CarInformation.HomeDuration;
00587
00588 if (temp_hours_B > 24.0)
00589 temp_hours_B -= 24.0;
00590
00591 if(temp_sec_B > 86400.0){
00592 temp_sec_B -= 86400.0;
00593 }
00594
00595
00596 temp_hours_curr = floor(CarInformation.WorkArrive/100);
00597
00598 temp_hours_curr_two = (CarInformation.WorkArrive - temp_hours_curr*100) / 60.0;
00599 temp_hours_C = temp_hours_curr + temp_hours_curr_two;
00600 temp_hours_D = temp_hours_C + CarInformation.WorkDuration/3600.0;
00601
00602 temp_sec_curr = temp_hours_curr * 3600.0;
00603 temp_sec_curr_two = (CarInformation.WorkArrive - temp_hours_curr*100) * 60.0;
00604 temp_sec_C = temp_sec_curr + temp_sec_curr_two;
00605 temp_sec_D = temp_sec_C + CarInformation.WorkDuration;
00606
00607 if (temp_hours_D > 24.0)
00608 temp_hours_D -= 24.0;
00609
00610 if(temp_sec_D > 86400.0){
00611 temp_sec_D -= 86400.0;
00612 }
00613
00614
00615
00616 if (temp_hours_D > temp_hours_A)
00617 {
00618 CarInformation.WorkHomeDuration = (86400.0 - temp_sec_D + temp_sec_A);
00619 }
00620 else
00621 {
00622 CarInformation.WorkHomeDuration = (temp_sec_A - temp_sec_D);
00623 }
00624
00625
00626 if (temp_hours_C < temp_hours_B)
00627 {
00628 CarInformation.HomeWorkDuration = (86400.0 - temp_sec_B + temp_sec_C);
00629 }
00630 else
00631 {
00632 CarInformation.HomeWorkDuration = (temp_sec_C - temp_sec_B);
00633 }
00634
00635
00636
00637 temp_hours_curr = ((double)(temp_date.hour)) + (((double)(temp_date.minute))/60.0) + (((double)(temp_date.second))/3600.0);
00638 temp_sec_curr = ((double)(temp_date.hour))*3600.0 + ((double)(temp_date.minute))*60.0 + ((double)(temp_date.second));
00639
00640
00641
00642 if (temp_sec_A < temp_sec_B)
00643 {
00644 if (temp_sec_C < temp_sec_D)
00645 {
00646 if (temp_sec_A < temp_sec_C)
00647 {
00648
00649 if ((temp_sec_curr < temp_sec_A) || (temp_sec_curr >= temp_sec_D))
00650 {
00651
00652 CarInformation.Location = VL_WORK_TO_HOME;
00653
00654
00655 if (temp_sec_curr < temp_sec_A)
00656 {
00657
00658 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_A - temp_sec_curr));
00659
00660 }
00661 else
00662 {
00663
00664 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_A + 86400.0 - temp_sec_curr));
00665
00666 }
00667 }
00668 else if ((temp_sec_curr >= temp_sec_A) && (temp_sec_curr < temp_sec_B))
00669 {
00670
00671 CarInformation.Location = VL_HOME;
00672
00673
00674
00675 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_B - temp_sec_curr));
00676
00677 }
00678 else if ((temp_sec_curr >= temp_sec_B) && (temp_sec_curr < temp_sec_C))
00679 {
00680
00681 CarInformation.Location = VL_HOME_TO_WORK;
00682
00683
00684
00685 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_C - temp_sec_curr));
00686
00687 }
00688 else
00689 {
00690
00691 CarInformation.Location = VL_WORK;
00692
00693
00694
00695 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_D - temp_sec_curr));
00696
00697 }
00698 }
00699 else
00700 {
00701
00702 if ((temp_sec_curr < temp_sec_C) || (temp_sec_curr >= temp_sec_B))
00703 {
00704
00705 CarInformation.Location = VL_HOME_TO_WORK;
00706
00707
00708 if (temp_sec_curr < temp_sec_C)
00709 {
00710
00711 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_C - temp_sec_curr));
00712
00713 }
00714 else
00715 {
00716
00717 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_C + 86400.0 - temp_sec_curr));
00718
00719 }
00720 }
00721 else if ((temp_sec_curr >= temp_sec_C) && (temp_sec_curr < temp_sec_D))
00722 {
00723
00724 CarInformation.Location = VL_WORK;
00725
00726
00727
00728 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_D - temp_sec_curr));
00729
00730 }
00731 else if ((temp_sec_curr >= temp_sec_D) && (temp_sec_curr < temp_sec_A))
00732 {
00733
00734 CarInformation.Location = VL_WORK_TO_HOME;
00735
00736
00737
00738 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_A - temp_sec_curr));
00739
00740 }
00741 else
00742 {
00743
00744 CarInformation.Location = VL_HOME;
00745
00746
00747
00748 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_B - temp_sec_curr));
00749
00750 }
00751 }
00752 }
00753 else
00754 {
00755
00756 if ((temp_sec_curr < temp_sec_D) || (temp_sec_curr >= temp_sec_C))
00757 {
00758
00759 CarInformation.Location = VL_WORK;
00760
00761
00762 if (temp_sec_curr < temp_sec_D)
00763 {
00764
00765 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_D - temp_sec_curr));
00766
00767 }
00768 else
00769 {
00770
00771 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_D + 86400.0 - temp_sec_curr));
00772
00773 }
00774 }
00775 else if ((temp_sec_curr >= temp_sec_D) && (temp_sec_curr < temp_sec_A))
00776 {
00777
00778 CarInformation.Location = VL_WORK_TO_HOME;
00779
00780
00781
00782 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_A - temp_sec_curr));
00783
00784 }
00785 else if ((temp_sec_curr >= temp_sec_A) && (temp_sec_curr < temp_sec_B))
00786 {
00787
00788 CarInformation.Location = VL_HOME;
00789
00790
00791
00792 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_B - temp_sec_curr));
00793
00794 }
00795 else
00796 {
00797
00798 CarInformation.Location = VL_HOME_TO_WORK;
00799
00800
00801
00802 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_C - temp_sec_curr));
00803
00804 }
00805 }
00806 }
00807 else
00808 {
00809
00810 if ((temp_sec_curr < temp_sec_B) || (temp_sec_curr >= temp_sec_A))
00811 {
00812
00813 CarInformation.Location = VL_HOME;
00814
00815
00816 if (temp_sec_curr < temp_sec_B)
00817 {
00818
00819 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_B - temp_sec_curr));
00820
00821 }
00822 else
00823 {
00824
00825 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_B + 86400.0 - temp_sec_curr));
00826
00827 }
00828 }
00829 else if ((temp_sec_curr >= temp_sec_B) && (temp_sec_curr < temp_sec_C))
00830 {
00831
00832 CarInformation.Location = VL_HOME_TO_WORK;
00833
00834
00835
00836 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_C - temp_sec_curr));
00837
00838 }
00839 else if ((temp_sec_curr >= temp_sec_C) && (temp_sec_curr < temp_sec_D))
00840 {
00841
00842 CarInformation.Location = VL_WORK;
00843
00844
00845
00846 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_D - temp_sec_curr));
00847
00848 }
00849 else
00850 {
00851
00852 CarInformation.Location = VL_WORK_TO_HOME;
00853
00854
00855
00856 CarInformation.next_state_change = temp_time + (TIMESTAMP)(floor(temp_sec_A - temp_sec_curr));
00857
00858 }
00859 }
00860
00861
00862 if (CarInformation.battery_size <= 0.0)
00863 {
00864 if ((mileage_classification != 0.0) && (CarInformation.mileage_efficiency != 0.0))
00865 {
00866 CarInformation.battery_size = mileage_classification / CarInformation.mileage_efficiency;
00867 }
00868 else
00869 {
00870 GL_THROW("Battery size is not specified, nor are the mileage classification or efficiency!");
00871
00872
00873
00874
00875 }
00876 }
00877 else
00878 {
00879
00880
00881 if (mileage_classification != 0.0)
00882 {
00883 CarInformation.mileage_efficiency = mileage_classification / CarInformation.battery_size;
00884 }
00885 else
00886 {
00887 if (CarInformation.mileage_efficiency != 0.0)
00888 {
00889 mileage_classification = CarInformation.battery_size * CarInformation.mileage_efficiency;
00890 }
00891 else
00892 {
00893 GL_THROW("Mileage efficiency not specified, more information needed!");
00894
00895
00896
00897
00898 }
00899 }
00900 }
00901
00902
00903 if ((CarInformation.battery_capacity < 0.0) && (CarInformation.battery_SOC >= 0.0))
00904 {
00905
00906 CarInformation.battery_capacity = CarInformation.battery_size * CarInformation.battery_SOC / 100.0;
00907 }
00908
00909
00910 if ((CarInformation.battery_SOC < 0.0) && (CarInformation.battery_capacity >= 0.0))
00911 {
00912
00913 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
00914 }
00915
00916
00917 if ((CarInformation.battery_SOC < 0.0) || (CarInformation.battery_capacity < 0.0))
00918 {
00919 if (CarInformation.Location == VL_HOME)
00920 {
00921
00922 CarInformation.battery_SOC = (1.0 - ((CarInformation.next_state_change - temp_time) / CarInformation.HomeDuration)) * 100.0;
00923
00924
00925 if ((CarInformation.battery_SOC > 100.0) || (CarInformation.battery_SOC < 0.0))
00926 {
00927
00928 CarInformation.battery_SOC = 50.0;
00929
00930 gl_warning("Battery SOC calculation messed up and somehow went outsize 0 - 100 range!");
00931
00932
00933
00934 }
00935
00936
00937 CarInformation.battery_capacity = CarInformation.battery_size * CarInformation.battery_SOC / 100.0;
00938 }
00939 else if ((CarInformation.Location == VL_HOME_TO_WORK) || (CarInformation.Location == VL_WORK))
00940 {
00941
00942 CarInformation.battery_capacity = CarInformation.battery_size - CarInformation.travel_distance / 2.0 / CarInformation.mileage_efficiency;
00943
00944
00945 if ((CarInformation.battery_capacity < 0.0) || (CarInformation.battery_capacity > CarInformation.battery_size))
00946 {
00947
00948 CarInformation.battery_capacity = CarInformation.battery_size / 2.0;
00949
00950 gl_warning("Battery attempted to discharge too far!");
00951
00952
00953
00954
00955 }
00956
00957
00958 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
00959 }
00960 else
00961 {
00962
00963 CarInformation.battery_capacity = CarInformation.battery_size - CarInformation.travel_distance / CarInformation.mileage_efficiency;
00964
00965
00966 if ((CarInformation.battery_capacity < 0.0) || (CarInformation.battery_capacity > CarInformation.battery_size))
00967 {
00968
00969 CarInformation.battery_capacity = 0.0;
00970
00971 gl_warning("Battery attempted to discharge too far!");
00972
00973
00974
00975
00976 }
00977
00978
00979 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
00980 }
00981 }
00982
00983
00984 if ((CarInformation.ChargeEfficiency<0) || (CarInformation.ChargeEfficiency > 1.0))
00985 {
00986 GL_THROW("Charger efficiency is outside of practical bounds!");
00987
00988
00989
00990
00991 }
00992
00993 return init_res;
00994 }
00995
00996 int evcharger_det::isa(char *classname)
00997 {
00998 return (strcmp(classname,"evcharger_det")==0 || residential_enduse::isa(classname));
00999 }
01000
01001 TIMESTAMP evcharger_det::sync(TIMESTAMP t0, TIMESTAMP t1)
01002 {
01003 OBJECT *obj = OBJECTHDR(this);
01004 double temp_double, charge_out_percent;
01005 complex temp_complex;
01006 TIMESTAMP t2, tret, tdiff;
01007
01008 temp_double = 0;
01009
01010
01011 if (prev_time != t1)
01012 {
01013
01014 tdiff = t1 - t0;
01015
01016
01017 load.power = 0.0;
01018 charge_out_percent = 0.0;
01019
01020
01021 switch (CarInformation.Location)
01022 {
01023 case VL_HOME:
01024
01025 if (t1 >= CarInformation.next_state_change)
01026 {
01027
01028 CarInformation.Location = VL_HOME_TO_WORK;
01029
01030
01031 tdiff = CarInformation.next_state_change - t0;
01032
01033
01034 temp_double = (double)(tdiff) / 3600.0 * ChargeRate / 1000.0 * CarInformation.ChargeEfficiency;
01035
01036
01037 CarInformation.battery_capacity += temp_double;
01038
01039
01040 if (CarInformation.battery_capacity < 0.0)
01041 {
01042 CarInformation.battery_capacity = 0.0;
01043 }
01044 else if (CarInformation.battery_capacity > CarInformation.battery_size)
01045 {
01046 CarInformation.battery_capacity = CarInformation.battery_size;
01047 }
01048
01049
01050 if ((variation_trip_std_dev > 0.0) || (variation_trip_mean != 0.0))
01051 {
01052
01053 temp_double = gl_random_normal(RNGSTATE,variation_trip_mean,variation_trip_std_dev);
01054
01055
01056 temp_double += CarInformation.travel_distance / 2.0;
01057
01058
01059 if (temp_double < 0)
01060 {
01061 temp_double = CarInformation.travel_distance / 2.0;
01062 }
01063
01064
01065 CarInformation.battery_capacity = CarInformation.battery_capacity - temp_double / CarInformation.mileage_efficiency;
01066 }
01067 else
01068 {
01069
01070 CarInformation.battery_capacity = CarInformation.battery_capacity - CarInformation.travel_distance / 2.0 / CarInformation.mileage_efficiency;
01071 }
01072
01073
01074 if (CarInformation.battery_capacity < 0.0)
01075 {
01076
01077 CarInformation.battery_capacity = 0.0;
01078 }
01079 else if (CarInformation.battery_capacity > CarInformation.battery_size)
01080 {
01081 CarInformation.battery_capacity = CarInformation.battery_size;
01082 }
01083
01084
01085 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
01086
01087
01088 if ((variation_std_dev > 0.0) || (variation_mean != 0.0))
01089 {
01090
01091 temp_double = gl_random_normal(RNGSTATE,variation_mean,variation_std_dev) + CarInformation.HomeWorkDuration;
01092
01093
01094 if (temp_double < 0)
01095 {
01096 temp_double = CarInformation.HomeWorkDuration;
01097 }
01098
01099
01100
01101 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(temp_double));
01102 }
01103 else
01104 {
01105
01106
01107 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(CarInformation.HomeWorkDuration));
01108
01109
01110 }
01111
01112
01113 ChargeRate = 0.0;
01114 }
01115 else
01116 {
01117
01118 CarInformation.Location = VL_HOME;
01119
01120
01121 temp_double = (double)(tdiff) / 3600.0 * ChargeRate / 1000.0 * CarInformation.ChargeEfficiency;
01122
01123
01124
01125
01126 CarInformation.battery_capacity += temp_double;
01127
01128
01129 if (CarInformation.battery_capacity < 0.0)
01130 {
01131 CarInformation.battery_capacity = 0.0;
01132 }
01133 else if (CarInformation.battery_capacity > CarInformation.battery_size)
01134 {
01135 CarInformation.battery_capacity = CarInformation.battery_size;
01136 }
01137
01138
01139 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
01140
01141
01142 if (CarInformation.battery_SOC < 100.0)
01143 {
01144 charge_out_percent = 100;
01145 }
01146 else
01147 {
01148 charge_out_percent = 0.0;
01149 }
01150
01151
01152 ChargeRate = CarInformation.MaxChargeRate * charge_out_percent / 100.0;
01153
01154
01155 load.power = ChargeRate / 1000.0;
01156 }
01157 break;
01158 case VL_HOME_TO_WORK:
01159
01160 ChargeRate = 0.0;
01161
01162
01163 if (t1 >= CarInformation.next_state_change)
01164 {
01165
01166 CarInformation.Location = VL_WORK;
01167
01168
01169 if (Work_Charge_Available == true)
01170 {
01171
01172 temp_double = CarInformation.WorkDuration / 3600.0;
01173
01174
01175 temp_double *= CarInformation.MaxChargeRate;
01176
01177
01178 CarInformation.battery_capacity += temp_double;
01179
01180
01181 if (CarInformation.battery_capacity < 0.0)
01182 {
01183 CarInformation.battery_capacity = 0.0;
01184 }
01185 else if (CarInformation.battery_capacity > CarInformation.battery_size)
01186 {
01187 CarInformation.battery_capacity = CarInformation.battery_size;
01188 }
01189
01190
01191 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
01192 }
01193
01194
01195 if ((variation_std_dev > 0.0) || (variation_mean != 0.0))
01196 {
01197
01198 temp_double = gl_random_normal(RNGSTATE,variation_mean,variation_std_dev) + CarInformation.WorkDuration;
01199
01200
01201 if (temp_double < 0)
01202 {
01203 temp_double = CarInformation.WorkDuration;
01204 }
01205
01206
01207
01208 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(temp_double));
01209 }
01210 else
01211 {
01212
01213
01214 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(CarInformation.WorkDuration));
01215
01216
01217 }
01218 }
01219 else
01220 {
01221 CarInformation.Location = VL_HOME_TO_WORK;
01222
01223
01224 }
01225 break;
01226 case VL_WORK:
01227
01228 ChargeRate = 0.0;
01229
01230
01231 if (t1 >= CarInformation.next_state_change)
01232 {
01233
01234 CarInformation.Location = VL_WORK_TO_HOME;
01235
01236
01237 if ((variation_trip_std_dev > 0.0) || (variation_trip_mean != 0.0))
01238 {
01239
01240 temp_double = gl_random_normal(RNGSTATE,variation_trip_mean,variation_trip_std_dev);
01241
01242
01243 temp_double += CarInformation.travel_distance / 2.0;
01244
01245
01246 if (temp_double < 0)
01247 {
01248 temp_double = CarInformation.travel_distance / 2.0;
01249 }
01250
01251
01252 CarInformation.battery_capacity = CarInformation.battery_capacity - temp_double / CarInformation.mileage_efficiency;
01253 }
01254 else
01255 {
01256
01257 CarInformation.battery_capacity = CarInformation.battery_capacity - CarInformation.travel_distance / 2.0 / CarInformation.mileage_efficiency;
01258 }
01259
01260
01261 if (CarInformation.battery_capacity < 0.0)
01262 {
01263
01264 CarInformation.battery_capacity = 0.0;
01265 }
01266 else if (CarInformation.battery_capacity > CarInformation.battery_size)
01267 {
01268 CarInformation.battery_capacity = CarInformation.battery_size;
01269 }
01270
01271
01272 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
01273
01274
01275 if ((variation_std_dev > 0.0) || (variation_mean != 0.0))
01276 {
01277
01278 temp_double = gl_random_normal(RNGSTATE,variation_mean,variation_std_dev) + CarInformation.WorkHomeDuration;
01279
01280
01281 if (temp_double < 0)
01282 {
01283 temp_double = CarInformation.WorkHomeDuration;
01284 }
01285
01286
01287
01288 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(temp_double));
01289 }
01290 else
01291 {
01292
01293
01294 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(CarInformation.WorkHomeDuration));
01295
01296
01297 }
01298 }
01299 else
01300 {
01301
01302 CarInformation.Location = VL_WORK;
01303
01304
01305 }
01306 break;
01307 case VL_WORK_TO_HOME:
01308
01309 ChargeRate = 0.0;
01310
01311
01312 if (t1 >= CarInformation.next_state_change)
01313 {
01314
01315 CarInformation.Location = VL_HOME;
01316
01317
01318
01319 tdiff = t1 - CarInformation.next_state_change;
01320
01321
01322 temp_double = (double)(tdiff) / 3600.0 * ChargeRate / 1000.0 * CarInformation.ChargeEfficiency;
01323
01324
01325 CarInformation.battery_capacity += temp_double;
01326
01327
01328 if (CarInformation.battery_capacity < 0.0)
01329 {
01330 CarInformation.battery_capacity = 0.0;
01331 }
01332 else if (CarInformation.battery_capacity > CarInformation.battery_size)
01333 {
01334 CarInformation.battery_capacity = CarInformation.battery_size;
01335 }
01336
01337
01338 CarInformation.battery_SOC = CarInformation.battery_capacity / CarInformation.battery_size * 100.0;
01339
01340
01341 if (CarInformation.battery_SOC < 100.0)
01342 {
01343 charge_out_percent = 100;
01344 }
01345 else
01346 {
01347 charge_out_percent = 0.0;
01348 }
01349
01350
01351 ChargeRate = CarInformation.MaxChargeRate * charge_out_percent / 100.0;
01352
01353
01354 load.power = ChargeRate / 1000.0;
01355
01356
01357 if ((variation_std_dev > 0.0) || (variation_mean != 0.0))
01358 {
01359
01360 temp_double = gl_random_normal(RNGSTATE,variation_mean,variation_std_dev) + CarInformation.HomeDuration;
01361
01362
01363 if (temp_double < 0)
01364 {
01365 temp_double = CarInformation.HomeDuration;
01366 }
01367
01368
01369
01370 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(temp_double));
01371 }
01372 else
01373 {
01374
01375
01376 CarInformation.next_state_change = t1 + (TIMESTAMP)(floor(CarInformation.HomeDuration));
01377
01378
01379 }
01380 }
01381 else
01382 {
01383 CarInformation.Location = VL_WORK_TO_HOME;
01384
01385
01386 }
01387 break;
01388 case VL_UNKNOWN:
01389 default:
01390 GL_THROW("Vehicle is at an unknown location!");
01391
01392
01393
01394
01395 }
01396
01397
01398 prev_time = t1;
01399
01400
01401 }
01402
01403
01404 load.total = load.power;
01405
01406
01407 tret = CarInformation.next_state_change;
01408
01409
01410 if (off_nominal_time == true)
01411 {
01412
01413 t2 = t1 + glob_min_timestep;
01414 if (tret < t2)
01415 tret = t2;
01416 }
01417
01418
01419 t2 = residential_enduse::sync(t0, t1);
01420
01421 if (tret < t2)
01422 {
01423 if (tret == TS_NEVER)
01424 return tret;
01425 else
01426 return -tret;
01427 }
01428 else
01429 {
01430 if (t2 == TS_NEVER)
01431 return t2;
01432 else
01433 return -t2;
01434 }
01435 }
01436
01438
01440
01441 EXPORT int create_evcharger_det(OBJECT **obj, OBJECT *parent)
01442 {
01443 try
01444 {
01445 *obj = gl_create_object(evcharger_det::oclass);
01446
01447 if (*obj!=NULL)
01448 {
01449 evcharger_det *my = OBJECTDATA(*obj,evcharger_det);
01450 gl_set_parent(*obj,parent);
01451 my->create();
01452 return 1;
01453 }
01454 else
01455 return 0;
01456 }
01457 CREATE_CATCHALL(evcharger_det);
01458 }
01459
01460 EXPORT int init_evcharger_det(OBJECT *obj)
01461 {
01462 try {
01463 evcharger_det *my = OBJECTDATA(obj,evcharger_det);
01464 return my->init(obj->parent);
01465 }
01466 INIT_CATCHALL(evcharger_det);
01467 }
01468
01469 EXPORT int isa_evcharger_det(OBJECT *obj, char *classname)
01470 {
01471 if(obj != 0 && classname != 0){
01472 return OBJECTDATA(obj,evcharger_det)->isa(classname);
01473 } else {
01474 return 0;
01475 }
01476 }
01477
01478 EXPORT TIMESTAMP sync_evcharger_det(OBJECT *obj, TIMESTAMP t0)
01479 {
01480 try {
01481 evcharger_det *my = OBJECTDATA(obj, evcharger_det);
01482 TIMESTAMP t1 = my->sync(obj->clock, t0);
01483 obj->clock = t0;
01484 return t1;
01485 }
01486 SYNC_CATCHALL(evcharger_det);
01487 }
01488