Added some comments
This commit is contained in:
parent
1eede7d8c4
commit
38f866cd1b
32
channel.py
32
channel.py
@ -16,6 +16,12 @@ pilot_value = 1 + 1j
|
|||||||
snr_db = 300
|
snr_db = 300
|
||||||
|
|
||||||
def sim(in_data):
|
def sim(in_data):
|
||||||
|
"""
|
||||||
|
Simulate effects of communication channel.
|
||||||
|
|
||||||
|
Convolves the channel response, and adds random noise to the signal.
|
||||||
|
"""
|
||||||
|
|
||||||
out_data = np.ndarray((len(in_data), len(in_data[0])), dtype=np.csingle)
|
out_data = np.ndarray((len(in_data), len(in_data[0])), dtype=np.csingle)
|
||||||
|
|
||||||
# noise stuff is straight copied from the DSP illustrations article
|
# noise stuff is straight copied from the DSP illustrations article
|
||||||
@ -34,6 +40,32 @@ def sim(in_data):
|
|||||||
# Again, most of this is stolen from the guide
|
# Again, most of this is stolen from the guide
|
||||||
# this sort of stuff I had no idea about before I read the guide
|
# this sort of stuff I had no idea about before I read the guide
|
||||||
def estimate(in_data, pilots=0):
|
def estimate(in_data, pilots=0):
|
||||||
|
"""
|
||||||
|
Estimate channel effects by some cool properties.
|
||||||
|
|
||||||
|
Since the effects of the channel medium is a convolution of the transmitted signal,
|
||||||
|
we can abuse this for some easy math.
|
||||||
|
|
||||||
|
We take the time domain input signal and turn that into a frequency domain signal.
|
||||||
|
If we had a perfect channel, this frequency domain signal would exactly equal the signal
|
||||||
|
transmitted. But it doesn't. However, we are in the frequency domain, which means
|
||||||
|
convolution turns into multiplication, and to find the effect of the channel on each
|
||||||
|
subcarrier, we can simply use division.
|
||||||
|
|
||||||
|
Unfortunately, we don't know what the original data was, so we use "pilot" subchannels, which transmit
|
||||||
|
known information. We can use this to get estimates for each of the pilot carriers, and finally, we can interpolate
|
||||||
|
these values to get an estimate for everything.
|
||||||
|
|
||||||
|
There are a few issues with this method:
|
||||||
|
1: It is very estimate-ey. We have to interpolate from a subset of the carriers.
|
||||||
|
2: It is quite inefficient. We are sending useless information on every symbol.
|
||||||
|
|
||||||
|
I think a better solution is to send a known symbol (or a set of known symbols)
|
||||||
|
at the beginnning of each transmission instead. This means we get a full channel estimate
|
||||||
|
every time. This also has the advantage of being able to synchronise the symbols. Since I
|
||||||
|
will be implementing some sort of protocol anyways, I think this will be a good idea. As well,
|
||||||
|
we move slow enough that the channel will not likely change significantly over a single packet.
|
||||||
|
"""
|
||||||
|
|
||||||
all_carriers = np.arange(len(in_data[0]))
|
all_carriers = np.arange(len(in_data[0]))
|
||||||
|
|
||||||
|
24
main.py
24
main.py
@ -7,7 +7,6 @@ Hopefully eventually this modem design makes it onto an fpga.
|
|||||||
TODO:
|
TODO:
|
||||||
Change channel estimation to pre-amble symbols
|
Change channel estimation to pre-amble symbols
|
||||||
Add comments for functions
|
Add comments for functions
|
||||||
Explain what the main function is doing
|
|
||||||
Add more errors, like a shifted signal
|
Add more errors, like a shifted signal
|
||||||
Add support for 16-QAM, 64-QAM, etc...
|
Add support for 16-QAM, 64-QAM, etc...
|
||||||
Add some sort of payload support, i.e. be able to drop the padding at the end
|
Add some sort of payload support, i.e. be able to drop the padding at the end
|
||||||
@ -29,6 +28,14 @@ import qam
|
|||||||
from serpar import parallelise, serialise
|
from serpar import parallelise, serialise
|
||||||
|
|
||||||
def cp_add(in_data, prefix_len):
|
def cp_add(in_data, prefix_len):
|
||||||
|
"""
|
||||||
|
Adds a cyclic prefix to an array of symbols, with a specified length.
|
||||||
|
|
||||||
|
This changes the linear convolution of the data into a circular convolution,
|
||||||
|
allowing easier equalization.
|
||||||
|
As well, it helps remove inter-symbol interference.
|
||||||
|
"""
|
||||||
|
|
||||||
out_data = np.ndarray((len(in_data), len(in_data[0]) + prefix_len), dtype=np.csingle)
|
out_data = np.ndarray((len(in_data), len(in_data[0]) + prefix_len), dtype=np.csingle)
|
||||||
|
|
||||||
for i in range(len(in_data)):
|
for i in range(len(in_data)):
|
||||||
@ -38,6 +45,10 @@ def cp_add(in_data, prefix_len):
|
|||||||
return out_data
|
return out_data
|
||||||
|
|
||||||
def cp_remove(in_data, prefix_len):
|
def cp_remove(in_data, prefix_len):
|
||||||
|
"""
|
||||||
|
Removes cyclic prefix from retrieved data. Naively assumes that data is correctly aligned.
|
||||||
|
"""
|
||||||
|
|
||||||
out_data = np.ndarray((len(in_data), len(in_data[0]) - prefix_len), dtype=np.csingle)
|
out_data = np.ndarray((len(in_data), len(in_data[0]) - prefix_len), dtype=np.csingle)
|
||||||
|
|
||||||
for i in range(len(in_data)):
|
for i in range(len(in_data)):
|
||||||
@ -54,25 +65,36 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
bytes = bytearray(data, 'utf8')
|
bytes = bytearray(data, 'utf8')
|
||||||
|
|
||||||
|
# Turn data into a parallelised form, able to be QAM-modulated
|
||||||
parallel = parallelise(64, bytes)
|
parallel = parallelise(64, bytes)
|
||||||
|
|
||||||
|
# modulate data with a QAM scheme
|
||||||
modulated = qam.modulate(parallel, pilots=20)
|
modulated = qam.modulate(parallel, pilots=20)
|
||||||
|
|
||||||
|
# Run IFFT to get a time-domain signal to send
|
||||||
ofdm_time = np.fft.ifft(modulated)
|
ofdm_time = np.fft.ifft(modulated)
|
||||||
|
|
||||||
|
# Add cyclic prefix to each symbol
|
||||||
tx = cp_add(ofdm_time, 16)
|
tx = cp_add(ofdm_time, 16)
|
||||||
|
|
||||||
|
# Simulate effects of a multipath channel
|
||||||
rx = channel.sim(tx)
|
rx = channel.sim(tx)
|
||||||
|
|
||||||
|
# Remove cyclic prefix from incoming symbols
|
||||||
ofdm_cp_removed = cp_remove(rx, 16)
|
ofdm_cp_removed = cp_remove(rx, 16)
|
||||||
|
|
||||||
|
# Bring symbols back into frequency domain to get carrier channels
|
||||||
to_equalize = np.fft.fft(ofdm_cp_removed)
|
to_equalize = np.fft.fft(ofdm_cp_removed)
|
||||||
|
|
||||||
|
# Find an estimate for channel effect
|
||||||
H_est = channel.estimate(to_equalize, pilots=20)
|
H_est = channel.estimate(to_equalize, pilots=20)
|
||||||
|
|
||||||
|
# Equalise based on estimated channel
|
||||||
to_decode = channel.equalize(to_equalize, H_est)
|
to_decode = channel.equalize(to_equalize, H_est)
|
||||||
|
|
||||||
|
# Demodulate symbol into output data
|
||||||
to_serialise = qam.demodulate(to_decode, pilots=20)
|
to_serialise = qam.demodulate(to_decode, pilots=20)
|
||||||
|
|
||||||
|
# Turn data back into string
|
||||||
data = serialise(64, to_serialise)
|
data = serialise(64, to_serialise)
|
||||||
print(data)
|
print(data)
|
||||||
|
8
qam.py
8
qam.py
@ -16,6 +16,10 @@ def modulate(in_data, pilots=0):
|
|||||||
"""
|
"""
|
||||||
Modulates into 4-QAM encoding, might change that number later.
|
Modulates into 4-QAM encoding, might change that number later.
|
||||||
|
|
||||||
|
This turns input data into a "constellation" of complex numbers,
|
||||||
|
ready to be fed into an IFFT. This constellation could also be used
|
||||||
|
directly with an IQ modulator.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
in_data - m X n array, m symbols to run on
|
in_data - m X n array, m symbols to run on
|
||||||
pilots (optional) - number of pilot signals to intersperse into carriers
|
pilots (optional) - number of pilot signals to intersperse into carriers
|
||||||
@ -54,6 +58,10 @@ def modulate(in_data, pilots=0):
|
|||||||
return out_data
|
return out_data
|
||||||
|
|
||||||
def demodulate(in_data, pilots=0):
|
def demodulate(in_data, pilots=0):
|
||||||
|
"""
|
||||||
|
Demodulates incoming signal.
|
||||||
|
"""
|
||||||
|
|
||||||
all_carriers = np.arange(len(in_data[0]), dtype=int)
|
all_carriers = np.arange(len(in_data[0]), dtype=int)
|
||||||
|
|
||||||
if pilots > 0:
|
if pilots > 0:
|
||||||
|
Loading…
Reference in New Issue
Block a user