def test_modualtion_should_be_25_percent_of_amplitude(self): laser_control = AudioModulationLaserControl(self.sample_rate, self.on_frequency, self.off_frequency, self.offset) laser_control.set_laser_on() sample_data_chunk = numpy.array([(1.0, 1.0)]) po1 = math.cos(0.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) po2 = math.cos(1.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) po3 = math.cos(2.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) po4 = math.cos(3.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) po5 = math.cos(0.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) po6 = math.cos(1.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) po7 = math.cos(2.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) po8 = math.cos(3.0 / 4.0 * 2.0 * math.pi) * (self._MODULATION_AMPLITUDE_RATIO + 0.75) expected_data = numpy.array([[po1, po1], [po2, po2], [po3, po3], [po4, po4], [po5, po5], [po6, po6], [po7, po7], [po8, po8]]) actual_data = laser_control.modulate(sample_data_chunk).next() self.assertNumpyArrayEquals(expected_data, actual_data)
def test_when_laser_off_modulate_it_at_off_frequency(self): laser_control = AudioModulationLaserControl(self.sample_rate, self.on_frequency, self.off_frequency, self.offset) laser_control.set_laser_off() sample_data_chunk = numpy.array([(0, 0)]) po1 = math.cos( 0.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO po2 = math.cos( 1.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO po3 = math.cos( 2.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO po4 = math.cos( 3.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO po5 = math.cos( 4.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO po6 = math.cos( 5.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO po7 = math.cos( 6.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO po8 = math.cos( 7.0 / 8.0 * 2.0 * math.pi) * self._MODULATION_AMPLITUDE_RATIO expected_data = numpy.array([[po1, po1], [po2, po2], [po3, po3], [po4, po4], [po5, po5], [po6, po6], [po7, po7], [po8, po8]]) actual_data = laser_control.modulate(sample_data_chunk).next() self.assertNumpyArrayEquals(expected_data, actual_data)
def test_off_frequency_must_be_an_even_divisor_of_sample_rate(self): sample_rate = 1000 on_frequency = 500 bad_off_frequency = 99 with self.assertRaises(Exception): AudioModulationLaserControl(sample_rate, on_frequency, bad_off_frequency, self.offset)
def test_modualtion_should_be_25_percent_of_amplitude(self): laser_control = AudioModulationLaserControl(self.sample_rate,self.on_frequency,self.off_frequency) laser_control.set_laser_on() sample_data_chunk = numpy.array([(1.0,1.0)]) po1 = math.cos(0.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) po2 = math.cos(1.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) po3 = math.cos(2.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) po4 = math.cos(3.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) po5 = math.cos(0.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) po6 = math.cos(1.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) po7 = math.cos(2.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) po8 = math.cos(3.0 / 4.0 * 2.0 * math.pi ) * ( self._MODULATION_AMPLITUDE_RATIO + 0.75 ) expected_data = numpy.array([[po1,po1],[po2,po2],[po3,po3],[po4,po4],[po5,po5],[po6,po6],[po7,po7],[po8,po8]]) actual_data = laser_control.modulate(sample_data_chunk).next() self.assertNumpyArrayEquals(expected_data,actual_data)
def test_when_laser_on_modulate_it_at_on_frequency(self): laser_control = AudioModulationLaserControl(self.sample_rate,self.on_frequency,self.off_frequency) laser_control.set_laser_on() sample_data_chunk = numpy.array([(0,0)]) po1 = math.cos(0.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO po2 = math.cos(1.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO po3 = math.cos(2.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO po4 = math.cos(3.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO po5 = math.cos(0.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO po6 = math.cos(1.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO po7 = math.cos(2.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO po8 = math.cos(3.0 / 4.0 * 2.0 * math.pi ) * self._MODULATION_AMPLITUDE_RATIO expected_data = numpy.array([[po1,po1],[po2,po2],[po3,po3],[po4,po4],[po5,po5],[po6,po6],[po7,po7],[po8,po8]]) actual_data = laser_control.modulate(sample_data_chunk).next() self.assertNumpyArrayEquals(expected_data,actual_data)
def __init__(self, configuration_manager, printer): logging.info("Calibartion API Startup") self._configuration_manager = configuration_manager self._printer = printer self._configuration = self._configuration_manager.load(self._printer) self._point_generator = SinglePointGenerator() self._blink_generator = BlinkGenerator() self._alignment_generator = CalibrationLineGenerator() self._scale_generator = SquareGenerator(speed=1, radius=1) self._test_patterns = { 'Hilbert Space Filling Curve': HilbertGenerator(), 'Square': SquareGenerator(), 'Circle': CircleGenerator(), 'Spiral': SpiralGenerator(), 'Memory Hourglass': MemoryHourglassGenerator() } self._current_generator = self._point_generator self._laser_control = AudioModulationLaserControl( self._configuration.audio.output.sample_rate, self._configuration.audio.output.modulation_on_frequency, self._configuration.audio.output.modulation_off_frequency, self._configuration.options.laser_offset) transformer = TuningTransformer( scale=self._configuration.calibration.max_deflection) self._path_to_audio = PathToAudio( self._laser_control.actual_samples_per_second, transformer, self._configuration.options.laser_thickness_mm) self._audio_writer = None self._controller = None logging.debug("Setting up audiowriter") self._audio_writer = AudioWriter( self._configuration.audio.output.sample_rate, self._configuration.audio.output.bit_depth, ) self._current_generator = self._point_generator self._controller = Controller( self._laser_control, self._path_to_audio, self._audio_writer, self._current_generator, ) self.make_pattern_fit() self._controller.start()
def test_when_laser_off_modulate_it_at_off_frequency_with_offset(self): offset = [0.1,0.1] laser_control = AudioModulationLaserControl(self.sample_rate,self.on_frequency,self.off_frequency, offset) laser_control.set_laser_off() sample_data_chunk = numpy.array([(0,0)]) po1 = math.cos(0.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) po2 = math.cos(1.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) po3 = math.cos(2.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) po4 = math.cos(3.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) po5 = math.cos(4.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) po6 = math.cos(5.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) po7 = math.cos(6.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) po8 = math.cos(7.0 / 8.0 * 2.0 * math.pi ) * (self._MODULATION_AMPLITUDE_RATIO + ( 0.1 * self._SOURCE_AMPLITUDE_RATIO)) expected_data = numpy.array([[po1,po1],[po2,po2],[po3,po3],[po4,po4],[po5,po5],[po6,po6],[po7,po7],[po8,po8]]) actual_data = laser_control.modulate(sample_data_chunk).next() self.assertNumpyArrayEquals(expected_data,actual_data)
def test_number_of_sample_generated_for_on_and_off_should_be_consistant( self): sample_rate = 44100 on_frequency = 11025 off_frequency = 7350 sample_data_chunk = numpy.array([(0, 0)]) laser_control = AudioModulationLaserControl(sample_rate, on_frequency, off_frequency, self.offset) laser_control.set_laser_on() laser_on = len(list(laser_control.modulate(sample_data_chunk))) laser_control.set_laser_off() laser_off = len(list(laser_control.modulate(sample_data_chunk))) self.assertEqual(laser_on, laser_off)
def test_number_of_sample_generated_for_on_and_off_should_be_consistant(self): sample_rate = 44100 on_frequency = 11025 off_frequency = 7350 sample_data_chunk = numpy.array([(0,0)]) laser_control = AudioModulationLaserControl(sample_rate,on_frequency,off_frequency) laser_control.set_laser_on() laser_on = len(list(laser_control.modulate(sample_data_chunk))) laser_control.set_laser_off() laser_off = len(list(laser_control.modulate(sample_data_chunk))) self.assertEqual(laser_on,laser_off)
def print_layers(self, layer_generator, dry_run=False): if self._configuration.serial.on: self._commander = SerialCommander(self._configuration.serial.port) else: self._commander = NullCommander() laser_control = AudioModulationLaserControl( self._configuration.audio.output.sample_rate, self._configuration.audio.output.modulation_on_frequency, self._configuration.audio.output.modulation_off_frequency, self._configuration.options.laser_offset) transformer = HomogenousTransformer( self._configuration.calibration.max_deflection, self._configuration.calibration.height, self._configuration.calibration.lower_points, self._configuration.calibration.upper_points, ) path_to_audio = PathToAudio( laser_control.actual_samples_per_second, transformer, self._configuration.options.laser_thickness_mm) if dry_run: audio_writer = None self.zaxis = None zaxis_control = None abort_on_error = False else: audio_writer = AudioWriter( self._configuration.audio.output.sample_rate, self._configuration.audio.output.bit_depth, ) self.zaxis = self._get_zaxis() abort_on_error = True self._controller = Controller( laser_control, path_to_audio, audio_writer, layer_generator, zaxis=self.zaxis, status_call_back=self._status_call_back, max_lead_distance=self._configuration.dripper.max_lead_distance_mm, abort_on_error=abort_on_error) self._controller.start()
class CalibrationAPI(object): def __init__(self, configuration_manager, printer): logging.info("Calibartion API Startup") self._configuration_manager = configuration_manager self._printer = printer self._configuration = self._configuration_manager.load(self._printer) self._point_generator = SinglePointGenerator() self._blink_generator = BlinkGenerator() self._alignment_generator = CalibrationLineGenerator() self._scale_generator = SquareGenerator(speed=1, radius=1) self._test_patterns = { 'Hilbert Space Filling Curve': HilbertGenerator(), 'Square': SquareGenerator(), 'Circle': CircleGenerator(), 'Spiral': SpiralGenerator(), 'Memory Hourglass': MemoryHourglassGenerator() } self._current_generator = self._point_generator self._laser_control = AudioModulationLaserControl( self._configuration.audio.output.sample_rate, self._configuration.audio.output.modulation_on_frequency, self._configuration.audio.output.modulation_off_frequency, self._configuration.options.laser_offset) transformer = TuningTransformer( scale=self._configuration.calibration.max_deflection) self._path_to_audio = PathToAudio( self._laser_control.actual_samples_per_second, transformer, self._configuration.options.laser_thickness_mm) self._audio_writer = None self._controller = None logging.debug("Setting up audiowriter") self._audio_writer = AudioWriter( self._configuration.audio.output.sample_rate, self._configuration.audio.output.bit_depth, ) self._current_generator = self._point_generator self._controller = Controller( self._laser_control, self._path_to_audio, self._audio_writer, self._current_generator, ) self.make_pattern_fit() self._controller.start() '''Used to show a single point with no calibration applied''' def show_point(self, xyz=[0.5, 0.5, 0.5]): x, y, z = xyz self._point_generator.xy = [x, y] if (self._current_generator != self._point_generator): self._unapply_calibration() self._update_generator(self._point_generator) '''Used to show a blinking point with no calibration applied used for aligning on and off laser posisition''' def show_blink(self, xyz=[0.5, 0.5, 0.0]): x, y, z = xyz self._blink_generator.xy = [x, y] if (self._current_generator != self._blink_generator): self._unapply_calibration() self._update_generator(self._blink_generator) '''Used to show a single line on one axis used to line up calibration grid''' def show_line(self): self._unapply_calibration() self._update_generator(self._alignment_generator) def get_max_deflection(self): return self._configuration.calibration.max_deflection def set_max_deflection(self, deflection): self._configuration.calibration.max_deflection = deflection self._unapply_calibration() self._save() '''Allows user so force the laser on''' def set_laser_off_override(self, state): self._controller.laser_off_override = state '''Gets the currently configured offset for laser on and off''' def get_laser_offset(self): return self._configuration.options.laser_offset '''Sets the currently configured offset for laser on and off''' def set_laser_offset(self, laser_offset): self._configuration.options.laser_offset = laser_offset self._laser_control.set_offset(laser_offset) self._save() '''Used to show a test pattern with calibration applied''' def show_test_pattern(self, pattern): if pattern in self._test_patterns.keys(): self._apply_calibration() self._update_generator(self._test_patterns[pattern]) else: logging.error('Pattern: %s does not exist' % pattern) raise Exception('Pattern: %s does not exist' % pattern) '''Changes the speed at which the test pattern is drawn in mm/sec''' def set_test_pattern_speed(self, speed): [pattern.set_speed(speed) for pattern in self._test_patterns.values()] '''Shows the scale square''' def show_scale(self): self._unapply_calibration() self._update_generator(self._scale_generator) '''returns a list of test patterns''' def get_test_patterns(self): return self._test_patterns.keys() '''Returns the current calibration for the printer''' def current_calibration(self): return self._configuration.calibration '''Saves the suppliled calibration''' def save_points(self, height, lower_points, upper_points): self._configuration.calibration.height = height self._configuration.calibration.lower_points = lower_points self._configuration.calibration.upper_points = upper_points self._save() def _save(self): self._configuration_manager.save(self._configuration) self.make_pattern_fit() #TODO make this better. #deprecated def make_pattern_fit(self): for pattern in self._test_patterns.values(): pattern.set_radius(self.get_largest_object_radius()) '''Must be called before shutting down applications''' def stop(self): self._controller.stop() def _update_generator(self, generator): self._current_generator = generator self._controller.change_generator(self._current_generator) def _apply_calibration(self): self._path_to_audio.set_transformer( HomogenousTransformer( scale=self._configuration.calibration.max_deflection, upper_height=self._configuration.calibration.height, lower_points=self._configuration.calibration.lower_points, upper_points=self._configuration.calibration.upper_points)) def _unapply_calibration(self): self._path_to_audio.set_transformer( TuningTransformer( scale=self._configuration.calibration.max_deflection)) def _validate_points(self, points): if (len(points) != 4): return False return True '''Based on current calibrations_gets_maximum_size_of_object at the base layer''' def get_largest_object_radius(self): lowest = None for (x, y) in self._configuration.calibration.lower_points.values(): if not lowest or abs(x) < lowest: lowest = abs(x) if abs(y) < lowest: lowest = abs(y) return lowest def stop(self): self._controller.stop()