hermespy-rt

Minimalistic signal processing ray-tracer in C
git clone https://git.ea.contact/hermespy-rt
Log | Files | Refs

commit 5dfc8fb72fbb7a1af122abf85a0b146edd02c956
parent 2e7acb2ebe5382af48399387efecfb88b1d42a3a
Author: Egor Achkasov <eaachkasov@edu.hse.ru>
Date:   Wed, 26 Feb 2025 20:46:35 +0100

Impl rays visualizer; Fix active mask bug; Add rays and active log

Diffstat:
Mcompute_paths.c | 32++++++++++++++++++++++++++------
Mtest.c | 63++++++++++++++++++++++++++++++---------------------------------
Atest.h | 11+++++++++++
Dviz_ray_bin.py | 17-----------------
Avizrays.c | 317+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 384 insertions(+), 56 deletions(-)

diff --git a/compute_paths.c b/compute_paths.c @@ -673,18 +673,34 @@ void compute_paths( * - Spawn scattering rays towards the rx * - TODO Spawn refraction rays with gains as per eqs. (31c)-(31d) from ITU-R P.2040-3 */ + FILE* ray_file = fopen("rays.bin", "wb"); + if (!ray_file) { + fprintf(stderr, "Could not open file rays.bin\n"); + exit(8); + } + fwrite(rays, sizeof(Ray), num_tx * num_paths, ray_file); + + FILE* active_file = fopen("active.bin", "wb"); + if (!active_file) { + fprintf(stderr, "Could not open file active.bin\n"); + exit(8); + } + fwrite(active, sizeof(uint8_t), num_tx * num_paths / 8 + 1, active_file); + for (size_t bounce = 0; bounce < num_bounces; ++bounce) { - size_t active_byte_index = 0, active_bit_pos = 0; /* active[active_byte_index] & (1 << active_bit_pos) */ + /* active[active_byte_index] & (1 << active_bit_pos) */ + size_t active_byte_index = 0; + uint8_t active_bit = 1; size_t off_tx_path = 0; /* tx * num_paths + path */ for (size_t tx = 0; tx < num_tx; ++tx) - for (size_t path = 0; path < num_paths; ++path, ++off_tx_path) { + for (size_t path = 0; path < num_paths; ++path, ++off_tx_path, active_bit <<= 1) { /* Check if the ray is active */ - if (active_bit_pos == 8) { - active_bit_pos = 0; + if (!active_bit) { + active_bit = 1; ++active_byte_index; } - if (!(active[active_byte_index] & (1 << active_bit_pos))) + if (!(active[active_byte_index] & active_bit)) continue; /***********************************************************************/ @@ -697,7 +713,7 @@ void compute_paths( /* Find the hit point and trinagle and the angle of incidence */ moeller_trumbore(&rays[off_tx_path], &scene, &t, &mesh_ind, &face_ind, &theta); if (mesh_ind == (uint32_t)-1) { /* Ray hit nothing */ - active[active_byte_index] &= ~(1 << active_bit_pos); + active[active_byte_index] &= ~active_bit; --num_active; continue; } @@ -800,7 +816,11 @@ void compute_paths( /***********************************************************************/ /* TODO */ } + fwrite(rays, sizeof(Ray), num_tx * num_paths, ray_file); + fwrite(active, sizeof(uint8_t), num_tx * num_paths / 8 + 1, active_file); } + fclose(ray_file); + fclose(active_file); /* Free */ free(a_te_re_refl); diff --git a/test.c b/test.c @@ -1,4 +1,5 @@ #include "compute_paths.h" +#include "test.h" #include <stdio.h> /* for fprintf */ #include <stdlib.h> /* for malloc */ @@ -10,28 +11,24 @@ int main(int argc, char **argv) return 1; } - float rx_positions[3] = {0.0, 0.0, 2.5}; - float tx_positions[3] = {0.0, 0.0, 2.5}; + float rx_positions[3] = {0.0, 0.0, .5}; + float tx_positions[3] = {0.0, 0.0, .5}; float rx_velocities[3] = {0.0, 0.0, 0.0}; float tx_velocities[3] = {0.0, 0.0, 0.0}; float carrier_frequency = 3.0; /* 3 GHz */ - size_t num_rx = 1; - size_t num_tx = 1; - size_t num_paths = 10000; - size_t num_bounces = 3; - float *directions_los = (float*)malloc(num_rx * num_tx * 3 * sizeof(float)); - float *a_te_re_los = (float*)malloc(num_rx * num_tx * sizeof(float)); - float *a_te_im_los = (float*)malloc(num_rx * num_tx * sizeof(float)); - float *a_tm_re_los = (float*)malloc(num_rx * num_tx * sizeof(float)); - float *a_tm_im_los = (float*)malloc(num_rx * num_tx * sizeof(float)); - float *tau_los = (float*)malloc(num_rx * num_tx * sizeof(float)); - float *directions_rx_scat = (float*)malloc(num_rx * num_tx * num_bounces * num_paths * 3 * sizeof(float)); - float *directions_tx_scat = (float*)malloc(num_paths * 3 * sizeof(float)); - float *a_te_re_scat = (float*)malloc(num_rx * num_tx * num_bounces * num_paths * sizeof(float)); - float *a_te_im_scat = (float*)malloc(num_rx * num_tx * num_bounces * num_paths * sizeof(float)); - float *a_tm_re_scat = (float*)malloc(num_rx * num_tx * num_bounces * num_paths * sizeof(float)); - float *a_tm_im_scat = (float*)malloc(num_rx * num_tx * num_bounces * num_paths * sizeof(float)); - float *tau_scat = (float*)malloc(num_rx * num_tx * num_bounces * num_paths * sizeof(float)); + float *directions_los = (float*)malloc(g_numRx * g_numTx * 3 * sizeof(float)); + float *a_te_re_los = (float*)malloc(g_numRx * g_numTx * sizeof(float)); + float *a_te_im_los = (float*)malloc(g_numRx * g_numTx * sizeof(float)); + float *a_tm_re_los = (float*)malloc(g_numRx * g_numTx * sizeof(float)); + float *a_tm_im_los = (float*)malloc(g_numRx * g_numTx * sizeof(float)); + float *tau_los = (float*)malloc(g_numRx * g_numTx * sizeof(float)); + float *directions_rx_scat = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * 3 * sizeof(float)); + float *directions_tx_scat = (float*)malloc(g_numPaths * 3 * sizeof(float)); + float *a_te_re_scat = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)); + float *a_te_im_scat = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)); + float *a_tm_re_scat = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)); + float *a_tm_im_scat = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)); + float *tau_scat = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)); compute_paths( argv[1], rx_positions, @@ -39,7 +36,7 @@ int main(int argc, char **argv) rx_velocities, tx_velocities, carrier_frequency, - num_rx, num_tx, num_paths, num_bounces, + g_numRx, g_numTx, g_numPaths, g_numBounces, directions_los, a_te_re_los, a_te_im_los, a_tm_re_los, a_tm_im_los, tau_los, directions_rx_scat, directions_rx_scat, a_te_re_scat, a_te_im_scat, a_tm_re_scat, a_tm_im_scat, tau_scat @@ -53,17 +50,17 @@ int main(int argc, char **argv) fwrite(data, sizeof(float), size, f); \ fclose(f); - WRITE_BIN("directions_los.bin", directions_los, num_rx * num_tx * 3); - WRITE_BIN("a_te_re_los.bin", a_te_re_los, num_rx * num_tx); - WRITE_BIN("a_te_im_los.bin", a_te_im_los, num_rx * num_tx); - WRITE_BIN("a_tm_re_los.bin", a_tm_re_los, num_rx * num_tx); - WRITE_BIN("a_tm_im_los.bin", a_tm_im_los, num_rx * num_tx); - WRITE_BIN("tau_los.bin", tau_los, num_rx * num_tx); - WRITE_BIN("directions_rx_scat.bin", directions_rx_scat, num_rx * num_tx * num_bounces * num_paths * 3); - WRITE_BIN("directions_tx_scat.bin", directions_tx_scat, num_paths * 3); - WRITE_BIN("a_te_re_scat.bin", a_te_re_scat, num_rx * num_tx * num_bounces * num_paths); - WRITE_BIN("a_te_im_scat.bin", a_te_im_scat, num_rx * num_tx * num_bounces * num_paths); - WRITE_BIN("a_tm_re_scat.bin", a_tm_re_scat, num_rx * num_tx * num_bounces * num_paths); - WRITE_BIN("a_tm_im_scat.bin", a_tm_im_scat, num_rx * num_tx * num_bounces * num_paths); - WRITE_BIN("tau_scat.bin", tau_scat, num_rx * num_tx * num_bounces * num_paths); + WRITE_BIN("directions_los.bin", directions_los, g_numRx * g_numTx * 3); + WRITE_BIN("a_te_re_los.bin", a_te_re_los, g_numRx * g_numTx); + WRITE_BIN("a_te_im_los.bin", a_te_im_los, g_numRx * g_numTx); + WRITE_BIN("a_tm_re_los.bin", a_tm_re_los, g_numRx * g_numTx); + WRITE_BIN("a_tm_im_los.bin", a_tm_im_los, g_numRx * g_numTx); + WRITE_BIN("tau_los.bin", tau_los, g_numRx * g_numTx); + WRITE_BIN("directions_rx_scat.bin", directions_rx_scat, g_numRx * g_numTx * g_numBounces * g_numPaths * 3); + WRITE_BIN("directions_tx_scat.bin", directions_tx_scat, g_numPaths * 3); + WRITE_BIN("a_te_re_scat.bin", a_te_re_scat, g_numRx * g_numTx * g_numBounces * g_numPaths); + WRITE_BIN("a_te_im_scat.bin", a_te_im_scat, g_numRx * g_numTx * g_numBounces * g_numPaths); + WRITE_BIN("a_tm_re_scat.bin", a_tm_re_scat, g_numRx * g_numTx * g_numBounces * g_numPaths); + WRITE_BIN("a_tm_im_scat.bin", a_tm_im_scat, g_numRx * g_numTx * g_numBounces * g_numPaths); + WRITE_BIN("tau_scat.bin", tau_scat, g_numRx * g_numTx * g_numBounces * g_numPaths); } diff --git a/test.h b/test.h @@ -0,0 +1,11 @@ +#ifndef TEST_H +#define TEST_H + +#include <stdint.h> + +uint32_t g_numPaths = 10000; +uint32_t g_numBounces = 3; +uint32_t g_numTx = 1; +uint32_t g_numRx = 1; + +#endif diff --git a/viz_ray_bin.py b/viz_ray_bin.py @@ -1,17 +0,0 @@ -import open3d as o3d -import numpy as np -from sys import argv - -pcs = [] -for arg in argv[1:]: - f = open(arg, 'rb') - #a = np.fromfile(f, dtype=np.float32).reshape((-1, 3)) - #a = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(a)) - #pcs.append(a) - a = np.fromfile(f, dtype=np.float32).reshape((-1, 10000, 3)) - f.close() - for ai in a: - ai = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(ai)) - pcs.append(ai) -pcs.append(o3d.io.read_triangle_mesh('scenes/box.ply')) -o3d.visualization.draw(pcs, show_ui=True) diff --git a/vizrays.c b/vizrays.c @@ -0,0 +1,317 @@ +#include "test.h" /* for g_numPaths, g_numBounces, g_numTx, g_numRx */ + +#include <GL/glut.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <stdint.h> + +/** + * Structs + */ + +typedef struct { + float x, y, z; +} Vec3; + +typedef struct { + Vec3 o; + float lastX, lastY; + float yaw, pitch; +} Camera; + +typedef struct { + uint32_t num_vertices; + Vec3* vs; + uint32_t num_triangles; + uint32_t* is; +} Mesh; + +typedef struct { + uint32_t num_meshes; + Mesh* meshes; +} Scene; + +/** + * Globals + */ + +Camera g_cam = {{0.f, 0.f, 5.f}, 0.f, 0.f, 0.f, 0.f}; +uint8_t g_mouseDown = 0; + +float* g_rays = NULL; +uint8_t *g_active = NULL; + +Scene g_scene = {0}; + +int g_bounce_cur = 0; + +/** + * Loading functions + */ + +void loadRays(const char* filename) { + FILE* file = fopen(filename, "rb"); + if (!file) { + printf("Failed to open file\n"); + exit(8); + } + + uint32_t fileSize = (g_numBounces + 1) * g_numTx * g_numPaths * 2 * 3; + g_rays = (float*)malloc(fileSize * sizeof(float)); + fread(g_rays, sizeof(float), fileSize, file); + fclose(file); + + /* active.bin */ + file = fopen("active.bin", "rb"); + if (!file) { + printf("Failed to open file\n"); + exit(8); + } + uint32_t activeSize = (g_numBounces + 1) * (g_numTx * g_numPaths / 8 + 1); + g_active = (uint8_t*)malloc(activeSize * sizeof(uint8_t)); + fread(g_active, sizeof(uint8_t), activeSize, file); + fclose(file); +} + +void loadScene(const char* filename) { + FILE* file = fopen(filename, "rb"); + if (!file) { + printf("Failed to open file\n"); + exit(8); + } + + /* Magic */ + char magic[3]; + fread(magic, 1, 3, file); + if (magic[0] != 'H' || magic[1] != 'R' || magic[2] != 'T') { + printf("Invalid file format\n"); + exit(8); + } + + /* Scene */ + fread(&g_scene.num_meshes, sizeof(uint32_t), 1, file); + g_scene.meshes = (Mesh*)malloc(g_scene.num_meshes * sizeof(Mesh)); + + /* Meshes */ + for (Mesh* mesh = g_scene.meshes; + mesh != g_scene.meshes + g_scene.num_meshes; + ++mesh) + { + fread(&mesh->num_vertices, sizeof(uint32_t), 1, file); + mesh->vs = (Vec3*)malloc(mesh->num_vertices * sizeof(Vec3)); + fread(mesh->vs, sizeof(Vec3), mesh->num_vertices, file); + fread(&mesh->num_triangles, sizeof(uint32_t), 1, file); + mesh->is = (uint32_t*)malloc(mesh->num_triangles * 3 * sizeof(uint32_t)); + fread(mesh->is, sizeof(uint32_t), mesh->num_triangles * 3, file); + } + fclose(file); +} + +/** + * Draw functions + */ + +void drawScene() { + glColor3f(1.0f, 1.0f, 1.0f); + glBegin(GL_TRIANGLES); + for (uint32_t i = 0; i < g_scene.num_meshes; i++) { + Mesh* mesh = &g_scene.meshes[i]; + for (uint32_t j = 0; j < mesh->num_triangles; j++) { + uint32_t idx = mesh->is[j * 3]; + Vec3 v1 = mesh->vs[idx]; + idx = mesh->is[j * 3 + 1]; + Vec3 v2 = mesh->vs[idx]; + idx = mesh->is[j * 3 + 2]; + Vec3 v3 = mesh->vs[idx]; + glVertex3f(v1.x, v1.y, v1.z); + glVertex3f(v2.x, v2.y, v2.z); + glVertex3f(v3.x, v3.y, v3.z); + } + } + glEnd(); +} + +void drawRays() { + float color = (float)g_bounce_cur / g_numBounces; + glColor3f(color, 0.0f, 1.0f - color); + + glBegin(GL_LINES); + int idx_base = g_bounce_cur * g_numTx * g_numPaths * 2 * 3; + uint32_t active_byte = g_bounce_cur * (g_numTx * g_numPaths / 8 + 1); + uint8_t active_bit = 1; + uint32_t num_skipped = 0; + for (int path = 0; path < g_numPaths; ++path, active_bit <<= 1) { + int idx = idx_base + path * 2 * 3; + + if (!active_bit) { + active_byte++; + active_bit = 1; + } + if (!(g_active[active_byte] & active_bit)) + { + num_skipped++; + continue; + } + + /* Origin */ + float x1 = g_rays[idx]; + float y1 = g_rays[idx + 1]; + float z1 = g_rays[idx + 2]; + + /* Destination */ + float x2 = x1 + g_rays[idx + 3]; + float y2 = y1 + g_rays[idx + 4]; + float z2 = z1 + g_rays[idx + 5]; + + glVertex3f(x1, y1, z1); + glVertex3f(x2, y2, z2); + } + glEnd(); + printf("Skipped %d paths\n", num_skipped); + + /* Draw points */ + glPointSize(5.0f); + glBegin(GL_POINTS); + active_byte = g_bounce_cur * (g_numTx * g_numPaths / 8 + 1); + active_bit = 1; + for (int path = 0; path < g_numPaths; ++path) { + int idx = idx_base + path * 2 * 3; + if (!active_bit) { + active_byte++; + active_bit = 1; + } + if (!(g_active[active_byte] & active_bit)) + continue; + glVertex3f(g_rays[idx], g_rays[idx + 1], g_rays[idx + 2]); + } + glEnd(); +} + +/** + * Callbacks + */ + +void display() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + + /* Apply camera transformation */ + glRotatef(g_cam.pitch, 1.0f, 0.0f, 0.0f); + glRotatef(g_cam.yaw, 0.0f, 1.0f, 0.0f); + glTranslatef(-g_cam.o.x, -g_cam.o.y, -g_cam.o.z); + + drawScene(); + drawRays(); + + glutSwapBuffers(); +} + +void reshape(int w, int h) { + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0f, (float)w/h, 0.1f, 1000.0f); + glMatrixMode(GL_MODELVIEW); +} + +void keyboard(unsigned char key, int x, int y) { + float speed = 0.5f; + switch (key) { + case 'w': // Forward + g_cam.o.x += sin(g_cam.yaw * M_PI/180.0f) * speed; + g_cam.o.z -= cos(g_cam.yaw * M_PI/180.0f) * speed; + break; + case 's': // Backward + g_cam.o.x -= sin(g_cam.yaw * M_PI/180.0f) * speed; + g_cam.o.z += cos(g_cam.yaw * M_PI/180.0f) * speed; + break; + case 'a': // Left + g_cam.o.x -= cos(g_cam.yaw * M_PI/180.0f) * speed; + g_cam.o.z -= sin(g_cam.yaw * M_PI/180.0f) * speed; + break; + case 'd': // Right + g_cam.o.x += cos(g_cam.yaw * M_PI/180.0f) * speed; + g_cam.o.z += sin(g_cam.yaw * M_PI/180.0f) * speed; + break; + case 'q': // Up + g_cam.o.y += speed; + break; + case 'e': // Down + g_cam.o.y -= speed; + break; + case 'x': // Next bounce + if (g_bounce_cur != g_numBounces) + g_bounce_cur++; + break; + case 'z': // Previous bounce + if (g_bounce_cur != 0) + g_bounce_cur--; + break; + case 27: // Escape key + free(g_rays); + for (uint32_t i = 0; i < g_scene.num_meshes; i++) { + free(g_scene.meshes[i].vs); + free(g_scene.meshes[i].is); + } + free(g_scene.meshes); + exit(0); + } + glutPostRedisplay(); +} + +void motion(int x, int y) { + if (!g_mouseDown) return; + g_cam.yaw += (x - g_cam.lastX) * 0.2f; + g_cam.pitch += (y - g_cam.lastY) * 0.2f; + g_cam.pitch = fmax(-89.0f, fmin(89.0f, g_cam.pitch)); + g_cam.lastX = x; + g_cam.lastY = y; + glutPostRedisplay(); +} + +void mouse(int button, int state, int x, int y) { + if (button == GLUT_LEFT_BUTTON) { + if (state == GLUT_DOWN) { + g_mouseDown = 1; + g_cam.lastX = x; + g_cam.lastY = y; + } else { + g_mouseDown = 0; + } + } +} + +/** + * Main + */ + +int main(int argc, char** argv) { + const char* rays_filename = "rays.bin"; + + /* Load ray data */ + loadRays(rays_filename); + if (argc > 1) + loadScene(argv[1]); + + /* Initialize GLUT */ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutInitWindowSize(800, 600); + glutCreateWindow("Ray Visualization"); + + /* Set up OpenGL */ + glEnable(GL_DEPTH_TEST); + glClearColor(0.f, 0.f, 0.f, 1.0f); + + /* Register callbacks */ + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyboard); + glutMouseFunc(mouse); + glutMotionFunc(motion); + + glutMainLoop(); + + return 0; +}