Compare commits

..

1 Commits

Author SHA1 Message Date
0c8be8bb27 basic signal generator control 2025-03-28 15:57:57 +01:00
5 changed files with 43 additions and 93 deletions

View File

@ -13,3 +13,4 @@ link_directories(/opt/picoscope/lib)
add_subdirectory(src/recorder) add_subdirectory(src/recorder)
add_subdirectory(src/filter) add_subdirectory(src/filter)
add_subdirectory(src/awg)

7
src/awg/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
file(GLOB_RECURSE SOURCES "./*.c")
add_executable(awg ${SOURCES})
target_compile_options(awg PRIVATE -Wall -Wextra)
target_link_libraries(awg ps2000)
set_target_properties(awg PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
)

33
src/awg/main.c Normal file
View File

@ -0,0 +1,33 @@
#include <libps2000/ps2000.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int16_t unit = ps2000_open_unit();
if (unit == -1) {
fprintf(stderr, "failed to open a unit!\n");
return -1;
} else if (unit == 0) {
fprintf(stderr, "no units to open!\n");
return -1;
}
for (int32_t i = 0; i < 2000; i++) {
int16_t err = ps2000_set_sig_gen_built_in(unit, i * 1000, 0, PS2000_DC_VOLTAGE, 0, 0, 0, 0, PS2000_UPDOWN, 0);
if (err == 0) {
printf("failed to set voltage\n");
return 1;
} else {
fprintf(stderr, "%d\n", i);
}
usleep(1000);
}
ps2000_stop(unit);
ps2000_close_unit(unit);
return 0;
}

View File

