Ejemplo n.º 1
0
def test_superposition(wave: WaveformGenerator, scope: Oscilloscope):
    frequency = 1000
    amplitude1 = 2
    amplitude2 = 1

    def super_sine(x):
        return amplitude1 * np.sin(x) + amplitude2 * np.sin(5 * x)

    wave.load_function("SI1", super_sine, [0, 2 * np.pi])
    wave.generate("SI1", frequency)
    time.sleep(0.1)
    x, y = scope.capture(1, 10000, 1, trigger=0)

    def expected_f(x, amplitude1, amplitude2, frequency, phase):
        return amplitude1 * np.sin(2 * np.pi * frequency * x +
                                   phase) + amplitude2 * np.sin(
                                       5 * (2 * np.pi * frequency * x + phase))

    amplitude1 = 2
    amplitude2 = 1
    guess = [amplitude1, amplitude2, frequency, 0]
    [amplitude1_est, amplitude2_est, frequency_est,
     phase_est], _ = curve_fit(expected_f, x * MICROSECONDS, y, guess)

    assert amplitude1_est == pytest.approx(amplitude1, rel=RELTOL)
    assert amplitude2_est == pytest.approx(amplitude2, rel=RELTOL)
    assert frequency_est == pytest.approx(frequency, rel=RELTOL)

    coeff_of_det = r_squared(
        y,
        expected_f(x * MICROSECONDS, amplitude1_est, amplitude2_est,
                   frequency_est, phase_est),
    )

    assert coeff_of_det >= GOOD_FIT
Ejemplo n.º 2
0
    def __init__(
        self,
        device: SerialHandler = None,
        integration_time: float = 10e-6,
        master_clock_frequency: float = 2e6,
    ):
        self._device = SerialHandler() if device is None else device
        self._pwmgen = PWMGenerator(self._device)
        self._scope = Oscilloscope(self._device)
        self._ps = PowerSupply(self._device)
        self.integration_time = integration_time
        self.master_clock_frequency = master_clock_frequency

        self.poweron()
        self._pwmgen.set_state(sq3=True)
        self._start_master_clock()
        self._start_sh_clock()
Ejemplo n.º 3
0
class TCD1304:
    def __init__(self, ):
        self.pwmgen = PWMGenerator()
        self.scope = Oscilloscope()
        self.ps = PowerSupply()

    def set_power_source():
        self.ps.pv1 = 4

    def start_icg_clock(self):
        self.pwmgen.set_state(sq3=True)
        time.sleep(READ_OUT_TIME)
        self.pwmgen.set_state(sq3=False)

    def start_master_clock(self):
        prescaler = int(
            math.log(OSCILLATOR_FREQUENCY / FREQUENCY_MASTER_CLOCK) /
            math.log(2))
        self.pwmgen.map_reference_clock(["SQ1"], prescaler)

    def start_sh_clock(self):
        self.pwmgen.generate(["SQ2"], 1 / INTEGRATION_TIME, [0.5])

    def read_signal(self):
        self.scope.select_range('CH1', MAX_VOLTAGE_OUTPUT)
        self.scope.configure_trigger(channel='CH1', voltage=MIN_VOLTAGE_OUTPUT)
        self.scope.capture(channels=1,
                           samples=INTEGRATION_ELEMENTS * SAMPLES_PER_ELEMENT,
                           timegap=INTEGRATION_TIME / SAMPLES_PER_ELEMENT,
                           block=False)
        self.icg_clock()
        y, = self.scope.fetch_data()
        return y
Ejemplo n.º 4
0
def scope(handler):
    """Return an Oscilloscope instance.

    In integration test mode, this function also enables the analog output.
    """
    if not isinstance(handler, MockHandler):
        wave = WaveformGenerator(handler)
        wave.generate(["SI1", "SI2"], FREQUENCY)
        handler._logging = True
    return Oscilloscope(handler)
