generator of image sources

This commit is contained in:
zymon 2024-06-02 23:25:11 +02:00
parent 7505a5f5fc
commit 88ba6ea0b0

View file

@ -86,14 +86,6 @@ function ISM!(
o_min, o_max = config.order o_min, o_max = config.order
# Allocate memory
rd = @MVector zeros(T, 3) # Container for random displacement
isp = @MVector zeros(T, 3) # Container for relative image source position
b = @MVector zeros(T, 6) # Container for effective reflection coefficient
rx_DoA = @MVector zeros(T, 3) # Container for direction of incoming ray to receiver
tx_DoA = @MVector zeros(T, 3) # Container for direction of ray coming out from transmitter
Rp = @MVector zeros(T, 3) #
# Main loop # Main loop
for n = -N[1]:N[1], l = -N[2]:N[2], m = -N[3]:N[3] for n = -N[1]:N[1], l = -N[2]:N[2], m = -N[3]:N[3]
r = (n, l, m) # Wall reflection indicator r = (n, l, m) # Wall reflection indicator
@ -106,17 +98,14 @@ function ISM!(
if o_min <= o && (o <= o_max || o_max == -1) if o_min <= o && (o <= o_max || o_max == -1)
# Compute Rp part # Compute Rp part
for i = 1:3 Rp = @. (1 - 2p) * tx.position - rx.position
Rp[i] = (1 .- 2 * p[i]) * tx.position[i] - rx.position[i]
end
# image source position for given permutation # image source position for given permutation
isp .= Rp .+ Rr isp = Rp .+ Rr
if config.isd > 0.0 && o > 0 if config.isd > 0.0 && o > 0
# generate random displacement for the image source # generate random displacement for the image source
randn!(config.lrng, rd) isp .+= randn(config.lrng) * config.isd
isp .+= rd .* config.isd
end end
# Distance between receiver and image source # Distance between receiver and image source
@ -128,17 +117,17 @@ function ISM!(
if τ <= Nh / config.fs # Check if it still in transfer function rangΩ if τ <= Nh / config.fs # Check if it still in transfer function rangΩ
# Compute value of reflection coefficients # Compute value of reflection coefficients
b .= room.β .^ abs.((n - q, n, l - j, l, m - k, m)) b = @. room.β ^ abs((n - q, n, l - j, l, m - k, m))
# Direction of Arrival of ray incoming from image source to receiver # Direction of Arrival of ray incoming from image source to receiver
rx_DoA .= isp ./ d rx_DoA = isp ./ d
# Compute receiver directivity gain # Compute receiver directivity gain
rx_DG = directivity_pattern(SVector{3}(rx_DoA), rx.B, rx.directivity) rx_DG = directivity_pattern(SVector{3}(rx_DoA), rx.B, rx.directivity)
# Direction of Arrival of ray coming out from transmitter to wall # Direction of Arrival of ray coming out from transmitter to wall
perm = (abs(n - q) + abs(n), abs(l - j) + abs(l), abs(m - k) + abs(m)) perm = (abs(n - q) + abs(n), abs(l - j) + abs(l), abs(m - k) + abs(m))
tx_DoA .= -rx_DoA .* (-1, -1, -1).^perm tx_DoA = @. -rx_DoA * (-1, -1, -1)^perm
# Compute transmitter directivity gain # Compute transmitter directivity gain
tx_DG = directivity_pattern(SVector{3}(tx_DoA), tx.B, tx.directivity) tx_DG = directivity_pattern(SVector{3}(tx_DoA), tx.B, tx.directivity)
@ -163,3 +152,112 @@ function ISM!(
end end
end end
end end
function image_source_generator(
tx::TxRx,
rx::TxRx,
room::RectangularRoom,
config::ISMConfig;
)
T = Float64
# Number of samples in impulse response
Nh = config.N
# Samples to distance coefficient [m]
Γ = room.c / config.fs
# Transform size of the room from meters to samples
Lₛ = room.L ./ Γ
# Compute maximal wall reflection
N = ceil.(Int, Nh ./ (2 .* Lₛ))
o_min, o_max = config.order
# Main loop
return (begin
r = (n, l, m) # Wall reflection indicator
Rr = 2 .* r .* room.L # Wall lattice
p = @SVector [q, j, k] # Permutation tuple
# Order of reflection generated by image source
o = sum(abs.(2 .* r .- p))
if o_min <= o && (o <= o_max || o_max == -1)
# Compute Rp part
Rp = @. (1 - 2p) * tx.position - rx.position
# image source position for given permutation
isp = Rp .+ Rr
if config.isd > 0.0 && o > 0
# generate random displacement for the image source
isp .+= randn(config.lrng) * config.isd
end
# Distance between receiver and image source
d = norm(isp)
# Propagation time between receiver and image source
τ = d / room.c
if τ <= Nh / config.fs # Check if it still in transfer function rangΩ
# Compute value of reflection coefficients
b = @. room.β ^ abs((n - q, n, l - j, l, m - k, m))
# Direction of Arrival of ray incoming from image source to receiver
rx_DoA = isp ./ d
# Compute receiver directivity gain
rx_DG = directivity_pattern(SVector{3}(rx_DoA), rx.B, rx.directivity)
# Direction of Arrival of ray coming out from transmitter to wall
perm = (abs(n - q) + abs(n), abs(l - j) + abs(l), abs(m - k) + abs(m))
tx_DoA = @. -rx_DoA * (-1, -1, -1).^perm
# Compute transmitter directivity gain
tx_DG = directivity_pattern(SVector{3}(tx_DoA), tx.B, tx.directivity)
# Compute attenuation coefficient
A = tx_DG * rx_DG * prod(b) / (4π * d)
(A, τ, isp, o)
end
end
end for n = -N[1]:N[1], l = -N[2]:N[2], m = -N[3]:N[3], q 0:1, j 0:1, k 0:1)
end
function ISM_slower!(
h::AbstractVector{T},
tx::TxRx,
rx::TxRx,
room::RectangularRoom,
config::ISMConfig;
) where {T<:AbstractFloat}
# Impulse parameters
Δt = 1 / config.fs
ω = 2π / config.Wd
twid = π * config.fs
for a in image_source_generator(tx, rx, room, config)
if nothing !== a
A, τ, _, _ = a
# Compute range of samples in transfer function
i_s = max(ceil(Int, (τ - config.Wd / 2) * config.fs) + 1, 1) # start
i_e = min(floor(Int, (τ + config.Wd / 2) * config.fs) + 1, config.N) # end
# Insert yet another impulse into transfer function
for i i_s:i_e
t = (i - 1) * Δt - τ # time signature
w = fma(cos_fast(ω*t), 0.5, 0.5) # Hann window
x = twid * t
sinc = ifelse(iszero(x), 1.0, sin_fast(x)/x)
@inbounds h[i] += w * A * sinc
end
end
end
end