new version
authorAndrew Tridgell <tridge@samba.org>
Mon, 11 Oct 2010 11:46:18 +0000 (22:46 +1100)
committerAndrew Tridgell <tridge@samba.org>
Mon, 11 Oct 2010 11:46:18 +0000 (22:46 +1100)
pv_model/pv_model.py

index 2b814af316b272f9510731f2c8635152a8610cce..27009f273035147f36c3cb2f55b1b257050b2451 100755 (executable)
@@ -271,12 +271,12 @@ class subpanel:
         if recursive:
             for c in self.cells:
                 c._recalc()
-        # array Voc is sum of cells
+        # subpanel Voc is sum of cells
         self.Voc = 0
         for c in self.cells:
             self.Voc += c.V(0)                
             
-        # array Isc is min of cells
+        # subpanel Isc is min of cells
         self.Isc = self.cells[0].I(0)
         for c in self.cells:
             if c.I(0) < self.Isc:
@@ -339,10 +339,12 @@ class panel:
         for c in self.subpanels:
             self.Voc += c.V(0)                
             
-        # array Isc is min of cells
+        # panel Isc is max of cells. It is the maximum
+        # not the minimum due to the effect of the bypass diodes
+        # on the subpanels
         self.Isc = self.subpanels[0].I(0)
         for c in self.subpanels:
-            if c.I(0) < self.Isc:
+            if c.I(0) > self.Isc:
                 self.Isc = c.I(0)
 
     def V(self, I):
@@ -391,13 +393,15 @@ class string:
         if recursive:
             for p in self.panels:
                 p._recalc(recursive)
-        # array Isc is min of cells
+        # string Isc is max of the panel currents
+        # it is max, not min, as any underperforming
+        # panels will go into bypass
         self.Isc = self.panels[0].I(0)
         for c in self.panels:
-            if c.I(0) < self.Isc:
+            if c.I(0) > self.Isc:
                 self.Isc = c.I(0)
 
-        # array Voc is sum of cells
+        # string Voc is sum of panels
         self.Voc = 0
         for c in self.panels:
             self.Voc += c.V(0)                
@@ -463,7 +467,8 @@ class pvarray:
     @cacheobj
     def V(self, I):
         def Ierr(x):
-            return abs(I - self.I(x))
+            ret = abs(I - self.I(x))
+            return ret
         if I < 0:
             lower = 0
             upper = panel_Voc*len(self.strings[0].panels)
@@ -474,7 +479,7 @@ class pvarray:
             lower = 0
             upper = panel_Voc*opts.string_length
         print "aV I=%g lower=%g upper=%g" % (I, lower, upper)
-        return find_best(Ierr, lower, upper)
+        return find_best2(Ierr, lower, upper)
 
     def P(self, V):
         if V < inverter_range[0] or V > inverter_range[1]:
@@ -638,6 +643,57 @@ def shaded_2mpp():
         print("A1=%.2f A2=%.2f MPPP=%.2fW (%d shaded)" % (Pa1, Pa2, Pa1+Pa2, i+1))
 
 
+def panel_shading():
+    '''plot shading effects on 1 panel'''
+    p = panel()
+    maxv = p.Voc
+    minv = 0
+    plotit(p.P, minv, maxv, label='Unshaded', loc='upper left')
+
+    pylab.xlabel('Voltage (V)')
+    pylab.ylabel('Power (W)')
+    pylab.title("1 Panel")
+
+    for i in range(0, opts.num_subpanels):
+        p.subpanels[i].set_irradiance(opts.irradiance * opts.shade_factor)
+        p._recalc(True)
+        plotit(p.P, minv, maxv, label='%d shaded' % (i+1), loc='upper left')
+    pylab.show()
+
+def panel_shading_IV():
+    '''plot shading effects on 1 panel'''
+    p = panel()
+    maxv = p.Voc
+    minv = 0
+    plotit(p.I, minv, maxv, label='Unshaded', loc='upper left')
+
+    pylab.xlabel('Voltage (V)')
+    pylab.ylabel('Current (A)')
+    pylab.title("1 Panel")
+
+    for i in range(0, opts.num_subpanels):
+        p.subpanels[i].set_irradiance(opts.irradiance * opts.shade_factor)
+        p._recalc(True)
+        plotit(p.I, minv, maxv, label='%d shaded' % (i+1), loc='upper left')
+    pylab.show()
+
+def panel_shading_VI():
+    '''plot shading effects on 1 panel'''
+    p = panel()
+    maxi = p.Isc
+    mini = 0
+    plotit(p.V, mini, maxi, label='Unshaded', loc='upper left')
+
+    pylab.xlabel('Current (A)')
+    pylab.ylabel('Voltage (V)')
+    pylab.title("1 Panel")
+
+    for i in range(0, opts.num_subpanels):
+        p.subpanels[i].set_irradiance(opts.irradiance * opts.shade_factor)
+        p._recalc(True)
+        plotit(p.V, mini, maxi, label='%d shaded' % (i+1), loc='upper left')
+    pylab.show()
+
 def mpp_loss():
     '''show loss from not having separate MPPTs per string'''
     n=opts.string_length
@@ -1012,7 +1068,7 @@ def selftest():
         if err > tolerance:
             raise Exception("%s: v1=%f v2=%g" % (tag, v1, v2))
 
