예제 #1
0
class RampRunner(object):
    """The RampRunner. Program to run current and voltage measurements and log measurements
    of voltage, current, temperature, pressure and flow to the surfcat database.    
    """

    def __init__(self):
        # Initialize power supply
        # Initialize flow meter driver
        """Try to connect to the COM port of the flow meter and ask for the serial number"""
        print("Try and connect to red flow meter")
        try:
            self.red_flow_meter = RedFlowMeter(ramp.RED_FLOW_METER_COM_PORT, slave_address=42)
        except SerialException:
            message = 'Cannot find red flow meter on {}'.format(ramp.RED_FLOW_METER_COM_PORT)
            raise RuntimeError(message) 
    
        # Test serial number reply
        if self.red_flow_meter.read_value('serial') != 210059:
            raise RuntimeError('Incorrect reply to serial number')
    
        # Print actual flow value
        print(self.red_flow_meter.read_value('fluid_name'), self.red_flow_meter.read_value('flow'))
        # If more flow meters are used try them here
        #self.red_flow_meter.set_address(247)
        #print(self.red_flow_meter.read_value('fluid_name'), self.red_flow_meter.read_value('flow'))
        
        # Try to conect to power supply 
        print("Try and connect to power supply")
        try:
            self.cpx = CPX400DPDriver(output=1, interface='serial', device=ramp.POWER_SUPPLY_COM_PORT)
        except SerialException:
            message = 'Cannot find power supply on {}'.format(ramp.POWER_SUPPLY_COM_PORT)
            raise RuntimeError(message)
    
        if 'CPX400DP' not in self.cpx.read_software_version():
            raise RuntimeError('Incorrect software version reply')
            pass
        
        # Print the set point voltage
        print("The voltage set point is {}".format(self.cpx.read_set_voltage()))
        
        self.ramp = ramp.RAMP
        self.metadata = ramp.metadata
        self.area = ramp.area
        self.setpoint_pressure = ramp.setpoint_pressure
        self.setpoint_gas_flow = ramp.setpoint_gas_flow
        self.verify_ramp()
        self.data_set_saver = DataSetSaver(
            'measurements_large_CO2_MEA',
            'xy_values_large_CO2_MEA',
            credentials.USERNAME,
            credentials.PASSWORD,
        )
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.settimeout(0.1)
        self.host = ramp.RASPPI_HOST
        self.port = ramp.RASSPI_PORT
        self.message = 'json_wn#' + json.dumps({'no_voltages_to_set':True})
        

    def verify_ramp(self):
        """Verify the ramp for consistency and safety"""        
        for step in self.ramp:
            
            # Check if a contant voltage step has the right keys
            if step['type'] == 'constant_voltage':
                required_keys = {'type','duration','end_voltage', 'save_rate'}
                if step.keys() != required_keys:
                    raise RuntimeError('The keys must in a constant voltage step must be\
                                       {}'.format(required_keys))
                    
            # Check if a voltage ramp step has the right keys     
            elif step['type'] == 'voltage_ramp':
                required_keys = {'type', 'duration',\
                                 'start_voltage', 'end_voltage', 'voltage_step', 'save_rate'}
                if step.keys() != required_keys:
                    raise RuntimeError('The keys must in a constant voltage step must be\
                                       {}'.format(required_keys))
                elif step['start_voltage'] < 0: 
                    raise RuntimeError('Voltage must be must be positive and less than 5V, got: {}V'\
                                   .format(step['end_voltage']))
                elif step['end_voltage'] > 5:
                    raise RuntimeError('Voltage must be must be positive and less than 5V, got: {}V'\
                                   .format(step['end_voltage']))
                    
            elif step['type'] == 'constant_current':
                required_keys = {'type', 'duration',\
                                 'current_density', 'save_rate'}
                if step.keys() != required_keys:
                    raise RuntimeError('The keys must in a constant voltage step must be\
                                       {}'.format(required_keys))
                elif step['current_density'] < 0: 
                    raise RuntimeError('Current density must be positive, got: {}mA/cm2'\
                                   .format(step['current_density']))
            
            # Do checks on the common keys
            elif step['duration'] <= 0: 
                raise RuntimeError('Duration must be positive, got: {}'.format(step['duration']))
            # Check that the voltage is greater than 0 
            elif step['end_voltage'] < 0: 
                raise RuntimeError('Voltage must be must be positive and less than 5V, got: {}V'\
                                   .format(step['end_voltage']))
            #...and less than 5V
            elif step['end_voltage'] > 5:
                raise RuntimeError('Voltage must be must be positive and less than 5V, got: {}V'\
                                   .format(step['end_voltage']))
            # Check if the rate at which the data should be saved is positive.
            elif step['save_rate'] <=0:
                raise RuntimeError('The save rate must be positive, got: {}'.format(step['save_rate']))
            

    def run(self):
        """Run the ramp
        
        This is the main function that contains a loop over the steps in the ramp and the
        method that does all the work
        """
        
        self.data_set_saver.start()
        # Specify the start time for database
        now = time()
        now_custom_column = CustomColumn(now, 'FROM_UNIXTIME(%s)')
        
        # Add all measurements
        self.metadata['label'] = 'voltage'
        self.data_set_saver.add_measurement('voltage', self.metadata)
        self.metadata['label'] = 'current'
        self.data_set_saver.add_measurement('current', self.metadata)
        self.metadata['label'] = 'CO2 flow'
        self.data_set_saver.add_measurement('CO2 flow', self.metadata)
        # If another flow meter is used collect the flow here
        #self.metadata['label'] = 'cell outlet flow'
        #self.data_set_saver.add_measurement('cell outlet flow', self.metadata)
        # Collect the pressure reading from the pressure controller
        #self.metadata['label'] = 'pressure'
        #self.data_set_saver.add_measurement('pressure', self.metadata)
        # Add the one custom column
        self.metadata['time'] = now_custom_column
        
        # Set the current limit on the power supply to 10A
        self.cpx.set_current_limit(10)
        
        # Change address to CO2 flow controller
        self.red_flow_meter.set_address(42)
        # Set the CO2 flow to the specified value 
        self.red_flow_meter.write_value('setpoint_gas_flow', self.setpoint_gas_flow)
        
        
        # Set the pressure on the pressure controller
        #self.message = 'json_wn#' + json.dumps({'A': 0.0, 'B': self.setpoint_pressure })
        #self.sock.sendto(message.encode('ascii'), (self.host, self.port))
        
        try:
            for step in self.ramp:
                # Go through the steps in the ramp file
                if step['type'] == 'constant_voltage':
                    self.run_constant_voltage_step(step)
                elif step['type'] == 'voltage_ramp':
                    self.run_voltage_ramp_step(step)
                elif step['type'] == 'constant_current':
                    self.run_constant_current_step(step)
        except KeyboardInterrupt:
            print('Program interupted by user')
        finally:
            # End the data collection and turn off power supply after run or interruption
            print('The program has ended')
            self.cpx.output_status(False)
            self.red_flow_meter.set_address(42)
            self.red_flow_meter.write_value('setpoint_gas_flow', 0.0)
            #self.message = 'json_wn#' + json.dumps({'A': 0.0, 'B': 0.0})
            #self.sock.sendto(message.encode('ascii'), (self.host, self.port))
            self.data_set_saver.wait_for_queue_to_empty()
            self.data_set_saver.stop()
        
        

    def run_constant_voltage_step(self, step):
        """Run a single step"""
        print('Run constant voltage step with parameters', step)
        start_time = time()  # Read from step
                
        # Set voltage on power supply
        voltage_difference_limit = 0.01
        print("Setting voltage to {} V".format(step["end_voltage"]))
        self.cpx.set_voltage(step["end_voltage"])
        while abs(step["end_voltage"]-self.cpx.read_set_voltage())>voltage_difference_limit:
            print(self.cpx.read_set_voltage())
            pass
        
        # Turn on the power supply
        self.cpx.output_status(True)
        
        last_save = 0
        # Read of the flow and current as long as the duration lasts
        while (time() - start_time) < step['duration']*3600:
            # Log results to database
            
            # Send communication to datacard
            self.sock.sendto(self.message.encode('ascii'), (self.host, self.port))
            try:
                reply = self.sock.recv(1024).decode('ascii')
            except socket.timeout:
                pass
            else:
                # This is the data collection rate right now
                sleep(step['save_rate'])
                now = time()
                
                # Read voltage on power supply
                power_supply_voltage = self.cpx.read_actual_voltage()
                print('The voltage is: {}V on the power supply'.format(power_supply_voltage))
                
                # Read actual voltage on raspberry pi
                reply_data = json.loads(reply[4:])
                actual_voltage = reply_data['3']
                print('The voltage is: {}V on the cell'.format(actual_voltage))
                #pressure = reply_data['1']
                # Read the current from the power supply
                actual_current  = self.cpx.read_actual_current()
                print('The current is: {}A'.format(actual_current))
                
                # Change address to CO2 flow meter
                self.red_flow_meter.set_address(42)
                
                # Get the CO2 flow from the MFC
                CO2_flow = self.red_flow_meter.read_value('flow')
                
                # If another flow meter is used collect the flow here
                #self.red_flow_meter.set_address(247)
                # Get the flow from the cell into the GC from the MFM
                #cell_outlet_flow = self.red_flow_meter.read_value('flow')
                
                # time between data is saved
                print('Time since last save: {}s'.format(time()-last_save))
                last_save = time()
                
                # Save the measurements to the database
                self.data_set_saver.save_point('voltage', (now, actual_voltage))
                self.data_set_saver.save_point('current', (now, actual_current))
                self.data_set_saver.save_point('CO2 flow', (now, CO2_flow))
                #self.data_set_saver.save_point('CO2 flow', (now, pressure))
                #self.data_set_saver.save_point('cell outlet flow', (now, cell_outlet_flow))
        
    def run_constant_current_step(self, step):
        """Run a single step"""
        print('Run constant current step with parameters', step)
        start_time = time()  # Read from step
        
        # Change address to CO2 flow meter
        self.red_flow_meter.set_address(42)
        # Set current limit on power supply and set a high voltage to hit the limit
        # and let the power supply control the voltage
        current_density = step['current_density'] # in mA
        # Calculate the current from the corresponding area and corrent density
        current = current_density/1000*self.area
        print("Setting current to {}A".format(current))
        self.cpx.set_current_limit(current)
        self.cpx.set_voltage(4)
        # Turn on the power supply
        self.cpx.output_status(True)
        #self.red_flow_meter.write_value('setpoint_gas_flow', step['setpoint_gas_flow'])
        last_save = 0
        # Read of the flow and current as long as the duration lasts
        while (time() - start_time) < step['duration']*3600:
            # Log results to database
            
            # Send communication to datacard
            self.sock.sendto(self.message.encode('ascii'), (self.host, self.port))
            try:
                reply = self.sock.recv(1024).decode('ascii')
            except socket.timeout:
                pass
            else:
                # This is the data collection rate right now
                sleep(step['save_rate'])
                now = time()
                
                # Read voltage on power supply
                power_supply_voltage = self.cpx.read_actual_voltage()
                print('The voltage is: {}V on the power supply'.format(power_supply_voltage))
                
                # Read actual voltage on raspberry pi
                reply_data = json.loads(reply[4:])
                actual_voltage = reply_data['3']
                print('The voltage is: {}V on the cell'.format(actual_voltage))
                #pressure = reply_data['1']
                # Read the current from the power supply
                actual_current  = self.cpx.read_actual_current()
                print('The current is: {}A'.format(actual_current))
                
                # Change address to CO2 flow controller
                self.red_flow_meter.set_address(42)
                # Get the CO2 flow from the MFM
                CO2_flow = self.red_flow_meter.read_value('flow')
                # If another flow meter is used collect the flow here
                # Change adress to the cell outlet MFM
                #self.red_flow_meter.set_address(247)
                # Get the CO2 flow from the MFM
                #cell_outlet_flow = self.red_flow_meter.read_value('flow')
                # time between data is saved
                print('Time since last save: {}s'.format(time()-last_save))
                last_save = time()
                
                # Save the measurements to the database
                self.data_set_saver.save_point('voltage', (now, actual_voltage))
                self.data_set_saver.save_point('current', (now, actual_current))
                self.data_set_saver.save_point('CO2 flow', (now, CO2_flow))
                #self.data_set_saver.save_point('pressure', (now, pressure))
                #self.data_set_saver.save_point('cell outlet flow', (now, cell_outlet_flow))

    def run_voltage_ramp_step(self, step):
        """ Run voltage ramp step"""
        print('Run voltage ramp step with parameters', step)
        # Start time of this step for reference
        start_time = time()
        
        # Set voltage to the start voltage in the step and turn on the voltage
        self.cpx.set_voltage(step['start_voltage'])
        print('Starting voltage ramp at: {}'.format(step['start_voltage']))
        self.cpx.output_status(True)
        
        
        voltage_set_point = step['start_voltage']
        
        
        while (time() - start_time) < step['duration']*3600:
            now = time()
            
            # Change address to CO2 flow meter
            self.red_flow_meter.set_address(247)
            # Read flow value
            CO2_flow = self.red_flow_meter.read_value('flow')
            print(self.red_flow_meter.read_value('fluid_name'), CO2_flow)
            
            # Change address to N2 flow meter
            self.red_flow_meter.set_address(2)
            # Read flow value
            N2_flow = self.red_flow_meter.read_value('flow')
            print(self.red_flow_meter.read_value('fluid_name'), N2_flow)
            
            # Set the voltage on the power supply
            self.cpx.set_voltage(voltage_set_point)
            
            # Read actual voltage
            actual_voltage = self.cpx.read_actual_voltage()
            print('The current voltage is: {}V'.format(actual_voltage))
            print('The voltage set point is {}V'.format(voltage_set_point))
            # Read the current from the power supply
            actual_current  = self.cpx.read_actual_current()
            print('The current current is: {}A'.format(actual_current))
            
            # This is the data collection rate right now
            sleep(step['save_rate'])
            # Save the measurements to the database
            self.data_set_saver.save_point('voltage', (now, actual_voltage))
            self.data_set_saver.save_point('current', (now, actual_current))
            self.data_set_saver.save_point('CO2 flow', (now, CO2_flow))
            # Ramp the voltage by the voltage step in step
            voltage_set_point = voltage_set_point + step['voltage_step']
            
            # Terminate the ramp when the end voltage is reached            
            if voltage_set_point >= step['end_voltage']:
                print('end voltage, {} reached'.format(step['end_voltage']))
                sleep(1)
                # Turn off the power supply
                #self.cpx.output_status(False)
                break
        
        # Tell when the time loop is done and turn of power supply
        print('voltage ramp step has ended')