Ejemplo n.º 5
0
def oscilloscope(device: SerialHandler, channels: int,
                 duration: float) -> Tuple[List[str], List[np.ndarray]]:
    """Capture varying voltage signals on up to four channels simultaneously.

    Parameters
    ----------
    device : :class:`Handler`
        Serial interface for communicating with the PSLab device.
    channels : {1, 2, 4}
        Number of channels to sample from simultaneously. By default, samples are
        captured from CH1, CH2, CH3 and MIC.
    duration : float
        Duration in seconds up to which samples will be captured.

    Returns
    -------
    list of str
        "Timestamp", Name of active channels.
    list of numpy.ndarray
        List of numpy.ndarrays with timestamps in the first index and corresponding
        voltages in the following index. The length of the list is equal to one
        additional to the number of channels that were used to capture samples.
    """
    scope = Oscilloscope(device)
    max_samples = CP.MAX_SAMPLES // channels
    min_timegap = scope._lookup_mininum_timegap(channels)
    max_duration = max_samples * min_timegap * 1e-6
    active_channels = ([scope._channel_one_map] + scope._CH234)[:channels]
    xy = [np.array([]) for _ in range(1 + channels)]

    while duration > 0:
        if duration >= max_duration:
            samples = max_samples
        else:
            samples = round((duration * 1e6) / min_timegap)

        st = time.time()
        xy = np.append(xy,
                       scope.capture(channels, samples, min_timegap),
                       axis=1)
        duration -= time.time() - st

    return ["Timestamp"] + active_channels, xy
Ejemplo n.º 6
0
    def __init__(self):
        super().__init__()
        self.logic_analyzer = LogicAnalyzer(device=self)
        self.oscilloscope = Oscilloscope(device=self)
        self.waveform_generator = WaveformGenerator(device=self)
        self.pwm_generator = PWMGenerator(device=self)
        self.multimeter = Multimeter(device=self)
        self.power_supply = PowerSupply(device=self)
        self.i2c = I2CMaster(device=self)
        self.nrf = NRF24L01(device=self)

        if "V6" in self.version:  # Set the built-in WS2812B to green :)
            self.rgb_led([0, 20, 0])
Ejemplo n.º 7
0
    def __init__(
        self,
        port: str = None,
        baudrate: int = 1000000,
        timeout: float = 1.0,
    ):
        super().__init__(port, baudrate, timeout)
        self.logic_analyzer = LogicAnalyzer(device=self)
        self.oscilloscope = Oscilloscope(device=self)
        self.waveform_generator = WaveformGenerator(device=self)
        self.pwm_generator = PWMGenerator(device=self)
        self.multimeter = Multimeter(device=self)
        self.power_supply = PowerSupply(device=self)
        self.i2c = I2CMaster(device=self)
        self.nrf = NRF24L01(device=self)

        if "V6" in self.version:  # Set the built-in WS2812B to green :)
            self.rgb_led([0, 20, 0])
Ejemplo n.º 8
0
def test_sine_phase(wave: WaveformGenerator, scope: Oscilloscope):
    frequency = 500
    phase = 90
    wave.load_function("SI1", "sine")
    wave.load_function("SI2", "sine")
    wave.generate(["SI1", "SI2"], frequency, phase)
    time.sleep(0.1)
    x, y1, y2 = scope.capture(2, 5000, 2, trigger=0)

    def expected_f(x, amplitude, frequency, phase):
        return amplitude * np.sin(2 * np.pi * frequency * x + phase)

    guess1 = [3.3, frequency, 0]
    [_, _, phase1_est], _ = curve_fit(expected_f, x * MICROSECONDS, y1, guess1)
    guess2 = [3.3, frequency, phase * np.pi / 180]
    [_, _, phase2_est], _ = curve_fit(expected_f, x * MICROSECONDS, y2, guess2)

    assert phase2_est - phase1_est == pytest.approx(phase * np.pi / 180,
                                                    rel=RELTOL)
