def add(self, device_id, device_class, pool, miner, algo, region, hashrate, gross_mbtc, net_mbtc, device_watts, total_watts): if not os.path.exists(self.log_file): with open(self.log_file, "w") as f: f.write( "timestamp,device_id,device_class,pool,miner,algorithm,region,hashrate,gross_mbtc,net_mbtc,device_watts,total_watts\n" ) with open(self.log_file, "a+") as f: if net_mbtc == 0: net_s = "" else: net_s = "%.2f" % (net_mbtc) if '_' in algo: hashrate_s = Units().hashrate_str(hashrate) else: hashrate_s = Units().hashrate_str(hashrate[0]) f.write("%s,%d,%s,%s,%s,%s,%s,%s,%.2f,%s,%.2f,%.2f\n" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), device_id, device_class, pool, miner, algo, region, hashrate_s, gross_mbtc, net_s, device_watts, total_watts)) if os.path.getsize(self.log_file) >= ( Config().get('stats.max_size_mb') * 1024 * 1024): self.rotate_logs(self.log_file)
def __init__(self, sim, config): self.sim = sim self.config = config # Note: this is passed in, and is located at sim.pod.forces.aero in the config file # @see http://www.softschools.com/formulas/physics/air_resistance_formula/85/ self.air_resistance_k = Units.SI( self.config.air_density) * self.config.drag_coefficient * Units.SI( self.config.drag_area) / 2
def test_str_and_repr(self): """ String representations correctly created. """ num = Units(value=0, units='ok') expected = '0ok' actual = str(num) self.assertEqual(expected, actual) expected = "Units(value=0, units='ok')" actual = num.__repr__() self.assertEqual(expected, actual) exec('expected = ' + num.__repr__()) self.assertEqual(expected, num)
def get_power_draw_average_time_periods(self): data = {} for seconds in Config().get('live_data.power_draw_averages'): data[seconds] = Units().seconds_to_string(seconds) return data
def __init__(self, sim, config): PollingSensor.__init__(self, sim, config) self.logger = logging.getLogger("Accelerometer") self.logger.info("Initializing Accelerometer {}".format(self.config.id)) self.data = namedtuple('AccelerometerData', ['t_usec', 'raw_x', 'raw_y', 'raw_z', 'real_x', 'real_y', 'real_z']) # Quantities for converting to raw values raw_min = self.config.raw_min raw_max = self.config.raw_max real_min = Units.SI(self.config.real_min) real_max = Units.SI(self.config.real_max) self.sensor_input_range = (real_min, real_max) self.sensor_output_range = (raw_min, raw_max)
def get_miner_hashrate_for_algorithm_on_device(self, miner_name, algorithm, device_class): calibrated = self.get('%s.%s.%s' % (device_class, miner_name, algorithm)) if calibrated: return Units().hashrate_str(calibrated['hashrate']) return " "
class JoyStick: def __init__(self): self.converter = Units() def moveUp(self, amount): return "PR ,{0}".format(self.converter.El_to_encoder(amount,False),) def moveDown(self, amount): return "PR ,{0}".format(-1*self.converter.El_to_encoder(amount,False),) def moveRight(self, amount): return "PR {0},".format(self.converter.Az_to_encoder(amount,False),) def moveLeft(self, amount): return "PR {0},".format(-1*self.converter.Az_to_encoder(amount,False),) def moveAbs(self, Az, El): return "PA {0},{1}".format(self.converter.Az_to_encoder(Az), self.converter.El_to_encoder(El)) def calibrate(self, wanted_Az, wanted_El, current_Az, current_El): self.converter.setOffset(wanted_Az, wanted_El, current_Az, current_El)
def __init__(self, sim, config): self.sim = sim self.config = config self.name = "F_lateral_stability" self.step_listeners = [] self.data = namedtuple(self.name, ['x', 'y', 'z']) self.damping_coefficient = Units.SI(self.config.damping_coefficient)
def realnew(klass, h, M, L, K): self = object.__new__(klass) self.M = M self.L = L self.K = K self.h = h self.units = Units(h) self.U = self.units self.DH = self.units.C / self.units.H0 self.tH = 1.0 / self.units.H0 self._cosmology = _cosmology.Cosmology(self.M, self.K, self.L, self.h) return self
def check_hashrate(self): hashrates = Calibration().get_hashrates(self) if len(self.algos) == 0: return miner = self.algos[0]['miner'] algo = self.algos[0]['algo'] if not miner in hashrates.keys() or not algo in hashrates[miner].keys( ): self.log( 'warning', 'running uncalibrated algorithm %s with miner %s' % (algo, miner)) return if self.algos[0]['algo'] in Config().get('algorithms.single'): baseline = float(hashrates[miner][algo]['hashrate']) else: baseline = float(hashrates[miner][algo]['hashrate'][0]) threshold_pc_value = ( baseline / 100) * Config().get('hashrate_alert_threshold_percent') hr_s = Units().hashrate_str(self.algos[0]['hashrate'][0]) bl_s = Units().hashrate_str(baseline) if self.algos[0]['hashrate'][0] < baseline and ( baseline - self.algos[0]['hashrate'][0]) >= threshold_pc_value: self.log( 'warning', 'hashrate %d%% below calibrated rate [%s < %s]' % (Config().get('hashrate_alert_threshold_percent'), hr_s, bl_s)) if self.algos[0]['hashrate'][0] > baseline and ( self.algos[0]['hashrate'][0] - baseline) >= threshold_pc_value: self.log( 'warning', 'hashrate %d%% above calibrated rate [%s > %s]' % (Config().get('hashrate_alert_threshold_percent'), hr_s, bl_s))
def __init__(self, sim, config): PollingSensor.__init__(self, sim, config) self.logger = logging.getLogger("LaserOptoSensor") self.logger.info("Initializing Laser Opto Sensor {}".format( self.config.id)) # Get model info (min/max, raw values, etc.) self.model = self.sim.config.sensors.models[self.config.model] # Set ranges for mapping real to raw and vice versa self.real_range = [ Units.SI(self.model.real_min), Units.SI(self.model.real_max) ] self.raw_range = [self.model.raw_min, self.model.raw_max] # Get the height offset for this sensor? self.he_height_offset = Units.SI(self.config.he_height_offset) self.measurement_offset = self.he_height_offset - Units.SI( self.model.internal_offset) # Data types self.data = namedtuple('LaserOptoSensorData', ('t_usec', 'height'))
def parseFile(self, file): self.results = {} file = open(file,"r") try: for entry in file: entry = entry.strip() cols = entry.split("^") id = cols[0].strip("~") unit = cols[1].strip("~") unit = Units.getUnitForLabel(unit) label = cols[3].strip("~") val = Nutrient(label, unit, id) self.results[id] = val except: return None return self.results
def __init__(self, sim, config): Sensor.__init__(self, sim, config) self.logger = logging.getLogger("PollingSensor") # Configuration # Grab the fixed timestep from the sim. If we wanted to use a variable timestep we would need to do the next calculations in the lerp function self.sampling_rate = Units.SI(self.config.sampling_rate) # Hz # @see self._add_noise() and numpy.random.normal self.noise_center = self.config.noise.center or 0.0 self.noise_scale = self.config.noise.scale or 0.0 # Volatile #self.buffer = RingBuffer(config.buffer_size, config.dtype) # @todo: How to specify dtype in configuration? There should be a string rep of dtype I think self.buffer = None # Note: we depend on our listeners to handle any buffering/saving/sending of sensor values. Buffer is cleard after each step. self.sample_times = None self.next_start = 0.0 self.step_lerp_pcts = None # Set during step
def new_controller(self): ''' Inits controller. Usage: New Simulation ''' self.universe = Universe() # Holds the startpoint universe self.copy_universe = None # Folder where to save files and Default file name self.file_name = "test.xml" self.folder = "files/" self.filePath = None self.units = Units() self.pref_dict = {} self.timer_time = 10 self.steps_between_paint = 1
def set(self, **kwargs): """ set() [public] Purpose: Sets station plot variables (such as temperature, dewpoint, etc.) Parameters: Key-value pairs (station variable to value, e.g. tmpf=50. Returns: [nothing] """ re_value_string = re.compile("^(\\-?[\\d]+\\.?[\\d]*)[\\s]*([\\w\\d\\- ]+)$") for attr, value in kwargs.iteritems(): if attr in self._valid_attrs: re_value_match = re_value_string.match(value) if re_value_match is not None: obs_value, obs_units = re_value_match.groups() obs_value = Units.convert(float(obs_value), obs_units, HootPyStationPlot._internal_units[attr]) setattr(self, "_%s" % attr, obs_value) else: setattr(self, "_%s" % attr, value) else: fatalError("Attribute %s is not a valid attribute for this type of station plot." % attr) return
def create_step_samples(self, dt_usec): # Pod acceleration (x) pod_start_accel = self.sim.pod.last_acceleration pod_end_accel = self.sim.pod.acceleration # Create the samples (lerp between the times) sample_data = self._lerp(pod_start_accel, pod_end_accel) sample_times = sample_times = self._get_sample_times(dt_usec) # @todo: apply a rotation matrix to simulate the actual # NOTE: Accel is mounted such that it is rotated 90 degrees in the horizontal plane such that: # +y accel = +x pod reference frame, +x accel = -y pod reference frame # ^ This is the format for the data. # @todo: move this to config somehow (tbd) # Map real values to sample values samples = [] for i, t in enumerate(sample_times): real_x = 0 real_y = sample_data[i] real_z = 9.81 # Accel due to gravity # @todo: Apply a rotation matrix? # Map xyz = np.array((real_x, real_y, real_z)) # Add some noise (in G's) xyz += np.random.normal(self.noise_center, Units.SI(self.noise_scale), 3) xyz = np.interp(xyz, self.sensor_input_range, self.sensor_output_range) xyz = xyz.astype(int) samples.append(self.data(t, xyz[0], xyz[1], xyz[2], real_x, real_y, real_z)) #samples += self._get_gaussian_noise(samples, self.noise_center, self.noise_scale) return samples
def __init__(self, sim, config): self.sim = sim self.config = config # Physical # NOTE: @see diagram in http://confluence.rloop.org/display/SD/2.+Determine+Pod+Kinematics # For the track/tube reference frame, x=0 at the start of the track, and x = length at the end. # For the pod, x=0 is ahead and below the pod, with x+ being toward the read of the pod. self.length = Units.SI( config.length ) # meters -- Length from pod start position to end of track # Reference for the reflective stripes self.reflective_strip_width = Units.SI( config.reflective_strip_width) # meters (4 inches) self.reflective_pattern_interval = Units.SI( config.reflective_pattern_interval) # meters (100 feet) self.reflective_pattern_spacing = Units.SI( config.reflective_pattern_spacing ) # meters -- distance between stripes in a pattern self.track_gap_width = Units.SI( config.track_gap_width ) # Width of the gap in the subtrack in meters (probably worst scenario, more realistic 1-2 mm) self.track_gap_interval = Units.SI( config.track_gap_interval ) # Interval between the gaps in the subtrack in meters (Length of the aluminium plate) # Initialize self.reflective_strips = None # Will be a numpy array after initialization self._init_reflective_strips(config.enable_strip_patterns) self.reflective_strip_ends = self.reflective_strips + self.reflective_strip_width # Pre-calc the ends for use in LaserContrastSensor self.track_gaps = [] self._init_track_gaps()
def handle_device_update(self, device): if (datetime.datetime.now() - device.changed).seconds < (Config().get('calibration.update_calibration_data_after_mins') * 60): return for algo in device.algos: # Max update once a minute if algo['calibration_updated_at'] and \ (time.time() - algo['calibration_updated_at']) < 60: continue if len(algo['hashrate_readings']) >0: readings_a = [] readings_b = [] for reading in algo['hashrate_readings']: readings_a.append(reading[0]) readings_b.append(reading[1]) if '_' in algo['algo']: variance, n = self.get_variance(readings_a, readings_b) else: variance, n = self.get_variance(readings_a) if self.is_stable(variance, n): calibrated_data = self.get('%s.%s.%s' % (device.dclass, algo['miner'], algo['algo'])) if '_' in algo['algo']: nominal = [self.get_nominal_hashrate_from_range(readings_a), self.get_nominal_hashrate_from_range(readings_b)] else: nominal = self.get_nominal_hashrate_from_range(readings_a) if self.within_update_threshold(nominal, calibrated_data['hashrate']) and \ self.hashrate_is_visibly_different(nominal, calibrated_data['hashrate']): device.log('info', '%s[%s]: new calibrated rate: %s' % (algo['algo'], algo['miner'], Units().hashrate_str(nominal))) calibrated_data['hashrate'] = nominal self.update_calibration_data(device.dclass, algo['miner'], algo['algo'], nominal, calibrated_data['power_limit']) self.set("%s.%s.%s" % (device.dclass, algo['miner'], algo['algo']), calibrated_data) algo['calibration_updated_at'] = time.time()
def __init__(self, sim, config): ForceExerter.__init__(self, sim, config) self.name = 'F_lateral_stability' self.damping_coefficient = Units.SI(self.config.damping_coefficient)
class controller(object): ''' Controlls universe ''' def __init__(self): self.new_controller() def new_controller(self): ''' Inits controller. Usage: New Simulation ''' self.universe = Universe() # Holds the startpoint universe self.copy_universe = None # Folder where to save files and Default file name self.file_name = "test.xml" self.folder = "files/" self.filePath = None self.units = Units() self.pref_dict = {} self.timer_time = 10 self.steps_between_paint = 1 def create_object(self, name, mass, radius): ''' Creates Object and adds it to the current universe ''' uni_object = Uni_Object(name, mass, radius) self.universe.add_object(uni_object) return uni_object def delete_force(self, uni_object, delete_force_vector): ''' delete force from object ''' for i, force_vector in enumerate(uni_object.force_vector_list): if delete_force_vector == force_vector: uni_object.force_vector_list.pop(i) return True, 'Force removed' return False, 'Force not found' def delete_object(self, delete_uni_object): ''' delete object from universe ''' for i, uni_object in enumerate(self.universe.object_list): if delete_uni_object == uni_object: self.universe.object_list.pop(i) return True, 'Object removed' return False, 'Object not found' def validate_input(self, input_type, text, no_null = False): ''' If input text is invalid, returns default value ''' if input_type == 'string': if text == "": text = 'NONAME' elif input_type == 'int': if self.is_int(text): text = int(text) if no_null: if text == 0: text = 1 else: if no_null: text = 1 else: text = 0 elif input_type == 'float': if self.is_float(text): text = float(text) if no_null: if text == 0: text = 1.1 else: if no_null: text = 1.0 else: text = 0.0 return text def is_int(self, s): ''' Tests that given parameter is integer @return: Bool (True, if param is integer) ''' try: int(s) return True except ValueError: return False def is_float(self, s): ''' Tests that given parameter is float @return: Bool (True, if param is float) ''' try: float(s) return True except ValueError: return False def create_angle_force(self, uni_object, force, angle2d, angle3d): ''' Creates force vector from force and it's angles force,angle_xy,angle,xz => x,y,z (starting from the object location) ''' ( x, y, z ) = self.universe.maths.get_vector_xyz(force, angle2d, angle3d) force = Force_Vector(x, y, z) uni_object.add_force_vector(force) return force def set_object_angle_speed(self, uni_object, speed, angle2d, angle3d): ''' Sets object speed vector by transforming speed,angle_xy,angle,xz => x,y,z (starting from the object location) ''' ( x, y, z ) = self.universe.maths.get_vector_xyz(speed, angle2d, angle3d) uni_object.set_speed(x, y, z) def set_force_angle(self, force_vector, force, angle2d, angle3d): ''' Sets force vector by transforming speed,angle_xy,angle,xz => x,y,z (starting from the object location) ''' ( x, y, z ) = self.universe.maths.get_vector_xyz(force, angle2d, angle3d) force_vector.set_force(x, y, z) def get_object_angle_speed(self, uni_object): ''' Get speed vector in angle form ''' return self.universe.maths.xyz_to_angle(uni_object.speed_x, uni_object.speed_y, uni_object.speed_z) def get_object_force_speed(self, uni_object): ''' Get object force vector in angle form ''' return self.universe.maths.xyz_to_angle(uni_object.force_x, uni_object.force_y, uni_object.force_z) def get_force_angle(self, force_vector): ''' Get force vector in angle form ''' return self.universe.maths.xyz_to_angle(force_vector.x, force_vector.y, force_vector.z) def animate_step(self): ''' Simulates universe one step ''' self.universe.move_objects() def animate(self, obj_num, time): ''' Simulation is executed one year and it returns x-axis values divided by initial x-axis value from given object per month. Also step size is needed ''' running = True self.universe.maths.time = time status, message = self.set_startpoint() hour = round(3600.0 / self.universe.maths.time) day = round(hour*24.0) month = round(day*30.0) year = round(day*365.0) run_day = 0 message += "\n=============" while running: if (self.universe.step % day) == 0: run_day += 1 os.system("clear") print str(round((100 * self.universe.step / year),2)) + " % " if (self.universe.step % month) == 0: #print "month: " + str(self.controller.universe.step) x = self.universe.object_list[obj_num].x / self.copy_universe.object_list[obj_num].x x = str(x).replace(".",",") message += "\n" + x if self.universe.step > year: running = False self.animate_step() message += "\n=============" if status is True: message += "\nSimulation done. x-position monthly, over a year" return status, message def set_startpoint(self): ''' Sets startpoint for universe. It copies current in copy_universe ''' self.copy_universe = copy.deepcopy(self.universe) self.copy_universe.step = 0 self.copy_universe.calc_time = 0 return True, "Startpoint set" def reverse_startpoint(self): ''' Copies startpoint-universe as the current one. If no startpoint-universe is set, then nothing is done. ''' if self.copy_universe is not None: self.universe = copy.deepcopy(self.copy_universe) return True, "Startpoint reversed" return False, "No saved universe" def set_filePath(self, filePath): ''' For Qt filepath load/save ''' self.filePath = filePath def save(self): ''' Saves current simulation in file ''' self.pref_dict['paint'] = {'timer_time' : self.timer_time, 'steps_between_paint' : self.steps_between_paint } self.pref_dict['units'] = self.units.save_units() s = Dom_Save(self.pref_dict) s.add_universe(self.universe) if self.copy_universe is not None: s.add_universe(self.copy_universe) if self.filePath is None: return s.save_simulation(self.folder + self.file_name) return s.save_simulation(self.filePath) def load(self): ''' Loads simulation from file ''' l = Dom_Load() if self.filePath is None: filePath = self.folder + self.file_name else: filePath = self.filePath (uni_list, self.pref_dict) = l.load_simulation(filePath) if 'units' in self.pref_dict: self.units.load_units(self.pref_dict['units']) if 'paint' in self.pref_dict: self.timer_time = int(self.pref_dict['paint']['timer_time']) self.steps_between_paint = int(self.pref_dict['paint']['steps_between_paint']) if uni_list is not None: if len(uni_list) == 1: self.universe = uni_list[0] self.copy_universe = None elif len(uni_list) >= 2: self.universe = uni_list[0] self.copy_universe = uni_list[1] else: return False, "Not enough universe-objects" return True, "Load ok" return False, "File not found" def list_files_in_folder(self): ''' Returns files from file-folder ''' files = [] for f in os.listdir(self.folder): files.append(f) return files def not_empty(self): ''' Finds out if universe is empty and has no objects @return: Bool (true, if universe is empty) ''' if len(self.universe.object_list) > 0: return True return False
class Army(object): def __init__(self, units_config): self.units_config = units_config self.units = Units(units_config["units"]) self.allies = Allies(units_config["allies"]) self.battalions = Battalions(units_config["battalions"]) self.all = [self.units, self.allies, self.battalions] def __str__(self): line = [] for u in self.all: s = str(u) if s: line.append(s) return "{}: {}".format(self.points(), ", ".join(line)) def __repr__(self): return str(self.units) def __len__(self): return len(self.units) + len(self.allies) + len(self.battalions) def fullstr(self, rules_config={}): points = self.points() if rules_config: line = [ ("Points {} [{} to {}]".format(points, rules_config["points"] - points, rules_config["points"])) ] else: line = [("Points {}".format(points))] line.append( "\tWounds: {}, Models: {}, Bravery/Unit: {:.2f}, Save/Wound: {:.2f}+" .format(self.wounds(), self.unitsize(), self.avg_bravery_per_unit(), self.avg_save_per_wound())) for u in self.all: s = u.fullstr() if s: line.append(s) line.append("Roles: {}".format(self.sum_roles_str(rules_config))) line.append("") return "\n".join(line) def __getitem__(self, index): for u in self.all: if index < len(u): return u[index] index = index - len(u) raise IndexError("index out of range") def __setitem__(self, index, item): for u in self.all: if index < len(u): u[index] = item return index = index - len(u) raise IndexError("index out of range") def add(self, name, unittype): if unittype == "unit": self.units.add(name) elif unittype == "ally": self.allies.add(name) elif unittype == "battalion": self.battalions.add(name) else: raise KeyError('Invalid unit type') def points(self): x = 0 for u in self.all: x = x + u.points() return x def unitsize(self): x = 0 for u in self.all: x = x + u.unitsize() return x def wounds(self): x = 0 for u in self.all: x = x + u.wounds() return x def _bravery_sum(self): x = 0 for u in self.all: x = x + u._bravery_sum() return x def _save_mul_wounds_sum(self): x = 0 for u in self.all: x = x + u._save_mul_wounds_sum() return x def avg_bravery_per_unit(self): count = self.unitsize() if count == 0: return 0 return self._bravery_sum() / float(count) def avg_save_per_wound(self): count = self.wounds() if count == 0: return 0 return self._save_mul_wounds_sum() / float(count) def sum_roles(self, rules_config={}): r = {} for rulename, ruleactions in rules_config.get("units", {}).iteritems(): r[rulename] = 0 for u in self.all: u.sum_roles(r) return r def sum_roles_str(self, rules_config={}): roles = self.sum_roles(rules_config) line = [] for role, count in roles.iteritems(): rule = rules_config.get("units", {}).get(role, {}) if rule: if rule["max"] == -1: line.append("{} {} [{}+]".format(count, role, rule["min"])) else: line.append("{} {} [{}->{}]".format( count, role, rule["min"], rule["max"])) else: line.append("{} {}".format(count, role)) return ", ".join(line) def __check_min_max(self, constraint, current_value, default_min, default_max, restrict_config, final, showfails): con_min = restrict_config.get("min_" + constraint, default_min) con_max = restrict_config.get("max_" + constraint, default_max) if (current_value > con_max and con_max != -1) or (final and current_value < con_min): if showfails.value > PrintOption.SILENT.value: print "FAIL {}: {} {}->{} : {}".format(constraint, current_value, con_min, con_max, self) return False return True def is_valid(self, rules_config, restrict_config={}, final=True, showfails=PrintOption.SILENT): if not self.__check_min_max( "points", self.points(), rules_config["points"], rules_config["points"], restrict_config, final, showfails): return False if not self.__check_min_max("wounds", self.wounds(), 0, -1, restrict_config, final, showfails): return False if not self.__check_min_max("models", self.unitsize(), 0, -1, restrict_config, final, showfails): return False if not self.__check_min_max("allies", self.allies.points(), 0, rules_config["allies"], restrict_config, final, showfails): return False #Default battalions to off until better support added if not self.__check_min_max("battalions", self.battalions.num(), 0, 0, restrict_config, final, showfails): return False for u in self.all: if not u.is_valid(restrict_config, final, showfails): return False # Check roles rules_check = self.sum_roles(rules_config) for role, count in rules_check.iteritems(): # Check role meets min requirements if final and count < rules_config["units"][role]["min"]: if showfails.value > PrintOption.SILENT.value: print "FAIL Role MIN {} {} {} : {}".format( role, rules_config["units"][role]["min"], count, self) return False # Check role meets max requirements if rules_config["units"][role][ "max"] != -1 and count > rules_config["units"][role]["max"]: if showfails.value > PrintOption.SILENT.value: print "FAIL Role MAX {} {} {} : {}".format( role, rules_config["units"][role]["max"], count, self) return False return True
def __init__(self, units_config): self.units_config = units_config self.units = Units(units_config["units"]) self.allies = Allies(units_config["allies"]) self.battalions = Battalions(units_config["battalions"]) self.all = [self.units, self.allies, self.battalions]
def start(self, device, pool_name, miner, algorithm, region, quick=False, force=False): self.miner = miner self.device = device self.default_profile = Config().get('device_profiles.default') Miners().reload_config() device.pin = { 'pool_name': pool_name, 'miner_name': miner.name, 'algorithm': algorithm, 'region': region } if not Config().get('calibration'): Log().add('fatal', "calibration config missing from config file") for key in [ "hashrate_stabilisation_timeout_mins", "hashrate_stabilisation_tolerance", "hashrate_stabilisation_consecutive_readings_required", "algorithm_start_timeout" ]: if Config().get('calibration.%s' % (key)) == None: Log().add('fatal', "missing config option: calibration.%s" % (key)) if Config().get('calibration.power_tuning.enable'): for key in ["decrement_watts", "acceptable_loss_percent"]: if not Config().get('calibration.power_tuning.%s' % (key)): Log().add( 'fatal', "missing config option: calibration.power_tuning.%s" % (key)) Config().set('pools.%s.append_device_id_to_worker_name' % (pool_name), False) if pool_name == 'miningpoolhub': if Config().get('pools.miningpoolhub.hub_workers.%s' % (algorithm))[-5:] != 'CALIB': Config().set( 'pools.miningpoolhub.hub_workers.%s' % (algorithm), Config().get('pools.miningpoolhub.hub_workers.%s' % (algorithm)) + 'CALIB') else: if Config().get('pools.%s.worker_name' % (pool_name))[-5:] != 'CALIB': Config().set( 'pools.%s.worker_name' % (pool_name), Config().get('pools.%s.worker_name' % (pool_name)) + "CALIB") if quick: Config().set('calibration.power_tuning.enable', False) profile = Profiles().get_for_device_algo(device, algorithm) Log().add('info', ' device id: %d' % (device.id)) Log().add('info', ' pool: %s' % (pool_name)) Log().add('info', ' device class: %s' % (device.dclass)) Log().add('info', 'device profile: %s' % (profile.name)) Log().add('info', ' miner: %s' % (miner.name)) Log().add('info', ' algorithm: %s' % (algorithm)) Log().add('info', ' region: %s' % (region)) Miners().poll() Miners().get_device_state(device) if device.state != 'inactive': if device.state == 'calibrating': device.log( 'fatal', 'this device is already being used for calibration') if force: device.log('info', 'terminating existing worker') if not device.stop(True): device.log('fatal', 'failed to stop existing worker') else: device.log( 'fatal', 'unable to start calibration - device is in use (use --force to override)' ) self.set_pin(device.id) default_power_limit = device.default_power_limit_f min_power_limit = device.min_power_limit_f max_power_limit = device.max_power_limit_f if max_power_limit == 0: device.log('info', 'device does not support power monitoring') else: device.log('info', 'max power limit: %d W' % (max_power_limit)) device.log( 'info', 'stabilisation tolerance: %.2f%%' % (Config().get('calibration.hashrate_stabilisation_tolerance'))) if Config().get('debug'): device.log('debug', 'loading default profile') Nvidia().set_default_profile(device) if Config().get('debug'): device.log('debug', 'initialising pools') Pools() sample_timeout = Config().get( 'calibration.hashrate_stabilisation_timeout_mins') if default_power_limit != None and Config().get( 'calibration.power_tuning.enable'): device.log( 'info', 'starting initial run at max power limit [timeout=%dmins]' % (sample_timeout)) else: device.log( 'info', 'starting single run [timeout=%dmins]' % (sample_timeout)) Miners().poll() Miners().get_device_state(device) if device.state != 'calibrating': if not device.start(True): device.log('fatal', 'worker failed to start') if Config().get('calibration.power_tuning.enable'): if not device.power_supported(): device.log('info', 'device does not support power monitoring') else: device.set_power_limit(max_power_limit) initial_hashrate, initial_max_power_draw = self.get_max_hashrate_and_power_draw( miner, device, sample_timeout * 60) if initial_hashrate == None: device.log( 'info', 'skipping algorithm as we failed to get a stable reading') print "" return if initial_max_power_draw != None and initial_max_power_draw > max_power_limit: initial_max_power_draw = max_power_limit device.log( 'info', 'benchmark hashrate: %s' % (Units().hashrate_str(initial_hashrate))) if initial_max_power_draw != None: device.log('info', 'max power draw: %.2f' % (initial_max_power_draw)) initial_power_limit = int(math.ceil(initial_max_power_draw)) hashrate = initial_hashrate if initial_max_power_draw == None: power_limit = None elif Config().get('calibration.power_tuning.enable'): if max_power_limit == 0 or min_power_limit == 0 or default_power_limit == 0: device.log( 'error', 'device did not give us sane values for its min/max/default power limits' ) device.log( 'error', 'unable to proceed with power calibration - device may not support changing the power limit' ) power_limit = default_power_limit else: power_limit = initial_power_limit device.log('info', 'tuning power limit for optimum efficiency') hashrate, power_limit = self.do_power_calibration( device, power_limit, miner, hashrate, min_power_limit) else: power_limit = default_power_limit Nvidia().set_default_profile(device) self.unset_pin(device.id) device.log('info', 'storing calibration data') Calibration().update_calibration_data(device.dclass, miner.name, algorithm, hashrate, power_limit) if not device.stop(True): device.log('fatal', "failed to stop the miner process") print "" device.log( 'info', ' calibrated hashrate: %s' % (Units().hashrate_str(hashrate))) if power_limit != None: device.log('info', 'calibrated power limit: %.2f W' % (power_limit)) print ""
def __init__(self, sim, config): self.sim = sim self.config = config self.logger = logging.getLogger("Brake") # Limit Switches # Switch activation: We only want to call the callback when the switch is tripped, not repeatedly self.retract_sw_activated = False self.extend_sw_activated = False # Volatile #self.gap = Units.SI(self.config.initial_gap) # @todo: make this work # Rail Gap # Screw pos is the main value from which we calculate the gap and MLP values. [0, 75000]um fully retracted to fully extended (maps to brake gap) # Note: screw position is updated by the callback from the FCU self.gap = Units.SI(self.config.gap.initial_gap) #print "Gap after conversion is {}".format(self.gap) #exit() self.retracted_gap = Units.SI(self.config.gap.retracted_gap) self.extended_gap = Units.SI(self.config.gap.extended_gap) self.gap_range = [self.retracted_gap, self.extended_gap] # Screw self.screw_limit_sw_retract = Units.SI( self.config.lead_screw.limit_sw_retract) self.screw_limit_sw_extend = Units.SI( self.config.lead_screw.limit_sw_extend) self.screw_range = [ self.screw_limit_sw_retract, self.screw_limit_sw_extend ] # Calculate initial screw position from the initial gap (note: during processing it's the other way around) self.screw_pos = np.interp(self.gap, self.gap_range, self.screw_range) # Linear Position Sensor # @todo: check this to make sure the min/max are in the correct order -- should be retracted->extended self.mlp_range = [self.config.mlp.raw_min, self.config.mlp.raw_max] # Calculate raw MLP value from the screw position print("{}, {}, {}".format(self.screw_pos, self.screw_range, self.mlp_range)) self.mlp_raw = np.interp(self.screw_pos, self.screw_range, self.mlp_range) # Negator self.negator_torque = Units.SI(self.config.negator.torque) # TESTING ONLY self._gap_target = self.gap # Initialize to current value so we don't move yet self._gap_close_time = Units.SI(self.config.gap_close_min_time) self._gap_close_dist = self.retracted_gap - self.extended_gap self._gap_close_speed = self._gap_close_dist / self._gap_close_time # meters/second -- this is just a guess -- .007 m/s = closing 21mm in 3s #self.logger.debug("Brake gap close speed: {} m/s".format(self._gap_close_speed)) # /TESTING self.normal_force = 0.0 # N -- normal against the rail; +normal is away from the rail self.drag_force = 0.0 # N -- drag on the pod; -drag is toward the back of the pod self.last_normal_force = 0.0 self.last_drag_force = 0.0 # Lead Screw # revs per cm=2.5 There are 4 mm per single lead so 2.5 turns move the carriage 1 cm # Formulas: http://www.nookindustries.com/LinearLibraryItem/Ballscrew_Torque_Calculations self.screw_pitch = Units.SI(self.config.lead_screw.pitch) self.drive_efficiency = self.config.lead_screw.drive_efficiency self.backdrive_efficiency = self.config.lead_screw.backdrive_efficiency # Lead Screw Precalculated Values self._drive_torque_multiplier = self.screw_pitch / ( self.drive_efficiency * 2 * 3.14) self._backdrive_torque_multiplier = ( self.screw_pitch * self.backdrive_efficiency) / (2 * 3.14)
def hashrate_str(self): if self.algos[0]['algo'] in Config().get('algorithms.single'): return Units().hashrate_str(self.algos[0]['hashrate'][0]) return Units().hashrate_str(self.algos[0]['hashrate'])
def do_power_calibration(self, device, power_limit, miner, initial_hashrate, min_power_limit): sample_timeout = Config().get( 'calibration.hashrate_stabilisation_timeout_mins') acceptable_loss_pc = Config().get( 'calibration.power_tuning.acceptable_loss_percent') dial_back = False dialed_back = False hashrate = initial_hashrate if "_" in device.algos[0]['algo']: initial_value = initial_hashrate[0] else: initial_value = initial_hashrate while True: if dial_back: power_limit += Config().get( 'calibration.power_tuning.decrement_watts') / 2 dialed_back = True else: power_limit -= Config().get( 'calibration.power_tuning.decrement_watts') if power_limit < min_power_limit: power_limit = min_power_limit device.log('info', 'setting power limit: %d W' % (power_limit)) device.set_power_limit(power_limit) new_hashrate, max_power_draw = self.get_max_hashrate_and_power_draw( miner, device, sample_timeout * 60) if new_hashrate == None: device.log( 'info', 'skipping algorithm as we failed to get a stable reading') print "" return if "_" in device.algos[0]['algo']: new_value = new_hashrate[0] else: new_value = new_hashrate device.log( 'info', 'nominal hashrate: %s' % (Units().hashrate_str(new_hashrate))) if new_value > initial_value: device.log('info', 'hashrate is higher than before, w00t!') hashrate = new_hashrate initial_value = new_value elif new_value >= (initial_value - (initial_value / 100) * acceptable_loss_pc): hashrate = new_hashrate if power_limit == min_power_limit or dial_back: device.log( 'info', 'hashrate loss is within acceptable %.2f%%' % (acceptable_loss_pc)) else: device.log( 'info', 'hashrate loss is within acceptable %.2f%%, continuing' % (acceptable_loss_pc)) else: if dial_back or Config().get( 'calibration.power_tuning.decrement_watts') == 1: device.log( 'info', 'hashrate still below our acceptable loss level of %.2f%%, stopping' % (acceptable_loss_pc)) if Config().get( 'calibration.power_tuning.decrement_watts') == 1: power_limit += 1 else: power_limit += Config().get( 'calibration.power_tuning.decrement_watts') / 2 break else: device.log( 'info', 'hashrate fell below our acceptable loss level of %.2f%%, dialling back %d W' % (acceptable_loss_pc, Config().get( 'calibration.power_tuning.decrement_watts') / 2)) dial_back = True if dialed_back: break if power_limit == min_power_limit and not dial_back: device.log('info', 'minimum power limit reached, stopping') break return [hashrate, power_limit]
def __init__(self, sim, config): ForceExerter.__init__(self, sim, config) self.name = 'F_aero' # @see http://www.softschools.com/formulas/physics/air_resistance_formula/85/ self.air_resistance_k = Units.SI(self.config.air_density) * self.config.drag_coefficient * Units.SI(self.config.drag_area) / 2
def testElEncToDeg(self): p = Units() self.failUnless(p.encoder_to_El(10)==1110)
def __init__(self): self.converter = Units()
def resistance(self): """Return a succinct string representing the resistance of this Resistor. e.g. '23.6KΩ' """ return str(Units.ohms(self.ohms))
def testAzEncToDeg(self): p = Units() self.failUnless(p.encoder_to_Az(10)==28440)
def __init__(self, sim, config): self.logger = logging.getLogger("Pod") self.logger.info("Initializing pod") self.sim = sim self.config = config self.name = 'pod_actual' self.step_listeners = [] self.step_forces = OrderedDict( ) # This will be filled in during each step # Pod physical properties # *** NOTE: all distances are in the track/tube reference frame, origin is pod location reference (centerpoint of fwd crossbar). +x is forward, +y is left, +z is up. # @see http://confluence.rloop.org/display/SD/2.+Determine+Pod+Kinematics self.mass = Units.SI(self.config.mass) self.pusher_plate_offset = Units.SI( self.config.physical.pusher_plate_offset) self.pusher_pin_travel = Units.SI( self.config.physical.pusher_pin_travel) # Forces that can act on the pod (note: these are cleared at the end of each step) self.net_force = np.array( (0.0, 0.0, 0.0) ) # Newtons; (x, y, z). +x pushes the pod forward, +z force lifts the pod, y is not currently used. # Initialize actual physical values (volatile variables). All refer to action in the x dimension only. self.acceleration = Units.SI( self.config.acceleration) or 0.0 # meters per second ^2 self.velocity = Units.SI( self.config.velocity) or 0.0 # meters per second self.position = Units.SI( self.config.position ) or 0.0 # meters. Position relative to the track; start position is 0m # @todo: this is just a sketch, for use with the hover engine calculations. Maybe switch accel, velocity, and position to coordinates? hmmmm... self.z_acceleration = 0.0 self.z_velocity = 0.0 self.he_height = Units.SI( self.config.landing_gear.initial_height ) # This should be gotten from the starting height of the lift mechanism self._initial_he_height = self.he_height # @todo: Remove this -- it's only used as a temporary block from going through the floor until the landing gear is implemented self.elapsed_time_usec = 0 # Values from the previous step (for lerping and whatnot) self.last_acceleration = 0.0 self.last_velocity = 0.0 self.last_position = 0.0 self.last_he_height = 0.0 # Handle forces that act on the pod """ self.forces = [] self.forces.append( AeroForce(self.sim, self.config.forces.aero) ) self.forces.append( BrakeForce(self.sim, self.config.forces.brakes) ) self.forces.append( GimbalForce(self.sim, self.config.forces.gimbals) ) self.forces.append( HoverEngineForce(self.sim, self.config.forces.hover_engines) ) self.forces.append( LateralStabilityForce(self.sim, self.config.forces.lateral_stability) ) self.forces.append( LandingGearForce(self.sim, self.config.forces.landing_gear) ) """ self.force_exerters = OrderedDict() self.force_exerters['aero'] = AeroForce(self.sim, self.config.forces.aero) self.force_exerters['brakes'] = BrakeForce(self.sim, self.config.forces.brakes) self.force_exerters['gimbals'] = GimbalForce( self.sim, self.config.forces.gimbals) self.force_exerters['hover_engines'] = HoverEngineForce( self.sim, self.config.forces.hover_engines) self.force_exerters['lateral_stability'] = LateralStabilityForce( self.sim, self.config.forces.lateral_stability) self.force_exerters['landing_gear'] = LandingGearForce( self.sim, self.config.forces.landing_gear) # Forces applied during the step (for recording purposes) # @todo: Maybe initialize these to ForceExerter.data(0,0,0)? self.step_forces = OrderedDict() self.step_forces['aero'] = ForceExerter.data(0, 0, 0) self.step_forces['brakes'] = ForceExerter.data(0, 0, 0) self.step_forces['gimbals'] = ForceExerter.data(0, 0, 0) self.step_forces['hover_engines'] = ForceExerter.data(0, 0, 0) self.step_forces['lateral_stability'] = ForceExerter.data(0, 0, 0) self.step_forces['landing_gear'] = ForceExerter.data(0, 0, 0) # Pre-calculated values # HE Drag """ Drag for a single hover engine (keep in mind that we have 8): Constants: w: Comes from solving 3d maxwell's equations (@whiplash) and using other fancy math -- provided by @whiplash -- not dependent on velocity, just depends on magnetic characteristics mu_0: Absolute permeability of the vacuum (constant) -- permeability constant, magnetic constant, etc. -- permeability of free space m: Magnetic dipole strength (constant, but depends on how magnets are arranged) h: thickness of conducting material (rail in this case) rho: density of conducting material (aluminum in this case) Variables: z_0: Distance between magnet and conducting surface v: Velocity Calculated: w = 2 * rho / (mu_0 * h) F_lift / F_drag = v / w F_lift = ((3 * mu_0 * m**2) / (32 * 3.14159 * z_0**4)) * (1 - w * (v**2 + w**2)**(-1/2)) Values (from @whiplash): mu_0: 4 pi x10e-7 rho: 2.7 g/cubic centimeter h: 0.5 in m: (@whiplash will need to calculate this -- it's a vector quantity, need to draw a magnetic circuit) """ # Brakes #self.brakes = [] #for brake_config in self.config.brakes: # self.brakes.append(Brake(self.sim, brake_config)) self.brakes = Brakes(self.sim, self.config.brakes) """ Sketch:
args_cli = pytools.parse_args() var = args_cli.var #confs = [ "gam3.ini", ] confs = [ args_cli.conf_filename, ] for conf_filename in confs: conf = Configuration(conf_filename, do_print=True) # restructure path to point to this dir fdir = conf.outdir print(fdir) units = Units(conf) #-------------------------------------------------- # read data flds_Epar = [] flds_Eperp = [] flds_Bpar = [] flds_Bperp = [] flds_Jpar = [] flds_Jperp = [] flds_time = [] flds_tot = []
def get_local_data(self, minimal=False): data = [] devices = nvidia.Nvidia().get_nvidia_devices(1, True) Miners().poll() if not minimal and os.path.exists( self.power_file) and os.path.getsize(self.power_file) > 0: power_draw_readings = pickle.loads(open(self.power_file).read()) else: power_draw_readings = [] if not minimal and os.path.exists( self.profitability_file) and os.path.getsize( self.profitability_file) > 0: profitability_readings = pickle.loads( open(self.profitability_file).read()) else: profitability_readings = [] Calibration().load() total_mbtc = 0 total_power = 0 total_power_limit = 0 power_values = {} power_limit_values = {} for device in devices: device.algos = [] Miners().get_device_state(device) mbtc_per_day_values = [0] algos = device.algos if len(algos) == 0: algos = ['IDLE'] for algo_i in range(0, len(algos)): algo = algos[algo_i] if algo_i == 0: omit_fields = False else: omit_fields = True if algo == 'IDLE': algo = "IDLE" algo1 = "IDLE" rate_s = "-" mbtc_per_day = 0 miner = '-' region = '-' pool = '-' _time = '-' else: algo1 = algo['algo'] miner = algo['miner'] region = algo['region'] pool = algo['pool'] _pool = Pools().pools[pool] if os.path.exists("/tmp/.minotaur.%d" % (device.id)): _time = Units().to_timestr( int(time.time() - os.stat("/tmp/.minotaur.%d" % (device.id)).st_mtime)) else: _time = '-' rate_a, rate_b = algo['hashrate'] if algo['algo'] in Config().get('algorithms')['double']: rate_s = Units().hashrate_str(rate_a) rate_s2 = Units().hashrate_str(rate_b) benchmarks = {algo['algo']: [rate_a, rate_b]} algo1, algo2 = algo['algo'].split("_") mbtc_per_day_values = [ _pool.mbtc_per_day( benchmarks, 'cached')[algo['region']][algo['algo']] ] else: rate_s = Units().hashrate_str(rate_a) benchmarks = {algo['algo']: rate_a} if algo['algo'] in _pool.mbtc_per_day( benchmarks, 'cached')[algo['region']].keys(): mbtc_per_day_values = [ _pool.mbtc_per_day( benchmarks, 'cached')[algo['region']][algo['algo']] ] else: mbtc_per_day_values = [0] if pool != '-': pool = _pool.shortened(region) metrics = device.to_hash() metrics.pop('changed', None) metrics['miner'] = miner metrics['region'] = region metrics['pool'] = pool metrics['time'] = _time metrics['omit_fields'] = omit_fields if metrics['fan']: metrics['fan'] = str(metrics['fan']).rjust(3) + " %" if metrics['miner']: metrics['miner'] = metrics['miner'][0:5] else: metrics['miner'] = '-' if algo == "IDLE": if metrics['gpu_u_i'] and metrics['gpu_u_i'] >= 90: algo = ".pending." algo1 = ".pending." rate_s = ".." mbtc_per_day = mbtc_per_day_values[0] metrics['host'] = 'local' metrics['id'] = device.id metrics[" algo"] = algo1 metrics["rate"] = rate_s metrics[" mBTC/day"] = ("%.2f" % (mbtc_per_day)).rjust(5) if not metrics['region']: metrics['region'] = '-' total_mbtc += sum(mbtc_per_day_values) if metrics['power_f']: power_values[metrics['id']] = metrics['power_f'] margin = self.calculate_profit_margin_for_card( sum(mbtc_per_day_values), metrics['power_f']) net_mbtc = (mbtc_per_day / 100) * margin if margin < 0: margin = 0 margin_s = "%d%%" % (int(margin)) metrics[" mBTC/day"] += "/" metrics[" mBTC/day"] += ("%.2f" % (net_mbtc)).rjust(5) metrics[" mBTC/day"] += " %s" % (margin_s.rjust(4)) else: margin = 0 if margin > 0: metrics["margin"] = "%.1f%%" % (margin) else: metrics["margin"] = "-" if metrics['limit_f']: power_limit_values[metrics['id']] = metrics['limit_f'] if device.state == 'calibrating': metrics[' algo'] = '*' + metrics[' algo'] elif device.get_pin() and 'algorithm' in device.get_pin().keys( ) and device.get_pin()['algorithm'] == metrics[' algo']: metrics[' algo'] = '+' + metrics[' algo'] elif device.get_pin() and 'algorithm' in device.get_pin().keys( ) and '_' in device.get_pin()['algorithm'] and metrics[ ' algo'] in device.get_pin()['algorithm'].split('_'): metrics[' algo'] = '+' + metrics[' algo'] else: metrics[' algo'] = ' ' + metrics[' algo'] if metrics['gpu_f']: match = re.match("^([\d]+)", metrics['gpu_f']) if match: metrics['gpu_f'] = match.group(1) else: metrics['gpu_f'] = '-' else: metrics['gpu_f'] = '-' if metrics['mem_f']: match = re.match("^([\d]+)", metrics['mem_f']) if match: metrics['mem_f'] = match.group(1) else: metrics['mem_f'] = '-' else: metrics['mem_f'] = '-' metrics['ps clocks'] = "%s %s/%s MHz" % ( metrics['ps'], metrics['gpu_f'], metrics['mem_f']) power = re.match("^([\d]+)", metrics['power']) limit = re.match("^([\d]+)", metrics['limit']) if power and limit: metrics['power'] = "%s/%s W" % (power.group(1), limit.group(1)) else: metrics['power'] = '-' data.append(metrics) if algo not in [ 'IDLE', '.pending.' ] and algo['algo'] in Config().get('algorithms.double'): mbtc_per_day = mbtc_per_day_values[1] metrics2 = metrics.copy() metrics2[" algo"] = algo2 metrics2["rate"] = rate_s2 metrics2[" mBTC/day"] = ("%.2f" % (mbtc_per_day)).rjust(5) net_mbtc = (mbtc_per_day / 100) * margin metrics2[" mBTC/day"] += "/" metrics2[" mBTC/day"] += ("%.2f" % (net_mbtc)).rjust(5) metrics2[" mBTC/day"] += " %s" % (margin_s.rjust(4)) if device.state == 'calibrating': metrics2[" algo"] = '*' + metrics2[' algo'] elif device.get_pin() and '_' in device.get_pin( )['algorithm'] and metrics2[' algo'] in device.get_pin( )['algorithm'].split('_'): metrics2[" algo"] = '+' + metrics2[' algo'] else: metrics2[" algo"] = ' ' + metrics2[' algo'] data.append(metrics2) total_power = sum(power_values.values()) total_power_limit = sum(power_limit_values.values()) electric_cost_mbtc = self.get_electricity_cost( total_power + Config().get('system_draw_watts'), True, Config().get('electricity_per_kwh')) net_mbtc = total_mbtc - electric_cost_mbtc return [ data, total_mbtc, net_mbtc, total_power, total_power_limit, power_draw_readings, profitability_readings ]