@ -1,7 +1,6 @@
file(GLOB_RECURSE SOURCES "./*.c") file(GLOB_RECURSE SOURCES "./*.c")
add_executable(recorder ${SOURCES}) add_executable(recorder ${SOURCES})
target_compile_options(recorder PRIVATE -Wall -Wextra) target_compile_options(recorder PRIVATE -Wall -Wextra)
target_compile_options(recorder PRIVATE -mavx2)
target_link_libraries(recorder ps2000) target_link_libraries(recorder ps2000)
set_target_properties(recorder PROPERTIES set_target_properties(recorder PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"

View File

@ -1,4 +1,3 @@
#include <sched.h>
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -20,105 +19,19 @@ void capture_stop(int signal) {
stop = true; stop = true;
} }
#ifdef __AVX2__
#include <immintrin.h>
__always_inline void to_float_iq(const int16_t* i_c, const int16_t* q_c, float* output, uint32_t len) {
size_t i = 0;
__m256 scale = _mm256_set1_ps(1.0f / INT16_MAX);
for (; i + 16 <= len; i += 16) {
// load
__m256i i_vec = _mm256_loadu_si256((__m256i*)&i_c[i]);
__m256i q_vec = _mm256_loadu_si256((__m256i*)&q_c[i]);
__m256i i_lo = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(i_vec));
__m256i i_hi = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(i_vec, 1));
__m256i q_lo = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(q_vec));
__m256i q_hi = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(q_vec, 1));
// convert to float
__m256 i_float_lo = _mm256_cvtepi32_ps(i_lo);
__m256 i_float_hi = _mm256_cvtepi32_ps(i_hi);
__m256 q_float_lo = _mm256_cvtepi32_ps(q_lo);
__m256 q_float_hi = _mm256_cvtepi32_ps(q_hi);
// scale
i_float_lo = _mm256_mul_ps(i_float_lo, scale);
i_float_hi = _mm256_mul_ps(i_float_hi, scale);
q_float_lo = _mm256_mul_ps(q_float_lo, scale);
q_float_hi = _mm256_mul_ps(q_float_hi, scale);
// interleave and store
__m256 interleaved_lo0 = _mm256_unpacklo_ps(i_float_lo, q_float_lo);
__m256 interleaved_lo1 = _mm256_unpackhi_ps(i_float_lo, q_float_lo);
__m256 interleaved_hi0 = _mm256_unpacklo_ps(i_float_hi, q_float_hi);
__m256 interleaved_hi1 = _mm256_unpackhi_ps(i_float_hi, q_float_hi);
_mm256_storeu_ps(&output[i * 2 + 0], _mm256_permute2f128_ps(interleaved_lo0, interleaved_lo1, 0x20));
_mm256_storeu_ps(&output[i * 2 + 8], _mm256_permute2f128_ps(interleaved_lo0, interleaved_lo1, 0x31));
_mm256_storeu_ps(&output[i * 2 + 16], _mm256_permute2f128_ps(interleaved_hi0, interleaved_hi1, 0x20));
_mm256_storeu_ps(&output[i * 2 + 24], _mm256_permute2f128_ps(interleaved_hi0, interleaved_hi1, 0x31));
}
for (; i < len; ++i) {
output[i * 2 + 0] = i_c[i] / (float)INT16_MAX;
output[i * 2 + 1] = q_c[i] / (float)INT16_MAX;
}
}
__always_inline void to_float(const int16_t* input, float* output, size_t len) {
size_t i = 0;
__m256 scale = _mm256_set1_ps(1.0f / INT16_MAX);
for (; i + 16 <= len; i += 16) {
// load
__m256i input_vec = _mm256_loadu_si256((__m256i*)&input[i]);
__m256i input_lo = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(input_vec));
__m256i input_hi = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(input_vec, 1));
// convert to float
__m256 float_lo = _mm256_cvtepi32_ps(input_lo);
__m256 float_hi = _mm256_cvtepi32_ps(input_hi);
// scale
float_lo = _mm256_mul_ps(float_lo, scale);
float_hi = _mm256_mul_ps(float_hi, scale);
// store
_mm256_storeu_ps(&output[i], float_lo);
_mm256_storeu_ps(&output[i + 8], float_hi);
}
for (; i < len; i++) {
output[i] = input[i] / (float)INT16_MAX;
}
}
#endif
void get_overview_buffers(int16_t** overviewBuffers, int16_t overflow, uint32_t triggeredAt, int16_t triggered, int16_t auto_stop, uint32_t nValues) { void get_overview_buffers(int16_t** overviewBuffers, int16_t overflow, uint32_t triggeredAt, int16_t triggered, int16_t auto_stop, uint32_t nValues) {
(void)overflow; (void)overflow;
(void)triggeredAt; (void)triggeredAt;
(void)triggered; (void)triggered;
(void)auto_stop; (void)auto_stop;
#ifdef __AVX2__
if (cfg->iq_mode) {
to_float_iq(overviewBuffers[0], overviewBuffers[2], buffer, nValues);
fwrite(buffer, sizeof(float), nValues * 2, stdout);
} else {
to_float(overviewBuffers[0], buffer, nValues);
fwrite(buffer, sizeof(float), nValues, stdout);
}
#else
if (cfg->iq_mode) { if (cfg->iq_mode) {
for (uint32_t i = 0; i < nValues; i++) { for (uint32_t i = 0; i < nValues; i++) {
buffer[(i * 2) + 0] = overviewBuffers[0][i] / (float)INT16_MAX; buffer[(i * 2) + 0] = overviewBuffers[0][i] / (float)INT16_MAX;
buffer[(i * 2) + 1] = overviewBuffers[2][i] / (float)INT16_MAX; buffer[(i * 2) + 1] = overviewBuffers[2][i] / (float)INT16_MAX;
} }
// fprintf(stderr, "%u\n", nValues);
fwrite(buffer, sizeof(float), nValues * 2, stdout); fwrite(buffer, sizeof(float), nValues * 2, stdout);
} else { } else {
for (uint32_t i = 0; i < nValues; i++) { for (uint32_t i = 0; i < nValues; i++) {
@ -127,7 +40,6 @@ void get_overview_buffers(int16_t** overviewBuffers, int16_t overflow, uint32_t
fwrite(buffer, sizeof(float), nValues, stdout); fwrite(buffer, sizeof(float), nValues, stdout);
} }
#endif
} }
void cleanup(int16_t unit) { void cleanup(int16_t unit) {
@ -181,8 +93,7 @@ int main(int argc, char** argv) {
buffer = (float*)malloc(sizeof(float) * (cfg->max_buffersize) * (cfg->iq_mode ? 2 : 1)); buffer = (float*)malloc(sizeof(float) * (cfg->max_buffersize) * (cfg->iq_mode ? 2 : 1));
// start data capture without aggregation // start data capture without aggregation
fprintf(stderr, "sample_interval=%u, time_units=%u, buffer_size=%u, max_buffer_size=%u\n", cfg->sample_interval, cfg->time_units, cfg->buffersize, fprintf(stderr, "sample_interval=%u, time_units=%u, buffer_size=%u, max_buffer_size=%u\n", cfg->sample_interval, cfg->time_units, cfg->buffersize, cfg->max_buffersize);
cfg->max_buffersize);
if (ps2000_run_streaming_ns(unit, cfg->sample_interval, cfg->time_units, cfg->buffersize, false, 1, cfg->max_buffersize) == 0) { if (ps2000_run_streaming_ns(unit, cfg->sample_interval, cfg->time_units, cfg->buffersize, false, 1, cfg->max_buffersize) == 0) {
fprintf(stderr, "run_streaming_ns failed!\n"); fprintf(stderr, "run_streaming_ns failed!\n");
cleanup(unit); cleanup(unit);
@ -194,7 +105,6 @@ int main(int argc, char** argv) {
while (!stop) { while (!stop) {
ps2000_get_streaming_last_values(unit, &get_overview_buffers); ps2000_get_streaming_last_values(unit, &get_overview_buffers);
sched_yield();
} }
cleanup(unit); cleanup(unit);