-    def check_IV(tag, m, tolerance=1.0):
+    def check_IV(tag, m, tolerance=10.0):
         irange = numpy.arange(-m.Isc, m.Isc*2, (3*m.Isc/100))
         for i in irange:
             check('%s: I=%g Isc=%g' % (tag, i, m.Isc), m.I(m.V(i)), i,
@@ -1042,7 +1098,7 @@ def selftest():
     p2 = c.P(cell_Vmp)
     check("irradiance", p1, p2/2, tolerance=10)
 
-    check("leakage", c.I(c.Voc+1), -1.0/(opts.panel_Roc/cell_scale))
+    check("leakage", c.I(c.Voc+1), -1.0/(opts.panel_Roc/cell_scale), tolerance=10)
 
     
     
@@ -1052,14 +1108,14 @@ def selftest():
     check("Voc", cell_Voc*opts.cells_per_subpanel, s.V(0))
     check("Isc", panel_Isc, s.I(0))
     check("Vmp", cell_Vmp*opts.cells_per_subpanel, s.V(panel_Imp))
-    check("Imp", panel_Imp, s.I(panel_Vmp*opts.cells_per_subpanel))
+    check("Imp", panel_Imp, s.I(panel_Vmp/opts.num_subpanels))
 
     check_IV("subpanel IV", s)
 
     s2=subpanel()
     s2.set_irradiance(500)
     check_IV("subpanel IV 500W/m2", s2, tolerance=2.0)
-    Vmp = panel_Vmp/opts.cells_per_subpanel
+    Vmp = panel_Vmp/opts.num_subpanels
     check("irradiance", s2.P(Vmp), s.P(Vmp)/2, tolerance=10)
 
     check("bypass1", s.I(-1.0) - s.Isc, 1.0/subpanel_Rbp)
@@ -1073,14 +1129,15 @@ def selftest():
     check("Isc", panel_Isc, p.I(0))
     check("Vmp", panel_Vmp, p.V(panel_Imp))
     check("Imp", panel_Imp, p.I(Vmp))
-    check("bypass", p.I(-1.0) - p.Isc, 1.0/subpanel_Rbp)
+    check("bypass", p.I(-1.0) - p.Isc, 1.0/(subpanel_Rbp*opts.num_subpanels))
 
     check_IV("panel IV", p)
 
     p2=subpanel()
     p2.set_irradiance(500)
     check_IV("panel IV 500W/m2", p2, tolerance=2.0)
-    check("irradiance", p2.P(Vmp), p.P(Vmp)/2, tolerance=10)
+    Vmp = panel_Vmp/opts.num_subpanels
+    check("irradiance", p2.P(Vmp), p.P(Vmp)/2, tolerance=15)
 
     print "Checking string behaviour"
     s=string(opts.string_length)
@@ -1088,7 +1145,7 @@ def selftest():
     check("Isc", panel_Isc, s.I(0))
     check("Vmp", panel_Vmp*opts.string_length, s.V(panel_Imp))
     check("Imp", panel_Imp, s.I(panel_Vmp*opts.string_length))
-    check("bypass", s.I(-1.0*opts.string_length) - s.Isc, 1.0/subpanel_Rbp)
+    check("bypass", s.I(-1.0*opts.string_length) - s.Isc, 1.0/(subpanel_Rbp*opts.num_subpanels))
 
     check_IV("string IV", s, tolerance=5.0)
 
@@ -1106,7 +1163,7 @@ def selftest():
     check("Isc", panel_Isc*2, a.I(0))
 #    check("Vmp", panel_Vmp*opts.string_length, a.V(panel_Imp*2))
     check("Imp", panel_Imp*2, a.I(panel_Vmp*opts.string_length))
-    check("bypass", a.I(-1.0*opts.string_length) - a.Isc, 2.0/subpanel_Rbp)
+    check("bypass", a.I(-1.0*opts.string_length) - a.Isc, 2.0/(opts.num_subpanels*subpanel_Rbp))
 
     check_IV("array IV", a, tolerance=2.0)
 
@@ -1137,6 +1194,9 @@ if __name__ == "__main__":
         "panel_IV_T"   : panel_IV_T,
         "panel_L"      : panel_L,
         "panel_IV_L"   : panel_IV_L,
+        "panel-shading": panel_shading,
+        "panel-shadingIV": panel_shading_IV,
+        "panel-shadingVI": panel_shading_VI,
         "string_P"     : string_P,
         "string_IV"    : string_IV,
         "string_VI"    : string_VI,
@@ -1174,7 +1234,7 @@ if __name__ == "__main__":
     parser.add_option("", "--irradiance", dest="irradiance", help="light level (W/m2)",type='float', default=1000)
     parser.add_option("", "--shade-factor", dest="shade_factor", help="shading factor",type='float', default=0.05)
     parser.add_option("", "--subpanels", dest="num_subpanels", help="subpanels per panel",
-                      type='int', default=1)
+                      type='int', default=3)
     parser.add_option("", "--cells-per-subpanel", dest="cells_per_subpanel", help="cells per subpanel",
                       type='int', default=1)
     parser.add_option("", "--blocking-diodes", dest="blocking_diodes",