def generate_options(inverter_name, module_name, zipcode, ac_dc_ratio=1.2, \ mount="Roof", station_class=1, v_max=600, bipolar=True): """String sizing: find all valid configurations for a location""" module = modules.Module(module_name) inverter = inverters.Inverter(inverter_name) temp_adder = {"Roof":30,\ "Ground":25,\ "Pole":20} #NREL suggests that long term degradation is primarily current not voltage derate20 = .97 #csv is performance hit dummy, usaf = geo.closest_usaf(geo.zip_coordinates(zipcode), station_class) eere_min = eere.minimum(usaf) module_max_voltage = module.v_max(eere_min) eere2 = eere.twopercent(usaf) module_min_voltage = module.v_min(eere2, temp_adder[mount]) * derate20 if inverter.vdcmax != 0: v_max = inverter.vdcmax maxlen = int(v_max//module_max_voltage) minlen = int(inverter.mppt_low/module_min_voltage) + 1 if minlen > maxlen: return [] inverter.array = modules.Array(module, \ [{'series':minlen}]*inverter.mppt_channels) inverter.array.minlength(minlen) inverter.array.maxlength(maxlen) #range to search lower_tol = .25 upper_tol = .30 p_nom_lower = ac_dc_ratio*(1+lower_tol) p_nom_upper = ac_dc_ratio*(1-upper_tol) #inverter_nominal = inverter.p_aco solutions = [] while inverter.ratio() < p_nom_lower: _tmp = copy.deepcopy(inverter) _tmp.max_v = _tmp.array.v_max(eere_min) _tmp.min_v = _tmp.array.v_min(eere2, temp_adder[mount]) if inverter.ratio() >= p_nom_upper: solutions.append(_tmp) inverter.array.inc() #i_max = max(inverter.idcmax,inverter.p_dco*1.0/inverter.mppt_low) #max_parallel = int(round(i_max/inverter.array.panel.i_mpp))+1 #Diophantine equation return solutions
def fill(inverter, zipcode, ac_dc_ratio=1.2, mount="Roof", station_class=1, \ v_max=600, bipolar=True): """deprecated use generate_options""" t_derate = {"Roof":30, \ "Ground":25, \ "Pole":20} #csv is performance hit dummy, usaf = geo.closest_usaf(geo.zip_coordinates(zipcode), station_class) max_v = inverter.array.panel.v_max(eere.minimum(usaf)) #NREL suggests that long term degradation is primarily current not voltage derate20 = .97 min_v = inverter.array.panel.v_min(eere.twopercent(usaf), \ t_derate[mount]) * derate20 if inverter.vdcmax != 0: v_max = inverter.vdcmax smax = int(v_max/max_v) #range to search lower_tol = .30 upper_tol = .30 p_nom_lower = ac_dc_ratio*(1+lower_tol) p_nom_upper = ac_dc_ratio*(1-upper_tol) inverter_nominal = inverter.p_aco psize = inverter.array.panel.p_max solutions = [] i_max = max(inverter.idcmax, inverter.p_dco*1.0/inverter.mppt_low) max_parallel = int(round(i_max/inverter.array.panel.i_mpp))+1 #Diophantine equation for string_len in range(smax+1): if (string_len*min_v) >= inverter.mppt_low: for p_count in range(max_parallel): p_nom = p_count*string_len*psize*1.0/inverter_nominal if p_nom < p_nom_upper and p_nom > lower_tol: inverter.array.shape = [string_len]*p_count _tmp = copy.deepcopy(inverter) _tmp.min_v = string_len*min_v _tmp.max_v = string_len*max_v solutions.append(_tmp) return solutions
def string_notes(system, run=0.0, station_class=3): """page 5""" name, usaf = geo.closest_usaf(geo.zip_coordinates(system.zipcode), \ station_class) mintemp = eere.minimum(usaf) twopercent_temp = eere.twopercent(usaf) ac_kva_rated = 0.0 dc_rated = 0.0 ac_kw = 0.0 for i in system.shape: dc_rated += i.array.p_max try: if i.phase == 1: ac_kva_rated += i.current * i.ac_voltage else: ac_kva_rated += i.phase * i.current * i.ac_voltage / 3**.5 except Exception: ac_kva_rated += i.p_aco ac_kw += i.p_aco notes = [] notes.append("%s KVA AC RATED" % round(ac_kva_rated/1000.0, 2)) notes.append("%s KW AC RATED" % round(ac_kw/1000.0, 2)) notes.append("%s KW DC RATED" % round(dc_rated/1000.0, 2)) #BUG: This doesn't work for unbalanced 3 phase if system.phase == 1: a_ac = round(ac_kva_rated/i.ac_voltage, 1) else: a_ac = round(ac_kva_rated/i.ac_voltage/3**.5, 1) notes.append("System AC Output Current: %s A" % a_ac) notes.append("Nominal AC Voltage: %s V" % i.ac_voltage) notes.append("") notes.append("Minimum Temperature: %s C" % mintemp) notes.append("2 Percent Max Temperature: %s C" % twopercent_temp) notes.append("Weather Source: %s %s" % (name, usaf)) notes.append("") d_inverters, d_panels = system.describe() a_max = 0 for i in system.shape: module_name = i.array.dump()['panel'] if d_panels.has_key(module_name): module = modules.Module(module_name) notes.append("PV Module Ratings @ STC") notes.append("Module Make: %s" % module.make) notes.append("Module Model: %s" % module.model) notes.append("Quantity: %s" % d_panels[module_name]) notes.append("Max Power-Point Current (Imp): %s A" % module.i_mpp) notes.append("Max Power-Point Voltage (Vmp): %s V" % module.v_mpp) notes.append("Open-Circuit Voltage (Voc): %s V" % module.v_oc) notes.append("Short-Circuit Current (Isc): %s A" % module.i_sc) notes.append("Maximum Power (Pmax): %s W" % round(module.p_max, 1)) notes.append("") d_panels.pop(module_name) if d_inverters.has_key(i.model): notes.append("Inverter Make: %s" % i.make) notes.append("Inverter Model: %s" % i.model) notes.append("Quantity: %s" % d_inverters[i.model]) notes.append("Max Power: %s KW" % round(i.p_aco/1000.0, 1)) #this is hack... This should be calculated based upon power cores if hasattr(i, 'current'): notes.append("Max AC Current: %s A" % round(i.current, 1)) elif i.ac_voltage == 480: notes.append("Max AC Current: %s A" % \ round(i.p_aco*1.0/i.ac_voltage/3**.5, 1)) else: notes.append("Max AC Current: %s A" % \ round(i.p_aco*1.0/i.ac_voltage, 1)) #greater than 1 in parallel if i.array.mcount() > 1: notes.append("DC Operating Current: %s A" % \ round(i.array.i_mpp(), 1)) notes.append("DC Short Circuit Current: %s A" % \ round(i.array.i_sc(), 1)) #greater than 1 in series if i.array.mcount() > 1: notes.append("DC Operating Voltage: %s V" % \ round(i.array.v_dc(), 1)) notes.append("System Max DC Voltage: %s V" % \ round(i.array.v_max(mintemp), 1)) if i.array.v_max(mintemp) > 600: logger.warning("WARNING: Array exceeds 600V DC") notes.append("Pnom Ratio: %s" % \ round((i.array.p_max/i.p_aco), 2)) if (i.array.v_dc(twopercent_temp) * .9) < i.mppt_low: logger.warning("WARNING: " \ "Array IV Knee drops out of Inverter range") if (i.array.p_max/i.p_aco) < 1.1: logger.warning("WARNING: Array potentially undersized") notes.append("") d_inverters.pop(i.model) if i.array.v_max(mintemp) > a_max: a_max = i.array.v_max(mintemp) notes.append("Array Azimuth: %s Degrees" % system.azimuth) notes.append("Array Tilt: %s Degrees" % system.tilt) sols_9 = system.solstice(9) sols_15 = system.solstice(15) notes.append("December 21 9:00 AM Sun Azimuth: %s Degrees" % \ (round(degrees(sols_9[1]), 1))) notes.append("December 21 9:00 AM Sun Altitude: %s Degrees" % \ (round(degrees(sols_9[0]), 1))) notes.append("December 21 3:00 PM Sun Azimuth: %s Degrees" % \ (round(degrees(sols_15[1]), 1))) notes.append("December 21 3:00 PM Sun Altitude: %s Degrees" % \ (round(degrees(sols_9[0]), 1))) if 'geomag' in sys.modules: notes.append("Magnetic declination: %s Degrees" % \ round(geomag.declination(dlat=system.place[0], \ dlon=system.place[1]))) notes.append("Minimum Row space ratio: %s" % \ round(system.min_row_space(1.0), 2)) if __name__ == '__main__': print "\n".join(notes) else: logger.info("Plant Details:\n" + "\n".join(notes)) print "" print "Minimum Bundle" min_c = vd.vd(a_ac, 5, verbose=False) try: ee.assemble(min_c, a_ac, conduit='STEEL') if run > 0: print "Long Run" min_c = vd.vd(a_ac, run, v=i.ac_voltage, t_amb=15, pf=.95, \ material='AL', verbose=False) ee.assemble(min_c, a_ac, conduit='PVC') except: print "Warning: Multiple sets of conductors" return notes
def write_notes(system, filename='output', v_nominal=240.0): """file out expedited permit form with system details""" station_class = 1 dummy, usaf = geo.closest_usaf(geo.zip_coordinates(system.zipcode), \ station_class) mintemp = eere.minimum(usaf) twopercent_temp = eere.twopercent(usaf) fields = [] for i in set(system.shape): module_name = i.array.dump()['panel'] module = modules.Module(module_name) print "PV Module Ratings @ STC" print "Module Make:", module.make fields.append(('Text1ModuleMake', module.make)) print "Module Model:", module.model fields.append(('Text1ModuleModel', module.model)) print "Max Power-Point Current (Imp):", module.i_mpp fields.append(('MAX POWERPOINT CURRENT IMP', module.i_mpp)) print "Max Power-Point Voltage (Vmp):", module.v_mpp fields.append(('MAX POWERPOINT VOLTAGE VMP', module.v_mpp)) print "Open-Circuit Voltage (v_oc):", module.v_oc fields.append(('OPENCIRCUIT VOLTAGE VOC', module.v_oc)) print "Short-Circuit Current (i_sc):", module.i_sc fields.append(('SHORTCIRCUIT CURRENT ISC', module.i_sc)) fields.append(('MAX SERIES FUSE OCPD', '15')) print "Maximum Power (p_max):", module.p_max fields.append(('MAXIMUM POWER PMAX', module.p_max)) print "Module Rated Max Voltage:", module.Vrated fields.append(('MAX VOLTAGE TYP 600VDC', module.Vrated)) fields.append(('VOC TEMP COEFF mVoC or oC', round(module.tk_v_oc, 2))) fields.append(('VOC TEMP COEFF mVoC', 'On')) print "Inverter Make:", i.make fields.append(('INVERTER MAKE', i.make)) print "Inverter Model:", i.model fields.append(('INVERTER MODEL', i.model)) print "Max Power", i.p_aco fields.append(('MAX POWER 40oC', i.p_aco)) fields.append(('NOMINAL AC VOLTAGE', 240)) print "Max AC Current: %s" % round(i.p_aco/v_nominal, 2) fields.append(('MAX AC CURRENT', round(i.p_aco/v_nominal, 2))) fields.append(('MAX DC VOLT RATING', i.mppt_hi)) print "Max AC OCPD Rating: %s" % ee.ocp_size(i.p_aco/v_nominal*1.25) print "Max System Voltage:", round(module.v_max(mintemp), 1) print "AC Output Current: %s" % \ round(sum([i.p_aco for i in system.shape])/v_nominal, 2) fields.append(('AC OUTPUT CURRENT', \ round(sum([i.p_aco for i in system.shape])/v_nominal, 2))) print "Nominal AC Voltage: %s" % v_nominal fields.append(('NOMINAL AC VOLTAGE_2', i.ac_voltage)) print "Minimum Temperature: %s C" % mintemp print "2 Percent Max: %s C" % twopercent_temp from fdfgen import forge_fdf fdf = forge_fdf("", fields, [], [], []) fdf_file = open("data.fdf", "w") fdf_file.write(fdf) fdf_file.close() import shlex from subprocess import call cmd = shlex.split("pdftk Example2-Micro-Inverter.pdf fill_form data.fdf" \ "%s output.pdf flatten" % filename) rc = call(cmd) return rc
record['utc_datetime'] = strptime(_sd, self.tz) record['datetime'] = strptime(_sd) return record def __del__(self): self.csvfile.close() def total(usaf, field='GHI (W/m^2)'): """total annual insolation, defaults to GHI""" running_total = 0 usafdata = data(usaf) for record in usafdata: running_total += float(record[field]) return running_total/1000. if __name__ == "__main__": from solpy import geo TILT = 32.0 #import matplotlib.pyplot as plt #place = zipToCoordinates('17601) #Lancaster PLACE = geo.zip_coordinates('19113') #Philadelphia DUMMY, USAF = geo.closest_usaf(PLACE) TOTAL_INS = 0 for i in data(USAF): output = irradiation.irradiation(i, PLACE, t=TILT) TOTAL_INS += output print TOTAL_INS/1000 print TOTAL_INS/(1000*365.0) print total(USAF)
PARSER = argparse.ArgumentParser(description='Model a PV system. '\ 'Currently displays annual output and graph') #import sys #opts, ARGS = getopt.getopt(sys.argv[1:], 'f:h') PARSER.add_argument('-z', '--zipcode', required=True) PARSER.add_argument('-m', '--mname') PARSER.add_argument('-v', '--voltage', type=int, default=600) ARGS = vars(PARSER.parse_args()) #print ARGS try: #start program ZIPCODE = ARGS['zipcode'] MAX_VOLTAGE = ARGS['voltage'] STATION_CLASS = 1 NAME, USAF = geo.closest_usaf(geo.zip_coordinates(ZIPCODE), \ STATION_CLASS) print "%s usaf: %s" % (NAME, USAF) print "Minimum Temperature: %s C" % minimum(USAF) print "2%% Max: %s C" % twopercent(USAF) print "Heating Degree days: %s" % hdd(USAF) print "Cooling Degree days: %s" % cdd(USAF) if ARGS['mname']: print "" MODELS = modules.model_search(ARGS['mname'].split(' ')) MODULE = None if len(MODELS) > 1: for i in MODELS: print i sys.exit(1) elif len(MODELS) == 1: print MODELS[0]
def set_zipcode(self, zipcode, station_class=3): """update zipcode""" self.zipcode = zipcode self.place = geo.zip_coordinates(self.zipcode) self.tz = geo.zip_tz(self.zipcode) self.name, self.usaf = geo.closest_usaf(self.place, station_class)
def string_notes(system, run=0.0, station_class=3): """page 5""" name, usaf = geo.closest_usaf(geo.zip_coordinates(system.zipcode), \ station_class) mintemp = eere.minimum(usaf) twopercent_temp = eere.twopercent(usaf) ac_kva_rated = 0.0 dc_rated = 0.0 ac_kw = 0.0 for i in system.shape: dc_rated += i.array.p_max try: if i.phase == 1: ac_kva_rated += i.current * i.ac_voltage else: ac_kva_rated += i.phase * i.current * i.ac_voltage / 3**.5 except Exception: ac_kva_rated += i.p_aco ac_kw += i.p_aco notes = [] notes.append("%s KVA AC RATED" % round(ac_kva_rated / 1000.0, 2)) notes.append("%s KW AC RATED" % round(ac_kw / 1000.0, 2)) notes.append("%s KW DC RATED" % round(dc_rated / 1000.0, 2)) #BUG: This doesn't work for unbalanced 3 phase if system.phase == 1: a_ac = round(ac_kva_rated / i.ac_voltage, 1) else: a_ac = round(ac_kva_rated / i.ac_voltage / 3**.5, 1) notes.append("System AC Output Current: %s A" % a_ac) notes.append("Nominal AC Voltage: %s V" % i.ac_voltage) notes.append("") notes.append("Minimum Temperature: %s C" % mintemp) notes.append("2 Percent Max Temperature: %s C" % twopercent_temp) notes.append("Weather Source: %s %s" % (name, usaf)) notes.append("") d_inverters, d_panels = system.describe() a_max = 0 for i in system.shape: module_name = i.array.dump()['panel'] if d_panels.has_key(module_name): module = modules.Module(module_name) notes.append("PV Module Ratings @ STC") notes.append("Module Make: %s" % module.make) notes.append("Module Model: %s" % module.model) notes.append("Quantity: %s" % d_panels[module_name]) notes.append("Max Power-Point Current (Imp): %s A" % module.i_mpp) notes.append("Max Power-Point Voltage (Vmp): %s V" % module.v_mpp) notes.append("Open-Circuit Voltage (Voc): %s V" % module.v_oc) notes.append("Short-Circuit Current (Isc): %s A" % module.i_sc) notes.append("Maximum Power (Pmax): %s W" % round(module.p_max, 1)) notes.append("") d_panels.pop(module_name) if d_inverters.has_key(i.model): notes.append("Inverter Make: %s" % i.make) notes.append("Inverter Model: %s" % i.model) notes.append("Quantity: %s" % d_inverters[i.model]) notes.append("Max Power: %s KW" % round(i.p_aco / 1000.0, 1)) #this is hack... This should be calculated based upon power cores if hasattr(i, 'current'): notes.append("Max AC Current: %s A" % round(i.current, 1)) elif i.ac_voltage == 480: notes.append("Max AC Current: %s A" % \ round(i.p_aco*1.0/i.ac_voltage/3**.5, 1)) else: notes.append("Max AC Current: %s A" % \ round(i.p_aco*1.0/i.ac_voltage, 1)) #greater than 1 in parallel if i.array.mcount() > 1: notes.append("DC Operating Current: %s A" % \ round(i.array.i_mpp(), 1)) notes.append("DC Short Circuit Current: %s A" % \ round(i.array.i_sc(), 1)) #greater than 1 in series if i.array.mcount() > 1: notes.append("DC Operating Voltage: %s V" % \ round(i.array.v_dc(), 1)) notes.append("System Max DC Voltage: %s V" % \ round(i.array.v_max(mintemp), 1)) if i.array.v_max(mintemp) > 600: logger.warning("WARNING: Array exceeds 600V DC") notes.append("Pnom Ratio: %s" % \ round((i.array.p_max/i.p_aco), 2)) if (i.array.v_dc(twopercent_temp) * .9) < i.mppt_low: logger.warning("WARNING: " \ "Array IV Knee drops out of Inverter range") if (i.array.p_max / i.p_aco) < 1.1: logger.warning("WARNING: Array potentially undersized") notes.append("") d_inverters.pop(i.model) if i.array.v_max(mintemp) > a_max: a_max = i.array.v_max(mintemp) notes.append("Array Azimuth: %s Degrees" % system.azimuth) notes.append("Array Tilt: %s Degrees" % system.tilt) sols_9 = system.solstice(9) sols_15 = system.solstice(15) notes.append("December 21 9:00 AM Sun Azimuth: %s Degrees" % \ (round(degrees(sols_9[1]), 1))) notes.append("December 21 9:00 AM Sun Altitude: %s Degrees" % \ (round(degrees(sols_9[0]), 1))) notes.append("December 21 3:00 PM Sun Azimuth: %s Degrees" % \ (round(degrees(sols_15[1]), 1))) notes.append("December 21 3:00 PM Sun Altitude: %s Degrees" % \ (round(degrees(sols_9[0]), 1))) if 'geomag' in sys.modules: notes.append("Magnetic declination: %s Degrees" % \ round(geomag.declination(dlat=system.place[0], \ dlon=system.place[1]))) notes.append("Minimum Row space ratio: %s" % \ round(system.min_row_space(1.0), 2)) if __name__ == '__main__': print "\n".join(notes) else: logger.info("Plant Details:\n" + "\n".join(notes)) print "" print "Minimum Bundle" min_c = vd.vd(a_ac, 5, verbose=False) try: ee.assemble(min_c, a_ac, conduit='STEEL') if run > 0: print "Long Run" min_c = vd.vd(a_ac, run, v=i.ac_voltage, t_amb=15, pf=.95, \ material='AL', verbose=False) ee.assemble(min_c, a_ac, conduit='PVC') except: print "Warning: Multiple sets of conductors" return notes
def write_notes(system, filename='output', v_nominal=240.0): """file out expedited permit form with system details""" station_class = 1 dummy, usaf = geo.closest_usaf(geo.zip_coordinates(system.zipcode), \ station_class) mintemp = eere.minimum(usaf) twopercent_temp = eere.twopercent(usaf) fields = [] for i in set(system.shape): module_name = i.array.dump()['panel'] module = modules.Module(module_name) print "PV Module Ratings @ STC" print "Module Make:", module.make fields.append(('Text1ModuleMake', module.make)) print "Module Model:", module.model fields.append(('Text1ModuleModel', module.model)) print "Max Power-Point Current (Imp):", module.i_mpp fields.append(('MAX POWERPOINT CURRENT IMP', module.i_mpp)) print "Max Power-Point Voltage (Vmp):", module.v_mpp fields.append(('MAX POWERPOINT VOLTAGE VMP', module.v_mpp)) print "Open-Circuit Voltage (v_oc):", module.v_oc fields.append(('OPENCIRCUIT VOLTAGE VOC', module.v_oc)) print "Short-Circuit Current (i_sc):", module.i_sc fields.append(('SHORTCIRCUIT CURRENT ISC', module.i_sc)) fields.append(('MAX SERIES FUSE OCPD', '15')) print "Maximum Power (p_max):", module.p_max fields.append(('MAXIMUM POWER PMAX', module.p_max)) print "Module Rated Max Voltage:", module.Vrated fields.append(('MAX VOLTAGE TYP 600VDC', module.Vrated)) fields.append(('VOC TEMP COEFF mVoC or oC', round(module.tk_v_oc, 2))) fields.append(('VOC TEMP COEFF mVoC', 'On')) print "Inverter Make:", i.make fields.append(('INVERTER MAKE', i.make)) print "Inverter Model:", i.model fields.append(('INVERTER MODEL', i.model)) print "Max Power", i.p_aco fields.append(('MAX POWER 40oC', i.p_aco)) fields.append(('NOMINAL AC VOLTAGE', 240)) print "Max AC Current: %s" % round(i.p_aco / v_nominal, 2) fields.append(('MAX AC CURRENT', round(i.p_aco / v_nominal, 2))) fields.append(('MAX DC VOLT RATING', i.mppt_hi)) print "Max AC OCPD Rating: %s" % ee.ocp_size( i.p_aco / v_nominal * 1.25) print "Max System Voltage:", round(module.v_max(mintemp), 1) print "AC Output Current: %s" % \ round(sum([i.p_aco for i in system.shape])/v_nominal, 2) fields.append(('AC OUTPUT CURRENT', \ round(sum([i.p_aco for i in system.shape])/v_nominal, 2))) print "Nominal AC Voltage: %s" % v_nominal fields.append(('NOMINAL AC VOLTAGE_2', i.ac_voltage)) print "Minimum Temperature: %s C" % mintemp print "2 Percent Max: %s C" % twopercent_temp from fdfgen import forge_fdf fdf = forge_fdf("", fields, [], [], []) fdf_file = open("data.fdf", "w") fdf_file.write(fdf) fdf_file.close() import shlex from subprocess import call cmd = shlex.split("pdftk Example2-Micro-Inverter.pdf fill_form data.fdf" \ "%s output.pdf flatten" % filename) rc = call(cmd) return rc