예제 #2
0
    'type': 14,
    'comment': "My Comment",
    'cathode_gas_type': "CO2",
    'anode_gas_type': "N2",
    'cathode_catalyst_description':
    "Magic",  #  "This is what it is made of: 4cm2"
    'anode_catalyst_description': "More Magic",
}
# Add the one custom column
metadata['time'] = now_custom_column

# Add all measurements
metadata['label'] = 'voltage'
data_set_saver.add_measurement('voltage', metadata)
metadata['label'] = 'current'
data_set_saver.add_measurement('current', metadata)

for n in range(100):
    x = float(n)
    y = time.time()
    y2 = y * 2
    data_set_saver.save_point('voltage', (x, y))
    print('voltage', x, y)
    data_set_saver.save_point('current', (x, y2))
    print('current', x, y)
    time.sleep(0.1)

data_set_saver.wait_for_queue_to_empty()
data_set_saver.stop()

time.sleep(3)
예제 #3
0
                )
                metadata_raw = {new: spectrum.metadata[orig] for orig, new in metadata_translation}
                metadata_raw.update({
                    'relative_path': relative_path,
                    'injection': injection,
                    'label': detector.split('.')[0] + ' Inj. ' + str(injection),
                    'type': 21,
                    'time': CustomColumn(time.mktime(spectrum.metadata['datetime']), 'FROM_UNIXTIME(%s)'),
                })

                # We don't use these columns, but they are setup in the database without default
                # values, so to avoid warnings we fill them in
                metadata_raw['sem_voltage'] = 0.0
                metadata_raw['preamp_range'] = 0.0

                codename = metadata_raw['relative_path'] + metadata_raw['label']
                data_set_saver.add_measurement(codename, metadata_raw)
                data_set_saver.save_points_batch(codename, spectrum.times, spectrum.values)

            print('   Uploaded raw spectra for {: <8}: {}'.format(detector, len(spectra)))
            data_set_saver.wait_for_queue_to_empty()

        print('   DONE')


# Enable logging at this point to show the user that they are waiting for the saver to save information
logging.basicConfig(level=logging.INFO)
data_set_saver.stop()
print('ALL DONE')