class Power_CellVoltage(ExplicitComponent): """ Compute the output voltage of the solar panels. """ def __init__(self, n, filename=None): super(Power_CellVoltage, self).__init__() self.n = n if not filename: fpath = os.path.dirname(os.path.realpath(__file__)) filename = fpath + '/data/Power/curve.dat' dat = np.genfromtxt(filename) nT, nA, nI = dat[:3] nT = int(nT) nA = int(nA) nI = int(nI) T = dat[3:3 + nT] A = dat[3 + nT:3 + nT + nA] I = dat[3 + nT + nA:3 + nT + nA + nI] # noqa: E741 V = dat[3 + nT + nA + nI:].reshape((nT, nA, nI), order='F') self.MBI = MBI(V, [T, A, I], [6, 6, 15], [3, 3, 3]) self.MBI.seterr('raise') self.x = np.zeros((84 * n, 3), order='F') self.xV = self.x.reshape((n, 7, 12, 3), order='F') def setup(self): n = self.n # Inputs self.add_input('LOS', np.zeros((n, )), units=None, desc='Line of Sight over Time') self.add_input('temperature', np.zeros((n, 5)), units='degK', desc='Temperature of solar cells over time') self.add_input( 'exposedArea', np.zeros((n, 7, 12)), units='m**2', desc='Exposed area to sun for each solar cell over time') self.add_input('Isetpt', np.zeros((n, 12)), units='A', desc='Currents of the solar panels') # Outputs self.add_output('V_sol', np.zeros((n, 12)), units='V', desc='Output voltage of solar panel over time') rows = np.arange(n * 12) cols = np.tile(np.repeat(0, 12), n) + np.repeat(np.arange(n), 12) self.declare_partials('V_sol', 'LOS', rows=rows, cols=cols) row = np.tile(np.repeat(0, 5), 12) + np.repeat(np.arange(12), 5) rows = np.tile(row, n) + np.repeat(12 * np.arange(n), 60) col = np.tile(np.arange(5), 12) cols = np.tile(col, n) + np.repeat(5 * np.arange(n), 60) self.declare_partials('V_sol', 'temperature', rows=rows, cols=cols) row = np.tile(np.arange(12), 7) rows = np.tile(row, n) + np.repeat(12 * np.arange(n), 84) cols = np.arange(n * 7 * 12) self.declare_partials('V_sol', 'exposedArea', rows=rows, cols=cols) row_col = np.arange(n * 12) self.declare_partials('V_sol', 'Isetpt', rows=row_col, cols=row_col) def setx(self, inputs): temperature = inputs['temperature'] LOS = inputs['LOS'] exposedArea = inputs['exposedArea'] Isetpt = inputs['Isetpt'] for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.xV[:, c, p, 0] = temperature[:, i] self.xV[:, c, p, 1] = LOS * exposedArea[:, c, p] self.xV[:, c, p, 2] = Isetpt[:, p] def compute(self, inputs, outputs): """ Calculate outputs. """ n = self.n self.setx(inputs) self.raw = self.MBI.evaluate(self.x)[:, 0].reshape((n, 7, 12), order='F') outputs['V_sol'] = np.zeros((n, 12)) for c in range(7): outputs['V_sol'] += self.raw[:, c, :] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ n = self.n exposedArea = inputs['exposedArea'] LOS = inputs['LOS'] raw1 = self.MBI.evaluate(self.x, 1)[:, 0].reshape((n, 7, 12), order='F') raw2 = self.MBI.evaluate(self.x, 2)[:, 0].reshape((n, 7, 12), order='F') raw3 = self.MBI.evaluate(self.x, 3)[:, 0].reshape((n, 7, 12), order='F') dV_dL = np.empty((n, 12)) dV_dT = np.zeros((n, 12, 5)) dV_dA = np.zeros((n, 7, 12)) dV_dI = np.empty((n, 12)) for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): dV_dL[:, p] += raw2[:, c, p] * exposedArea[:, c, p] dV_dT[:, p, i] += raw1[:, c, p] dV_dA[:, c, p] += raw2[:, c, p] * LOS dV_dI[:, p] += raw3[:, c, p] partials['V_sol', 'LOS'] = dV_dL.flatten() partials['V_sol', 'temperature'] = dV_dT.flatten() partials['V_sol', 'exposedArea'] = dV_dA.flatten() partials['V_sol', 'Isetpt'] = dV_dI.flatten()
class CommGainPatternComp(ExplicitComponent): """ Determines transmitter gain based on an external az-el map. """ # # def __init__(self, num_nodes, rawG_file=None): # super(CommGainPatternComp, self).__init__(num_nodes=num_nodes) # # if not rawG_file: # fpath = os.path.dirname(os.path.realpath(__file__)) # rawG_file = fpath + '/data/Comm/Gain.txt' # # rawGdata = np.genfromtxt(rawG_file) # rawG = (10 ** (rawGdata / 10.0)).reshape((361, 361), order='F') # # pi = np.pi # az = np.linspace(0, 2 * pi, 361) # el = np.linspace(0, 2 * pi, 361) # # self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) # self.x = np.zeros((self.n, 2), order='F') def initialize(self): dir_path = os.path.dirname(os.path.realpath(__file__)) parent_path = os.path.abspath(os.path.join(dir_path, os.pardir)) rawG_file = os.path.join(parent_path, 'data/Comm/Gain.txt') self.options.declare('num_nodes', types=(int, )) self.options.declare('rawG_file', types=(str, ), default=rawG_file) def setup(self): nn = self.options['num_nodes'] rawGdata = np.genfromtxt(self.options['rawG_file']) rawG = (10**(rawGdata / 10.0)).reshape((361, 361), order='F') pi = np.pi az = np.linspace(0, 2 * pi, 361) el = np.linspace(0, 2 * pi, 361) self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) self.MBI.seterr('raise') self.x = np.zeros((nn, 2), order='F') # Inputs self.add_input( 'azimuthGS', np.zeros(nn), units='rad', desc='Azimuth angle from satellite to ground station in ' 'Earth-fixed frame over time') self.add_input('elevationGS', np.zeros(nn), units='rad', desc='Elevation angle from satellite to ground station ' 'in Earth-fixed frame over time') # Outputs self.add_output('gain', np.zeros(nn), units=None, desc='Transmitter gain over time') row_col = np.arange(nn) self.declare_partials('gain', 'elevationGS', rows=row_col, cols=row_col) self.declare_partials('gain', 'azimuthGS', rows=row_col, cols=row_col) def compute(self, inputs, outputs): """ Calculate outputs. """ result = fixangles(self.options['num_nodes'], inputs['azimuthGS'], inputs['elevationGS']) self.x[:, 0] = result[0] self.x[:, 1] = result[1] outputs['gain'] = self.MBI.evaluate(self.x)[:, 0] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ partials['gain', 'azimuthGS'] = self.MBI.evaluate(self.x, 1)[:, 0] partials['gain', 'elevationGS'] = self.MBI.evaluate(self.x, 2)[:, 0]
class Comm_GainPattern(ExplicitComponent): """ Determines transmitter gain based on an external az-el map. """ def __init__(self, n, rawG_file=None): super(Comm_GainPattern, self).__init__() self.n = n if not rawG_file: fpath = os.path.dirname(os.path.realpath(__file__)) rawG_file = fpath + '/data/Comm/Gain.txt' rawGdata = np.genfromtxt(rawG_file) rawG = (10**(rawGdata / 10.0)).reshape((361, 361), order='F') pi = np.pi az = np.linspace(0, 2 * pi, 361) el = np.linspace(0, 2 * pi, 361) self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) self.MBI.seterr('raise') self.x = np.zeros((self.n, 2), order='F') def setup(self): n = self.n # Inputs self.add_input( 'azimuthGS', np.zeros(n), units='rad', desc='Azimuth angle from satellite to ground station in ' 'Earth-fixed frame over time') self.add_input('elevationGS', np.zeros(n), units='rad', desc='Elevation angle from satellite to ground station ' 'in Earth-fixed frame over time') # Outputs self.add_output('gain', np.zeros(n), units=None, desc='Transmitter gain over time') row_col = np.arange(n) self.declare_partials('gain', 'elevationGS', rows=row_col, cols=row_col) self.declare_partials('gain', 'azimuthGS', rows=row_col, cols=row_col) def compute(self, inputs, outputs): """ Calculate outputs. """ result = fixangles(self.n, inputs['azimuthGS'], inputs['elevationGS']) self.x[:, 0] = result[0] self.x[:, 1] = result[1] outputs['gain'] = self.MBI.evaluate(self.x)[:, 0] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ partials['gain', 'azimuthGS'] = self.MBI.evaluate(self.x, 1)[:, 0] partials['gain', 'elevationGS'] = self.MBI.evaluate(self.x, 2)[:, 0]
class Solar_ExposedArea(ExplicitComponent): """ Exposed area calculation for a given solar cell p: panel ID [0,11] c: cell ID [0,6] a: fin angle [0,90] z: azimuth [0,360] e: elevation [0,180] LOS: line of sight with the sun [0,1] """ def __init__(self, n, raw1_file=None, raw2_file=None): super(Solar_ExposedArea, self).__init__() self.n = n self.raw1_file = raw1_file self.raw2_file = raw2_file def setup(self): n = self.n raw1_file = self.raw1_file raw2_file = self.raw2_file fpath = os.path.dirname(os.path.realpath(__file__)) if not raw1_file: raw1_file = fpath + '/data/Solar/Area10.txt' if not raw2_file: raw2_file = fpath + '/data/Solar/Area_all.txt' raw1 = np.genfromtxt(raw1_file) raw2 = np.loadtxt(raw2_file) nc = self.nc = 7 self.np = 12 self.na = 10 self.nz = 73 self.ne = 37 angle = np.zeros(self.na) azimuth = np.zeros(self.nz) elevation = np.zeros(self.ne) index = 0 for i in range(self.na): angle[i] = raw1[index] index += 1 for i in range(self.nz): azimuth[i] = raw1[index] index += 1 index -= 1 azimuth[self.nz - 1] = 2.0 * np.pi for i in range(self.ne): elevation[i] = raw1[index] index += 1 angle[0] = 0.0 angle[-1] = np.pi / 2.0 azimuth[0] = 0.0 azimuth[-1] = 2 * np.pi elevation[0] = 0.0 elevation[-1] = np.pi counter = 0 data = np.zeros((self.na, self.nz, self.ne, self.np * self.nc)) flat_size = self.na * self.nz * self.ne for p in range(self.np): for c in range(nc): data[:, :, :, counter] = \ raw2[nc * p + c][119:119 + flat_size].reshape((self.na, self.nz, self.ne)) counter += 1 self.MBI = MBI(data, [angle, azimuth, elevation], [4, 10, 8], [4, 4, 4]) self.MBI.seterr('raise') self.x = np.zeros((self.n, 3)) self.Jfin = None self.Jaz = None self.Jel = None # Inputs self.add_input('finAngle', 0.0, units='rad', desc='Fin angle of solar panel') self.add_input( 'azimuth', np.zeros((n, )), units='rad', desc='Azimuth angle of the sun in the body-fixed frame over time') self.add_input( 'elevation', np.zeros((n, )), units='rad', desc='Elevation angle of the sun in the body-fixed frame over time' ) # Outputs self.add_output( 'exposedArea', np.zeros((n, self.nc, self.np)), desc='Exposed area to sun for each solar cell over time', units='m**2', lower=-5e-3, upper=1.834e-1) self.declare_partials('exposedArea', 'finAngle') nn = self.nc * self.np rows = np.tile(np.arange(nn), n) + np.repeat(nn * np.arange(n), nn) cols = np.tile(np.repeat(0, nn), n) + np.repeat(np.arange(n), nn) self.declare_partials('exposedArea', 'azimuth', rows=rows, cols=cols) self.declare_partials('exposedArea', 'elevation', rows=rows, cols=cols) def compute(self, inputs, outputs): """ Calculate outputs. """ self.setx(inputs) P = self.MBI.evaluate(self.x) outputs['exposedArea'] = P.reshape(self.n, self.nc, self.np, order='F') def setx(self, inputs): """ Sets our state array """ result = fixangles(self.n, inputs['azimuth'], inputs['elevation']) self.x[:, 0] = inputs['finAngle'] self.x[:, 1] = result[0] self.x[:, 2] = result[1] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ Jfin = self.MBI.evaluate(self.x, 1).reshape(self.n, self.nc, self.np, order='F') Jaz = self.MBI.evaluate(self.x, 2).reshape(self.n, self.nc, self.np, order='F') Jel = self.MBI.evaluate(self.x, 3).reshape(self.n, self.nc, self.np, order='F') partials['exposedArea', 'finAngle'] = Jfin.flatten() partials['exposedArea', 'azimuth'] = Jaz.flatten() partials['exposedArea', 'elevation'] = Jel.flatten()