Ejemplo n.º 9
0
def test_sine_wave(wave: WaveformGenerator, scope: Oscilloscope):
    frequency = 500
    wave.load_function("SI1", "sine")
    wave.generate("SI1", frequency)
    time.sleep(0.1)
    x, y = scope.capture(1, 10000, 1, trigger=0)

    def expected_f(x, amplitude, frequency, phase):
        return amplitude * np.sin(2 * np.pi * frequency * x + phase)

    amplitude = 3.3
    guess = [amplitude, frequency, 0]
    [amplitude_est, frequency_est,
     phase_est], _ = curve_fit(expected_f, x * MICROSECONDS, y, guess)

    assert amplitude_est == pytest.approx(amplitude, rel=RELTOL)
    assert frequency_est == pytest.approx(frequency, rel=RELTOL)

    coeff_of_det = r_squared(
        y, expected_f(x * MICROSECONDS, amplitude_est, frequency_est,
                      phase_est))

    assert coeff_of_det >= GOOD_FIT
Ejemplo n.º 10
0
def scope(handler: SerialHandler) -> Oscilloscope:
    handler._logging = True
    return Oscilloscope(handler)
Ejemplo n.º 11
0
 def __init__(self, ):
     self.pwmgen = PWMGenerator()
     self.scope = Oscilloscope()
     self.ps = PowerSupply()
Ejemplo n.º 12
0
class TCD1304:
    """The TCD1304 is a linear CCD suitable for visible spectrum analysis."""

    _INTEGRATION_ELEMENTS = 3694
    _MIN_VOLTAGE_OUTPUT = 2
    _MAX_VOLTAGE_OUTPUT = 4
    _SAMPLES_PER_ELEMENT = 2

    def __init__(
        self,
        device: SerialHandler = None,
        integration_time: float = 10e-6,
        master_clock_frequency: float = 2e6,
    ):
        self._device = SerialHandler() if device is None else device
        self._pwmgen = PWMGenerator(self._device)
        self._scope = Oscilloscope(self._device)
        self._ps = PowerSupply(self._device)
        self.integration_time = integration_time
        self.master_clock_frequency = master_clock_frequency

        self.poweron()
        self._pwmgen.set_state(sq3=True)
        self._start_master_clock()
        self._start_sh_clock()

    def poweron(self):
        """Turn TCD1304 on."""
        self._ps.pv1 = 5

    def poweroff(self):
        """Turn TCD1304 off."""
        self._ps.pv1 = 0

    def _start_icg_clock(self):
        read_out_time = self._INTEGRATION_ELEMENTS * self.integration_time
        self._pwmgen.set_state(sq3=False)
        self._pwmgen.set_state(sq3=True)
        time.sleep(read_out_time)
        self._pwmgen.set_state(sq3=False)
        self._pwmgen.set_state(sq3=True)

    def _start_master_clock(self):
        prescaler = int(
            math.log(_OSCILLATOR_FREQUENCY / self.master_clock_frequency) / math.log(2)
        )
        self._pwmgen.map_reference_clock(["SQ1"], prescaler)

    def _start_sh_clock(self):
        self._pwmgen.generate(["SQ2"], 1 / self.integration_time, [0.5])

    def read_signal(self):
        """Start the ICG clock and read the analog output from the TCD1304."""
        self._scope.select_range("CH1", self._MAX_VOLTAGE_OUTPUT)
        self._scope.configure_trigger(channel="CH1", voltage=self._MIN_VOLTAGE_OUTPUT)
        self._scope.capture(
            channels=1,
            samples=self._INTEGRATION_ELEMENTS * self._SAMPLES_PER_ELEMENT,
            timegap=self.integration_time / self._SAMPLES_PER_ELEMENT * _MICROSECONDS,
            block=False,
        )
        self._start_icg_clock()
        (y,) = self._scope.fetch_data()
        return y