hermespy-rt

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

commit ee046840344c8d9dd305aa165af7fa7ee06e9c62
parent 8b9a331fc8345e0530e46faec8fa26e47a7d67fa
Author: Egor Achkasov <eaachkasov@edu.hse.ru>
Date:   Thu, 27 Mar 2025 20:44:14 +0100

Make compute_paths output rays instead of writing them to a file

Diffstat:
Minc/compute_paths.h | 65++++++++++++++++++++++++++++++++++++++---------------------------
Ainc/ray.h | 11+++++++++++
Msrc/compute_paths.c | 322+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/vizrays.c | 94+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mtest/test.c | 56+++++++++++++++++++++++++++++++++++++++++---------------
5 files changed, 283 insertions(+), 265 deletions(-)

diff --git a/inc/compute_paths.h b/inc/compute_paths.h @@ -2,25 +2,32 @@ #define COMPUTE_PATHS_H #include "scene.h" /* for Scene */ +#include "vec3.h" /* for Vec3 */ +#include "ray.h" /* for Ray */ +#include "common.h" /* for IN, OUT */ #include <stddef.h> /* for size_t */ #include <stdint.h> /* for uint32_t */ -#define IN -#define OUT +/** Raytracing channel information returned by compute_paths for each path type (LoS, scatter) */ +typedef struct { + uint32_t num_rays; /* number of rays for each rx-tx pair */ + Vec3 *directions_rx; /* shape (num_rx, num_tx, num_rays) */ + Vec3 *directions_tx; /* shape (num_tx, num_rays) */ + float *a_te_re; /* shape (num_rx, num_tx, num_rays) */ + float *a_te_im; /* shape (num_rx, num_tx, num_rays) */ + float *a_tm_re; /* shape (num_rx, num_tx, num_rays) */ + float *a_tm_im; /* shape (num_rx, num_tx, num_rays) */ + float *tau; /* shape (num_rx, num_tx, num_rays) */ + float *freq_shift; /* Hz, shape (num_rx, num_tx, num_rays) */ +} ChannelInfo; -/** Raytracing information returned by compute_paths for each path type (LoS, scatter) */ +/** Raytracing rays information returned by compute_paths */ typedef struct { - uint32_t num_paths; - float *directions_rx; /* shape (num_rx, num_tx, num_paths, 3) */ - float *directions_tx; /* shape (num_rx, num_tx, num_paths, 3) */ - float *a_te_re; /* shape (num_rx, num_tx, num_paths) */ - float *a_te_im; /* shape (num_rx, num_tx, num_paths) */ - float *a_tm_re; /* shape (num_rx, num_tx, num_paths) */ - float *a_tm_im; /* shape (num_rx, num_tx, num_paths) */ - float *tau; /* shape (num_rx, num_tx, num_paths) */ - float *freq_shift; /* Hz, shape (num_rx, num_tx, num_paths) */ -} PathsInfo; + uint32_t num_bounces, num_rays; + Ray *rays; /* shape (num_tx, num_bounces, num_paths) */ + uint8_t *rays_active; /* bitmask, shape (num_tx, num_bounces, num_paths / 8 + 1) */ +} RaysInfo; /** Compute gains and delays between tx and rx in a 3D scene. * @@ -44,22 +51,26 @@ typedef struct { * \param num_paths number of paths to compute. Must be > 0 * \param num_bounces number of bounces to compute. Must be > 0 * - * \param los output Line-of-Sight results. los->num_paths = 1 - * \param scatter output scatter results. scatter->num_paths = num_bounces * num_paths + * \param chanInfo_los output Line-of-Sight channel information. .num_rays = 1 + * \param raysInfo_los output Line-of-Sight rays information. .num_bounces = .num_rays = 1 + * \param chanInfo_scat output scatter channel information. .num_rays = num_rays + * \param raysInfo_scat output scatter rays information. .num_bounces = num_bounces + 1, .num_rays = num_rays */ void compute_paths( - IN Scene *scene, /* Pointer to a loaded scene */ - IN Vec3 *rx_pos, /* shape (num_rx, 3) */ - IN Vec3 *tx_pos, /* shape (num_tx, 3) */ - IN Vec3 *rx_vel, /* shape (num_rx, 3) */ - IN Vec3 *tx_vel, /* shape (num_tx, 3) */ - IN float carrier_frequency, /* > 0.0 (IN GHz!) */ - IN size_t num_rx, /* number of receivers */ - IN size_t num_tx, /* number of transmitters */ - IN size_t num_paths, /* number of paths */ - IN size_t num_bounces, /* number of bounces */ - OUT PathsInfo *los, /* output LoS information */ - OUT PathsInfo *scatter /* output scatter information */ + IN Scene *scene, /* Pointer to a loaded scene */ + IN Vec3 *rx_pos, /* shape (num_rx, 3) */ + IN Vec3 *tx_pos, /* shape (num_tx, 3) */ + IN Vec3 *rx_vel, /* shape (num_rx, 3) */ + IN Vec3 *tx_vel, /* shape (num_tx, 3) */ + IN float carrier_frequency_GHz, /* > 0.0 (IN GHz!) */ + IN size_t num_rx, /* number of receivers */ + IN size_t num_tx, /* number of transmitters */ + IN size_t num_rays, /* number of rays */ + IN size_t num_bounces, /* number of bounces */ + OUT ChannelInfo *chanInfo_los, /* output LoS channel information */ + OUT RaysInfo *raysInfo_los, /* output LoS rays information */ + OUT ChannelInfo *chanInfo_scat, /* output scatter channel information */ + OUT RaysInfo *raysInfo_scat /* output scatter rays information */ ); #endif /* COMPUTE_PATHS_H */ diff --git a/inc/ray.h b/inc/ray.h @@ -0,0 +1,11 @@ +#ifndef RAY_H +#define RAY_H + +#include "vec3.h" /* for Vec3 */ + +typedef struct { + Vec3 o; /* origin */ + Vec3 d; /* direction */ +} Ray; + +#endif diff --git a/src/compute_paths.c b/src/compute_paths.c @@ -1,6 +1,9 @@ #include "../inc/compute_paths.h" /* for compute_paths */ #include "../inc/scene.h" /* for Scene, Mesh, Material */ #include "../inc/materials.h" /* for g_materials */ +#include "../inc/common.h" /* for IN, OUT, PERROR_CLEANUP_EXIT */ +#include "../inc/vec3.h" /* for Vec3, vec3_sub, vec3_cross, vec3_dot, vec3_normalize */ +#include "../inc/ray.h" /* for Ray */ #include <stddef.h> /* for size_t */ #include <stdlib.h> /* for exit, malloc, free */ @@ -117,10 +120,6 @@ const float* BINOMIAL_ALPHA_K[20] = { /* ==== STRUCTS ==== */ -typedef struct { - Vec3 o, d; -} Ray; - /* Radio material eta and additional parameters */ typedef struct { /* eta */ @@ -165,18 +164,9 @@ void cdivf( /* ==== PRECOMPUTED GLOBALS ==== */ -/* 4.f * PI * carrier_frequency * 1e9 / SPEED_OF_LIGHT */ -float g_free_space_loss_multiplier; /* Materials etas, calucalted for the given carrier_frequency */ MaterialPrecomputed g_materials_precomputed[NUM_G_MATERIALS]; -void precompute_free_space_loss_multiplier( - IN float carrier_frequency -) -{ - g_free_space_loss_multiplier = 4.f * PI * carrier_frequency * 1e9 / SPEED_OF_LIGHT; -} - void precompute_materials( IN Scene* scene, IN float carrier_frequency @@ -426,96 +416,75 @@ void scat_coefs( /* ==== MAIN FUNCTION ==== */ void compute_paths( - IN Scene *scene, /* Pointer to a loaded scene */ - IN Vec3 *rx_pos, /* shape (num_rx, 3) */ - IN Vec3 *tx_pos, /* shape (num_tx, 3) */ - IN Vec3 *rx_vel, /* shape (num_rx, 3) */ - IN Vec3 *tx_vel, /* shape (num_tx, 3) */ - IN float carrier_frequency, /* > 0.0 (IN GHz!) */ - IN size_t num_rx, /* number of receivers */ - IN size_t num_tx, /* number of transmitters */ - IN size_t num_paths, /* number of paths */ - IN size_t num_bounces, /* number of bounces */ - OUT PathsInfo *los, /* output LoS information. los->num_paths = 1 */ - OUT PathsInfo *scatter /* output scatter information. scatter->num_paths = num_bounces*num_paths */ + IN Scene *scene, /* Pointer to a loaded scene */ + IN Vec3 *rx_pos, /* shape (num_rx, 3) */ + IN Vec3 *tx_pos, /* shape (num_tx, 3) */ + IN Vec3 *rx_vel, /* shape (num_rx, 3) */ + IN Vec3 *tx_vel, /* shape (num_tx, 3) */ + IN float carrier_frequency_GHz, /* > 0.0 (IN GHz!) */ + IN size_t num_rx, /* number of receivers */ + IN size_t num_tx, /* number of transmitters */ + IN size_t num_paths, /* number of paths */ + IN size_t num_bounces, /* number of bounces */ + OUT ChannelInfo *chanInfo_los, /* output LoS channel information */ + OUT RaysInfo *raysInfo_los, /* output LoS rays information */ + OUT ChannelInfo *chanInfo_scat, /* output scatter channel information */ + OUT RaysInfo *raysInfo_scat /* output scatter rays information */ ) { /* Precompute globals */ - precompute_free_space_loss_multiplier(carrier_frequency); - precompute_materials(scene, carrier_frequency); + precompute_materials(scene, carrier_frequency_GHz); precompute_normals(scene); - /* Calculate a fibonacci sphere */ - Vec3 *ray_directions = (Vec3*)malloc(num_paths * sizeof(Vec3)); - float k, phi, theta; + /* Calculate a fibonacci sphere to init rays that leave the transmitters */ + /* rays shape = (num_tx, num_paths) */ + Ray *rays = (Ray*)malloc(num_tx * num_paths * sizeof(Ray)); for (size_t path = 0; path < num_paths; ++path) { - k = (float)path + .5f; - phi = acos(1.f - 2.f * k / num_paths); - theta = PI * (1.f + sqrtf(5.f)) * k; - ray_directions[path] = (Vec3){ + float k = (float)path + .5f; + float phi = acos(1.f - 2.f * k / num_paths); + float theta = PI * (1.f + sqrtf(5.f)) * k; + Vec3 d = (Vec3){ cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi) }; - } - - /* Record the tx directions */ - /* This is only valid for the fibbonaci sphere */ - scatter->directions_tx = (float*)memcpy( - scatter->directions_tx, - ray_directions, - num_paths * sizeof(Vec3) - ); - if (scatter->directions_tx == NULL) { - fprintf(stderr, "Failed to copy memory to scatter->directions_tx\n"); - exit(70); - } - - /* Create num_path rays for each tx */ - /* Shape (num_tx, num_paths) */ - Ray *rays = (Ray*)malloc(num_tx * num_paths * sizeof(Ray)); - for (size_t tx = 0, off = 0; tx < num_tx; ++tx) { - for (size_t path = 0; path < num_paths; ++path, ++off) { - rays[off].o = tx_pos[tx]; - rays[off].d = ray_directions[path]; + for (size_t tx = 0; tx < num_tx; ++tx) { + rays[tx * num_paths + path].o = tx_pos[tx]; + rays[tx * num_paths + path].d = d; } } - free(ray_directions); - /* Initialize variables needed for the RT */ - - /* Bouncing (reflecting) rays gains and delays */ + /* Init bouncing rays gains and delays */ /* shape (num_tx, num_paths) */ - float *a_te_re_refl = (float*)malloc(num_tx * num_paths * sizeof(float)); - float *a_te_im_refl = (float*)calloc(num_tx * num_paths, sizeof(float)); - float *a_tm_re_refl = (float*)malloc(num_tx * num_paths * sizeof(float)); - float *a_tm_im_refl = (float*)calloc(num_tx * num_paths, sizeof(float)); + float *a_te_re = (float*)malloc(num_tx * num_paths * sizeof(float)); + float *a_te_im = (float*)calloc(num_tx * num_paths, sizeof(float)); + float *a_tm_re = (float*)malloc(num_tx * num_paths * sizeof(float)); + float *a_tm_im = (float*)calloc(num_tx * num_paths, sizeof(float)); for (size_t i = 0; i < num_tx * num_paths; ++i) - a_te_re_refl[i] = a_tm_re_refl[i] = 1.f; - float *tau_t = (float*)calloc(num_tx * num_paths, sizeof(float)); + a_te_re[i] = a_tm_re[i] = 1.f; + float *tau = (float*)calloc(num_tx * num_paths, sizeof(float)); /* Active rays bitmask. 1 if the ray is still traced, 0 if it has left the scene */ uint8_t *active = (uint8_t*)malloc((num_tx * num_paths / 8 + 1) * sizeof(uint8_t)); for (size_t i = 0; i < num_tx * num_paths / 8 + 1; ++i) - active[i] = 0xff; + raysInfo_scat->rays_active[i] = active[i] = 0xff; size_t num_active = num_tx * num_paths; /* Temporary variables */ float t, r_te_re, r_te_im, r_tm_re, r_tm_im; - float a_te_re_new, a_te_im_new, a_tm_re_new, a_tm_im_new; + float theta; /* incidence angle */ float theta_s; /* scattering angle */ - uint32_t mesh_ind, face_ind, material_index; - Ray r; - Vec3 *h = (Vec3*)malloc(sizeof(Vec3)); - Vec3 n; + uint32_t mesh_ind, face_ind, material_ind; + Ray* r; /* Friis free space loss multiplier. Multiply this by a distance and take the second power to get a free space loss. */ - float free_space_loss_multiplier = 4.f * PI * carrier_frequency * 1e9 / SPEED_OF_LIGHT; + float carrier_frequency_hz = carrier_frequency_GHz * 1e9; + float free_space_loss_multiplier = 4.f * PI * carrier_frequency_hz / SPEED_OF_LIGHT; float free_space_loss; /* Doppler frequency shift carrier frequency multiplier */ - float doppler_shift_multiplier = carrier_frequency * 1e9 / SPEED_OF_LIGHT; + float doppler_shift_multiplier = carrier_frequency_hz / SPEED_OF_LIGHT; /* Initialize the doppler frequency shift using the tx velocities */ /* The scatter->freq_shift has the shape of (num_rx, num_tx, num_bounces*num_paths) */ @@ -525,16 +494,16 @@ void compute_paths( for (size_t path = 0; path != num_paths; ++path) { size_t off_rays = tx * num_paths + path; size_t off_scat = tx * num_paths * num_bounces + path; - scatter->freq_shift[off_scat] = vec3_dot(&tx_vel[tx], &rays[off_rays].d); - scatter->freq_shift[off_scat] *= doppler_shift_multiplier; + chanInfo_scat->freq_shift[off_scat] = vec3_dot(&tx_vel[tx], &rays[off_rays].d); + chanInfo_scat->freq_shift[off_scat] *= doppler_shift_multiplier; } for (size_t bounce = 1; bounce < num_bounces; ++bounce) - if (!memcpy(scatter->freq_shift + num_tx * num_paths * bounce, - scatter->freq_shift, num_tx * num_paths * sizeof(float))) + if (!memcpy(chanInfo_scat->freq_shift + num_tx * num_paths * bounce, + chanInfo_scat->freq_shift, num_tx * num_paths * sizeof(float))) exit(70); for (size_t rx = 1; rx < num_rx; ++rx) - if (!memcpy(scatter->freq_shift + num_tx * num_paths * num_bounces * rx, - scatter->freq_shift, num_tx * num_paths * num_bounces * sizeof(float))) + if (!memcpy(chanInfo_scat->freq_shift + num_tx * num_paths * num_bounces * rx, + chanInfo_scat->freq_shift, num_tx * num_paths * num_bounces * sizeof(float))) exit(70); /***************************************************************************/ @@ -543,65 +512,67 @@ void compute_paths( /* Consider imaginary parts of the LoS gains to be 0 in any way */ for (size_t off = 0; off != num_rx * num_tx; ++off) - los->a_te_im[off] = los->a_tm_im[off] = 0.f; + chanInfo_los->a_te_im[off] = chanInfo_los->a_tm_im[off] = 0.f; /* Calculate LoS paths directly from tx to rx */ + /* off = rx * num_tx + tx */ for (size_t rx = 0, off = 0; rx != num_rx; ++rx) for (size_t tx = 0; tx != num_tx; ++tx, ++off) { t = -1.f; mesh_ind = face_ind = -1; /* Create a ray from the tx to the rx */ - r.o = tx_pos[tx]; - r.d = vec3_sub(&rx_pos[rx], &r.o); + r = &raysInfo_los->rays[off]; + r->o = tx_pos[tx]; + r->d = vec3_sub(&rx_pos[rx], &r->o); /* In case the tx and the rx are at the same position */ - if (vec3_dot(&r.d, &r.d) < __FLT_EPSILON__) { + if (vec3_dot(&r->d, &r->d) < __FLT_EPSILON__) { /* Assume the direction to be (1, 0, 0) */ - los->directions_rx[off * 3] = 1.f; - los->directions_tx[off * 3] = -1.f; - los->directions_rx[off * 3 + 1] = los->directions_tx[off * 3 + 1] = 0.f; - los->directions_rx[off * 3 + 2] = los->directions_tx[off * 3 + 2] = 0.f; + chanInfo_los->directions_rx[off] = (Vec3){1.f, 0.f, 0.f}; + chanInfo_los->directions_tx[off] = (Vec3){-1.f, 0.f, 0.f}; /* Set gains to 1+0j */ - los->a_te_re[off] = los->a_tm_re[off] = 1.f; + chanInfo_los->a_te_re[off] = chanInfo_los->a_tm_re[off] = 1.f; /* Set delay to 0 */ - los->tau[off] = 0.f; + chanInfo_los->tau[off] = 0.f; /* Set doppler shift to 0. */ - los->freq_shift[off] = 0.f; + chanInfo_los->freq_shift[off] = 0.f; + /* Set the active bit to 1 */ + raysInfo_los->rays_active[off / 8] |= 1 << (off % 8); continue; } /* Is there any abstacle between the tx and the rx? */ - moeller_trumbore(&r, scene, &t, &mesh_ind, &face_ind, &theta); + moeller_trumbore(r, scene, &t, &mesh_ind, &face_ind, &theta); if (mesh_ind != (uint32_t)-1 && t <= 1.f) { /* An obstacle between the tx and the rx has been hit */ - los->a_te_re[off] = los->a_tm_re[off] = los->tau[off] = 0.f; + chanInfo_los->a_te_re[off] = chanInfo_los->a_tm_re[off] = chanInfo_los->tau[off] = 0.f; + /* Set the active bit to 0 */ + raysInfo_los->rays_active[off / 8] &= ~(1 << (off % 8)); continue; } /* No obstacle has been hit, the path is LoS */ /* Calculate the distance */ - t = sqrtf(vec3_dot(&r.d, &r.d)); + t = sqrtf(vec3_dot(&r->d, &r->d)); /* Calculate the direction */ - Vec3 d = {r.d.x / t, r.d.y / t, r.d.z / t}; - los->directions_tx[off * 3] = d.x; - los->directions_tx[off * 3 + 1] = d.y; - los->directions_tx[off * 3 + 2] = d.z; - los->directions_rx[off * 3] = -d.x; - los->directions_rx[off * 3 + 1] = -d.y; - los->directions_rx[off * 3 + 2] = -d.z; + Vec3 d = {r->d.x / t, r->d.y / t, r->d.z / t}; + chanInfo_los->directions_tx[off] = d; + chanInfo_los->directions_rx[off] = (Vec3){-d.x, -d.y, -d.z}; /* Calculate the free space loss */ free_space_loss = free_space_loss_multiplier * t; if (free_space_loss > 1.f) { - los->a_te_re[off] = 1.f / free_space_loss; - los->a_tm_re[off] = 1.f / free_space_loss; + chanInfo_los->a_te_re[off] = 1.f / free_space_loss; + chanInfo_los->a_tm_re[off] = 1.f / free_space_loss; } else - los->a_te_re[off] =los-> a_tm_re[off] = 1.f; + chanInfo_los->a_te_re[off] =chanInfo_los-> a_tm_re[off] = 1.f; /* Calculate the delay */ - los->tau[off] = t / SPEED_OF_LIGHT; + chanInfo_los->tau[off] = t / SPEED_OF_LIGHT; /* Calculate the doppler shift */ - los->freq_shift[off] = vec3_dot(tx_vel, &d) - vec3_dot(rx_vel, &d); - los->freq_shift[off] *= carrier_frequency * 1e9 / SPEED_OF_LIGHT; + chanInfo_los->freq_shift[off] = vec3_dot(tx_vel, &d) - vec3_dot(rx_vel, &d); + chanInfo_los->freq_shift[off] *= carrier_frequency_hz / SPEED_OF_LIGHT; + /* Set the active bit to 1 */ + raysInfo_los->rays_active[off / 8] |= 1 << (off % 8); } /***************************************************************************/ @@ -614,26 +585,14 @@ 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); + raysInfo_scat->rays = (Ray*)memcpy(raysInfo_scat->rays, rays, num_tx * num_paths * sizeof(Ray)); for (size_t bounce = 0; bounce < num_bounces; ++bounce) { /* 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 tx = 0; tx < num_tx; ++tx) { for (size_t path = 0; path < num_paths; ++path, ++off_tx_path, active_bit <<= 1) { /* Check if the ray is active */ @@ -659,8 +618,8 @@ void compute_paths( continue; } /* Calculate the reflection coefficients R_{eTE} and R_{eTM} */ - material_index = scene->meshes[mesh_ind].material_index; - refl_coefs(material_index, theta, + material_ind = scene->meshes[mesh_ind].material_index; + refl_coefs(material_ind, theta, &r_te_re, &r_te_im, &r_tm_re, &r_tm_im); /* Calculate the free space loss */ @@ -673,45 +632,45 @@ void compute_paths( r_tm_im /= free_space_loss; } /* Update the gains as a' = a * refl_coefs */ - a_te_re_new = a_te_re_refl[off_tx_path] * r_te_re - a_te_im_refl[off_tx_path] * r_te_im; - a_te_im_new = a_te_re_refl[off_tx_path] * r_te_im + a_te_im_refl[off_tx_path] * r_te_re; - a_tm_re_new = a_tm_re_refl[off_tx_path] * r_tm_re - a_tm_im_refl[off_tx_path] * r_tm_im; - a_tm_im_new = a_tm_re_refl[off_tx_path] * r_tm_im + a_tm_im_refl[off_tx_path] * r_tm_re; - a_te_re_refl[off_tx_path] = a_te_re_new; - a_te_im_refl[off_tx_path] = a_te_im_new; - a_tm_re_refl[off_tx_path] = a_tm_re_new; - a_tm_im_refl[off_tx_path] = a_tm_im_new; + float a_te_re_new = a_te_re[off_tx_path] * r_te_re - a_te_im[off_tx_path] * r_te_im; + float a_te_im_new = a_te_re[off_tx_path] * r_te_im + a_te_im[off_tx_path] * r_te_re; + float a_tm_re_new = a_tm_re[off_tx_path] * r_tm_re - a_tm_im[off_tx_path] * r_tm_im; + float a_tm_im_new = a_tm_re[off_tx_path] * r_tm_im + a_tm_im[off_tx_path] * r_tm_re; + a_te_re[off_tx_path] = a_te_re_new; + a_te_im[off_tx_path] = a_te_im_new; + a_tm_re[off_tx_path] = a_tm_re_new; + a_tm_im[off_tx_path] = a_tm_im_new; /* Update the delay */ - tau_t[off_tx_path] += t / SPEED_OF_LIGHT; + tau[off_tx_path] += t / SPEED_OF_LIGHT; /* Move and reflect the ray */ - r = rays[off_tx_path]; + r = &rays[off_tx_path]; /* Advance the ray to the hit point */ - *h = vec3_scale(&r.d, t); - r.o = vec3_add(h, &r.o); + Vec3 h = vec3_scale(&r->d, t); + r->o = vec3_add(&h, &r->o); /* Reflect the ray's direction as d' = d - 2*(d \cdot n)*n */ - n = scene->meshes[mesh_ind].ns[face_ind]; - t = vec3_dot(&r.d, &n); - *h = vec3_scale(&n, 2.f * t); - r.d = vec3_sub(&r.d, h); + Vec3 n = scene->meshes[mesh_ind].ns[face_ind]; + t = vec3_dot(&r->d, &n); + h = vec3_scale(&n, 2.f * t); + r->d = vec3_sub(&r->d, &h); /* Advance the ray origin a bit to avoid intersection with the same triangle */ - *h = vec3_scale(&r.d, 1e-4f); - r.o = vec3_add(&r.o, h); + h = vec3_scale(&r->d, 1e-4f); + r->o = vec3_add(&r->o, &h); /* Calculate the doppler shift caused by the reflection */ Vec3* mesh_vel = &scene->meshes[mesh_ind].velocity; - Vec3 d_rd = vec3_sub(&r.d, &rays[off_tx_path].d); - scatter->freq_shift[off_tx_path] += vec3_dot(&d_rd, mesh_vel) * doppler_shift_multiplier; + Vec3 d_rd = vec3_sub(&r->d, &rays[off_tx_path].d); + chanInfo_scat->freq_shift[off_tx_path] += vec3_dot(&d_rd, mesh_vel) * doppler_shift_multiplier; /* Save the reflected ray */ - rays[off_tx_path] = r; + rays[off_tx_path] = *r; /***********************************************************************/ /* Scatter the rays */ /***********************************************************************/ /* Scatter a path from the hit point towards the rx */ - Ray r_scat = { .o = r.o }; + Ray r_scat = { .o = r->o }; for (size_t rx = 0; rx < num_rx; ++rx) { /* [rx, tx, bounce, path] */ size_t off_scat = ((rx * num_tx + tx) * num_bounces + bounce) * num_paths + path; @@ -725,67 +684,74 @@ void compute_paths( moeller_trumbore(&r_scat, scene, &t, &mesh_ind, &face_ind, &theta); if (mesh_ind != (uint32_t)-1 && t <= 1.f) { /* An obstacle between the hit point and the rx has been hit */ - scatter->a_te_re[off_scat] = scatter->a_te_im[off_scat] - = scatter->a_tm_re[off_scat] - = scatter->a_tm_im[off_scat] - = scatter->tau[off_scat] - = 0.f; + chanInfo_scat->a_te_re[off_scat] = chanInfo_scat->a_te_im[off_scat] + = chanInfo_scat->a_tm_re[off_scat] + = chanInfo_scat->a_tm_im[off_scat] + = chanInfo_scat->tau[off_scat] + = 0.f; continue; } /* No obstacle has been hit */ /* Calculate the scattering angle */ theta_s = acosf(vec3_dot(&r_scat.d, &n)); /* Calculate the scattering coefficients */ - float a_te_re_new, a_te_im_new, a_tm_re_new, a_tm_im_new; - scat_coefs(theta_s, theta, material_index, + scat_coefs(theta_s, theta, material_ind, &a_te_re_new, &a_te_im_new, &a_tm_re_new, &a_tm_im_new); - scatter->a_te_re[off_scat] = a_te_re_refl[off_tx_path] * a_te_re_new - - a_te_im_refl[off_tx_path] * a_te_im_new; - scatter->a_te_im[off_scat] = a_te_re_refl[off_tx_path] * a_te_im_new - + a_te_im_refl[off_tx_path] * a_te_re_new; - scatter->a_tm_re[off_scat] = a_tm_re_refl[off_tx_path] * a_tm_re_new - - a_tm_im_refl[off_tx_path] * a_tm_im_new; - scatter->a_tm_im[off_scat] = a_tm_re_refl[off_tx_path] * a_tm_im_new - + a_tm_im_refl[off_tx_path] * a_tm_re_new; + chanInfo_scat->a_te_re[off_scat] = a_te_re[off_tx_path] * a_te_re_new + - a_te_im[off_tx_path] * a_te_im_new; + chanInfo_scat->a_te_im[off_scat] = a_te_re[off_tx_path] * a_te_im_new + + a_te_im[off_tx_path] * a_te_re_new; + chanInfo_scat->a_tm_re[off_scat] = a_tm_re[off_tx_path] * a_tm_re_new + - a_tm_im[off_tx_path] * a_tm_im_new; + chanInfo_scat->a_tm_im[off_scat] = a_tm_re[off_tx_path] * a_tm_im_new + + a_tm_im[off_tx_path] * a_tm_re_new; /* Calculate the direction */ - scatter->directions_rx[off_scat * 3] = -r_scat.d.x; - scatter->directions_rx[off_scat * 3 + 1] = -r_scat.d.y; - scatter->directions_rx[off_scat * 3 + 2] = -r_scat.d.z; + chanInfo_scat->directions_rx[off_scat] = (Vec3){-r_scat.d.x, -r_scat.d.y, -r_scat.d.z}; /* Calculate the delay */ - scatter->tau[off_scat] = tau_t[off_tx_path] + d2rx / SPEED_OF_LIGHT; + chanInfo_scat->tau[off_scat] = tau[off_tx_path] + d2rx / SPEED_OF_LIGHT; /* Calculate the free space loss */ free_space_loss = free_space_loss_multiplier * d2rx; free_space_loss *= free_space_loss; if (free_space_loss > 1.f) { - scatter->a_te_re[off_scat] /= free_space_loss; - scatter->a_te_im[off_scat] /= free_space_loss; - scatter->a_tm_re[off_scat] /= free_space_loss; - scatter->a_tm_im[off_scat] /= free_space_loss; + chanInfo_scat->a_te_re[off_scat] /= free_space_loss; + chanInfo_scat->a_te_im[off_scat] /= free_space_loss; + chanInfo_scat->a_tm_re[off_scat] /= free_space_loss; + chanInfo_scat->a_tm_im[off_scat] /= free_space_loss; } /* Calculate the doppler shift */ Vec3 d_rd = vec3_sub(&r_scat.d, &rays[off_tx_path].d); float freq_shift = vec3_dot(&d_rd, mesh_vel) * doppler_shift_multiplier; - scatter->freq_shift[off_scat] -= freq_shift; + chanInfo_scat->freq_shift[off_scat] -= freq_shift; } /***********************************************************************/ /* Refract the rays */ /***********************************************************************/ /* TODO */ + } + + /* Copy the rays to the raysInfo_scat */ + size_t off_scatter_rays = (tx * num_bounces + (bounce + 1)) * num_paths; + size_t off_active = (tx * num_bounces + (bounce + 1)) * (num_paths / 8 + 1); + memcpy( + raysInfo_scat->rays + off_scatter_rays, + rays + tx * num_paths, + num_paths * sizeof(Ray) + ); + memcpy( + raysInfo_scat->rays_active + off_active, + active, + (num_paths / 8 + 1) * sizeof(uint8_t) + ); } - 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); - free(a_te_im_refl); - free(a_tm_re_refl); - free(a_tm_im_refl); - free(tau_t); - free(h); + free(a_te_re); + free(a_te_im); + free(a_tm_re); + free(a_tm_im); + free(tau); free(active); free(rays); /* Free the scene */ diff --git a/src/vizrays.c b/src/vizrays.c @@ -1,5 +1,6 @@ #include "../inc/vec3.h" /* for Vec3 */ #include "../inc/scene.h" /* for Scene, Mesh, scene_load */ +#include "../inc/ray.h" /* for Ray */ #include "../test/test.h" /* for g_numPaths, g_numBounces, g_numTx, g_numRx */ @@ -34,7 +35,7 @@ Camera g_cam = { }; uint8_t g_mouseDown = 0; -float* g_rays = NULL; +Ray* g_rays = NULL; uint8_t *g_active = NULL; Scene g_scene = {0}; @@ -53,7 +54,7 @@ void loadRays(const char* filename) { } uint32_t fileSize = (g_numBounces + 1) * g_numTx * g_numPaths * 2 * 3; - g_rays = (float*)malloc(fileSize * sizeof(float)); + g_rays = (Ray*)malloc(fileSize * sizeof(float)); if (fread(g_rays, sizeof(float), fileSize, file) != fileSize) { printf("Failed to read rays\n"); exit(8); @@ -105,57 +106,60 @@ void drawRays() { float color = (float)g_bounce_cur / g_numBounces; glColor3f(color, 0.0f, 1.0f - color); - glBegin(GL_LINES); - uint32_t 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 (uint32_t path = 0; path < g_numPaths; ++path, active_bit <<= 1) { - uint32_t idx = idx_base + path * 2 * 3; + for (uint32_t tx = 0; tx < g_numTx; ++tx) { + glBegin(GL_LINES); + + uint32_t active_byte = (tx * (g_numBounces + 1) + g_bounce_cur) * (g_numPaths / 8 + 1); + uint32_t ray_ind_base = (tx * (g_numBounces + 1) + g_bounce_cur) * g_numPaths; - if (!active_bit) { - active_byte++; - active_bit = 1; + for (uint32_t path = 0; path < g_numPaths; ++path, active_bit <<= 1) { + if (!active_bit) { + active_byte++; + active_bit = 1; + } + if (!(g_active[active_byte] & active_bit)) + { + num_skipped++; + continue; + } + + uint32_t idx = ray_ind_base + path; + GLfloat x = g_rays[idx].o.x; + GLfloat y = g_rays[idx].o.y; + GLfloat z = g_rays[idx].o.z; + /* Origin */ + glVertex3f(x, y, z); + /* Destination */ + glVertex3f( + x + g_rays[idx].d.x, + y + g_rays[idx].d.y, + z + g_rays[idx].d.z + ); } - 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]; + glEnd(); - glVertex3f(x1, y1, z1); - glVertex3f(x2, y2, z2); + /* Draw points */ + glPointSize(5.0f); + glBegin(GL_POINTS); + active_byte = g_bounce_cur * (g_numTx * g_numPaths / 8 + 1); + active_bit = 1; + for (uint32_t path = 0; path < g_numPaths; ++path) { + if (!active_bit) { + active_byte++; + active_bit = 1; + } + if (!(g_active[active_byte] & active_bit)) + continue; + uint32_t idx = ray_ind_base + path; + glVertex3f(g_rays[idx].o.x, g_rays[idx].o.y, g_rays[idx].o.z); + } + glEnd(); } - glEnd(); + printf("\rSkipped %d paths", num_skipped); fflush(stdout); - - /* Draw points */ - glPointSize(5.0f); - glBegin(GL_POINTS); - active_byte = g_bounce_cur * (g_numTx * g_numPaths / 8 + 1); - active_bit = 1; - for (uint32_t path = 0; path < g_numPaths; ++path) { - uint32_t 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(); } /** diff --git a/test/test.c b/test/test.c @@ -1,5 +1,7 @@ -#include "../inc/compute_paths.h" /* for compute_paths */ +#include "../inc/compute_paths.h" /* for compute_paths, ChannelInfo, RaysInfo */ #include "../inc/scene.h" /* for Scene, scene_load */ +#include "../inc/vec3.h" /* for Vec3 */ +#include "../inc/ray.h" /* for Ray */ #include "test.h" /* for g_numRx, g_numTx, g_numPaths, g_numBounces */ @@ -18,27 +20,37 @@ int main(int argc, char **argv) Vec3 rx_velocities[1] = {{0.0, 0.0, 0.0}}; Vec3 tx_velocities[1] = {{0.0, 0.0, 0.0}}; float carrier_frequency = 3.0; /* 3 GHz */ - PathsInfo los = { - .num_paths = 1, - .directions_rx = (float*)malloc(g_numRx * g_numTx * 3 * sizeof(float)), - .directions_tx = (float*)malloc(g_numRx * g_numTx * 3 * sizeof(float)), + ChannelInfo chanInfo_los = { + .num_rays = 1, + .directions_rx = (Vec3*)malloc(g_numRx * g_numTx * sizeof(Vec3)), + .directions_tx = (Vec3*)malloc(g_numRx * g_numTx * sizeof(Vec3)), .a_te_re = (float*)malloc(g_numRx * g_numTx * sizeof(float)), .a_te_im = (float*)malloc(g_numRx * g_numTx * sizeof(float)), .a_tm_re = (float*)malloc(g_numRx * g_numTx * sizeof(float)), .a_tm_im = (float*)malloc(g_numRx * g_numTx * sizeof(float)), .tau = (float*)malloc(g_numRx * g_numTx * sizeof(float)), - .freq_shift = (float*)malloc(g_numRx * g_numTx * sizeof(float)) + .freq_shift = (float*)malloc(g_numRx * g_numTx * sizeof(float)), }; - PathsInfo scatter = { - .num_paths = g_numBounces * g_numPaths, - .directions_rx = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * 3 * sizeof(float)), - .directions_tx = (float*)malloc(g_numPaths * 3 * sizeof(float)), + RaysInfo raysInfo_los = { + .rays = (Ray*)malloc(g_numRx * g_numTx * sizeof(Ray)), + .rays_active = (uint8_t*)malloc(g_numRx * g_numTx * sizeof(uint8_t) / 8 + 1) + }; + ChannelInfo chanInfo_scat = { + .num_rays = g_numBounces * g_numPaths, + .directions_rx = (Vec3*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(Vec3)), + .directions_tx = (Vec3*)malloc(g_numPaths * sizeof(Vec3)), .a_te_re = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), .a_te_im = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), .a_tm_re = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), .a_tm_im = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), .tau = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), - .freq_shift = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)) + .freq_shift = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), + }; + RaysInfo raysInfo_scat = { + .num_bounces = g_numBounces + 1, + .num_rays = g_numPaths, + .rays = (Ray*)malloc(g_numRx * g_numTx * (g_numBounces + 1) * g_numPaths * sizeof(Ray)), + .rays_active = (uint8_t*)malloc(g_numRx * g_numTx * (g_numBounces + 1) * (g_numPaths / 8 + 1) * sizeof(uint8_t)) }; Scene scene = scene_load(argv[1]); compute_paths( @@ -49,18 +61,32 @@ int main(int argc, char **argv) tx_velocities, carrier_frequency, g_numRx, g_numTx, g_numPaths, g_numBounces, - &los, &scatter + &chanInfo_los, &raysInfo_los, + &chanInfo_scat, &raysInfo_scat ); /* Save the results */ FILE *f; - #define WRITE_BIN(name, data, size) \ + #define WRITE_BIN(name, data, dt, size) \ f = fopen(name, "wb"); \ - fwrite(data, sizeof(float), size, f); \ + fwrite(data, sizeof(dt), size, f); \ fclose(f); + + WRITE_BIN( + "rays.bin", + raysInfo_scat.rays, + float, + g_numRx * g_numTx * (g_numBounces + 1) * g_numPaths * 6 + ); + WRITE_BIN( + "active.bin", + raysInfo_scat.rays_active, + uint8_t, + g_numRx * g_numTx * (g_numBounces + 1) * (g_numPaths / 8 + 1) + ); /* Use this macro to write what you would like to inspect to a binary file */ /* Example: */ - /* WRITE_BIN("los_directions_rx.bin", los.directions_rx, g_numRx * g_numTx * 3); */ + /* WRITE_BIN("los_directions_rx.bin", los.directions_rx, float, g_numRx * g_numTx * 3); */ }