From 02d1e2f0ef89f7c9031a93c274ed599b6b3158f7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 19:07:59 +0200 Subject: [PATCH 01/14] Add CTCSS removal --- FMControl.cpp | 33 +++++++++++++++++++++++++-------- FMControl.h | 9 ++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index baa429c..72188dd 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -24,20 +24,36 @@ #include #endif -const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis -const unsigned int FM_MASK = 0x00000FFFU; +const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis +const float FILTER_GAIN_DB = 0.0F; +const unsigned int FM_MASK = 0x00000FFFU; CFMControl::CFMControl(CFMNetwork* network) : m_network(network), m_enabled(false), m_incomingRFAudio(1600U, "Incoming RF FM Audio"), -m_preemphasis(0.3889703155F, -0.32900055326F, 0.0F, 1.0F, 0.2820291817F, 0.0F, EMPHASIS_GAIN_DB), -m_deemphasis(1.0F, 0.2820291817F, 0.0F, 0.3889703155F, -0.32900055326F, 0.0F, EMPHASIS_GAIN_DB) +m_preemphasis (NULL), +m_deemphasis (NULL), +m_filterStage1(NULL), +m_filterStage2(NULL), +m_filterStage3(NULL) { + m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, EMPHASIS_GAIN_DB); + m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, EMPHASIS_GAIN_DB); + + m_filterStage1 = new CIIRDirectForm1Filter(0.29495028f, 0.0f, -0.29495028f, 1.0f, -0.61384624f, -0.057158668f, FILTER_GAIN_DB); + m_filterStage2 = new CIIRDirectForm1Filter(1.0f, 2.0f, 1.0f, 1.0f, 0.9946123f, 0.6050482f, FILTER_GAIN_DB); + m_filterStage3 = new CIIRDirectForm1Filter(1.0f, -2.0f, 1.0f, 1.0f, -1.8414584f, 0.8804949f, FILTER_GAIN_DB); } CFMControl::~CFMControl() { + delete m_preemphasis ; + delete m_deemphasis ; + + delete m_filterStage1; + delete m_filterStage2; + delete m_filterStage3; } bool CFMControl::writeModem(const unsigned char* data, unsigned int length) @@ -57,7 +73,6 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) if (data[0U] != TAG_DATA) return false; - m_incomingRFAudio.addData(data + 1U, length - 1U); unsigned int bufferLength = m_incomingRFAudio.dataSize(); if (bufferLength > 255U) @@ -97,8 +112,10 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) } //De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_deemphasis.filter(samples[i]); + for (unsigned int i = 0U; i < nSamples; i++) { + samples[i] = m_deemphasis->filter(samples[i]); + samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); + } #if defined(DUMP_RF_AUDIO) if(audiofile != NULL) @@ -152,7 +169,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) //Pre-emphasise the data and other stuff. for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_preemphasis.filter(samples[i]); + samples[i] = m_preemphasis->filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; diff --git a/FMControl.h b/FMControl.h index 9067d89..c7af709 100644 --- a/FMControl.h +++ b/FMControl.h @@ -26,7 +26,7 @@ // Uncomment this to dump audio to a raw audio file // The file will be written in same folder as executable // Toplay the file : aplay -f FLOAT_LE -c1 -r8000 -t raw audiodump.bin -//#define DUMP_RF_AUDIO +// #define DUMP_RF_AUDIO class CFMControl { public: @@ -45,8 +45,11 @@ private: CFMNetwork* m_network; bool m_enabled; CRingBuffer m_incomingRFAudio; - CIIRDirectForm1Filter m_preemphasis; - CIIRDirectForm1Filter m_deemphasis; + CIIRDirectForm1Filter * m_preemphasis; + CIIRDirectForm1Filter * m_deemphasis; + CIIRDirectForm1Filter * m_filterStage1; + CIIRDirectForm1Filter * m_filterStage2; + CIIRDirectForm1Filter * m_filterStage3; }; #endif From a28aa7792749ecf49550e8f4ad5f0ed7514e25ae Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 07:31:48 +0200 Subject: [PATCH 02/14] Add deemphasis and remove CTCSS, emphasis temp deactivated --- FMControl.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 72188dd..fadf005 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -41,6 +41,7 @@ m_filterStage3(NULL) m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, EMPHASIS_GAIN_DB); m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, EMPHASIS_GAIN_DB); + //cheby type 1 0.2dB cheby type 1 3rd order 300-2700Hz fs=8000 m_filterStage1 = new CIIRDirectForm1Filter(0.29495028f, 0.0f, -0.29495028f, 1.0f, -0.61384624f, -0.057158668f, FILTER_GAIN_DB); m_filterStage2 = new CIIRDirectForm1Filter(1.0f, 2.0f, 1.0f, 1.0f, 0.9946123f, 0.6050482f, FILTER_GAIN_DB); m_filterStage3 = new CIIRDirectForm1Filter(1.0f, -2.0f, 1.0f, 1.0f, -1.8414584f, 0.8804949f, FILTER_GAIN_DB); @@ -111,7 +112,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) samples[nSamples++] = float(sample2) / 2048.0F; } - //De-emphasise the data and any other processing needed (maybe a low-pass filter to remove the CTCSS) + //De-emphasise the data and remove CTCSS for (unsigned int i = 0U; i < nSamples; i++) { samples[i] = m_deemphasis->filter(samples[i]); samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); @@ -164,12 +165,12 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) for (unsigned int i = 0U; i < length; i += 2U) { unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; - samples[nSamples++] = (float(sample) / 32767.0F) - 1.0F; + samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; } //Pre-emphasise the data and other stuff. - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_preemphasis->filter(samples[i]); + //for (unsigned int i = 0U; i < nSamples; i++) + // samples[i] = m_preemphasis->filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; @@ -180,7 +181,7 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); - pack = 0; + pack = 0U; pack = ((unsigned int)sample1) << 12; pack |= sample2; From 0b8a9a1a4cef43202c42eb1f88c31f51d96f7569 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 07:32:09 +0200 Subject: [PATCH 03/14] Increase FM TX Buffer size --- Modem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modem.cpp b/Modem.cpp index cb2c18c..3a6974d 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -160,7 +160,7 @@ m_rxNXDNData(1000U, "Modem RX NXDN"), m_txNXDNData(1000U, "Modem TX NXDN"), m_txPOCSAGData(1000U, "Modem TX POCSAG"), m_rxFMData(1000U, "Modem RX FM"), -m_txFMData(1000U, "Modem TX FM"), +m_txFMData(5000U, "Modem TX FM"), m_rxTransparentData(1000U, "Modem RX Transparent"), m_txTransparentData(1000U, "Modem TX Transparent"), m_sendTransparentDataFrameType(0U), @@ -232,7 +232,7 @@ void CModem::setSerialParams(const std::string& protocol, unsigned int address, m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, true); + m_serial = new CSerialController(m_port, speed, false); } void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) From 75d5083f8e20ad32a7e52c720a6c0fa86e0f3ef3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 19:59:15 +0200 Subject: [PATCH 04/14] fixe network byte ordering, change audio dump to dumep 16 bit samples --- FMControl.cpp | 13 ++++++------- FMControl.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index fadf005..1e460b7 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -118,21 +118,20 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); } -#if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fwrite(samples, sizeof(float), nSamples, audiofile); -#endif - unsigned short out[170U]; // 85 * 2 unsigned int nOut = 0U; // Repack the data (8-bit unsigned values containing unsigned 16-bit data) for (unsigned int i = 0U; i < nSamples; i++) { unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = (sample >> 8) & 0xFFU; - out[nOut++] = (sample >> 0) & 0xFFU; + out[nOut++] = ((sample >> 8) & 0x00FFU) | ((sample << 8) & 0xFF00U);//change endianess to network order, transmit MSB first } +#if defined(DUMP_RF_AUDIO) + if(audiofile != NULL) + fwrite(out, sizeof(unsigned short), nOut, audiofile); +#endif + #if defined(DUMP_RF_AUDIO) if(audiofile != NULL) fclose(audiofile); diff --git a/FMControl.h b/FMControl.h index c7af709..1647010 100644 --- a/FMControl.h +++ b/FMControl.h @@ -25,7 +25,7 @@ // Uncomment this to dump audio to a raw audio file // The file will be written in same folder as executable -// Toplay the file : aplay -f FLOAT_LE -c1 -r8000 -t raw audiodump.bin +// Toplay the file : ffplay -autoexit -f u16be -ar 8000 audiodump.bin // #define DUMP_RF_AUDIO class CFMControl { From c2187fd6243683110f96161a993ac2fb6bbc2935 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 20:19:46 +0200 Subject: [PATCH 05/14] Add 460800 serial speed --- SerialController.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SerialController.cpp b/SerialController.cpp index aacc6c6..970501a 100644 --- a/SerialController.cpp +++ b/SerialController.cpp @@ -304,6 +304,10 @@ bool CSerialController::open() ::cfsetospeed(&termios, B230400); ::cfsetispeed(&termios, B230400); break; + case 460800U: + ::cfsetospeed(&termios, B460800); + ::cfsetispeed(&termios, B460800); + break; default: LogError("Unsupported serial port speed - %u", m_speed); ::close(m_fd); From 409e0de721c1ba615019aa3058cb1fde8c1b421e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 07:03:01 +0200 Subject: [PATCH 06/14] Send correct number of bytes --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index 1e460b7..b07206a 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -137,7 +137,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) fclose(audiofile); #endif - return m_network->writeData((unsigned char*)out, nOut); + return m_network->writeData((unsigned char*)out, nOut * sizeof(unsigned short)); } return true; From 8d4241d154e5e4d308d2f5087c04e7753c7ec437 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 08:20:39 +0200 Subject: [PATCH 07/14] Reenable RTS --- Modem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modem.cpp b/Modem.cpp index 3a6974d..e4dcb79 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -232,7 +232,7 @@ void CModem::setSerialParams(const std::string& protocol, unsigned int address, m_serial = new CI2CController(m_port, address); else #endif - m_serial = new CSerialController(m_port, speed, false); + m_serial = new CSerialController(m_port, speed, true); } void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency) From eef364b1a97aec7749a9fcb32f35d66349cf092d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 08:38:17 +0200 Subject: [PATCH 08/14] Enable Pre emphasis --- FMControl.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index b07206a..f1dc045 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -24,9 +24,10 @@ #include #endif -const float EMPHASIS_GAIN_DB = 0.0F; //Gain needs to be the same for pre an deeemphasis -const float FILTER_GAIN_DB = 0.0F; -const unsigned int FM_MASK = 0x00000FFFU; +const float DEEMPHASIS_GAIN_DB = 0.0F; +const float PREEMPHASIS_GAIN_DB = 30.0F; +const float FILTER_GAIN_DB = 0.0F; +const unsigned int FM_MASK = 0x00000FFFU; CFMControl::CFMControl(CFMNetwork* network) : m_network(network), @@ -38,8 +39,8 @@ m_filterStage1(NULL), m_filterStage2(NULL), m_filterStage3(NULL) { - m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, EMPHASIS_GAIN_DB); - m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, EMPHASIS_GAIN_DB); + m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, PREEMPHASIS_GAIN_DB); + m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, DEEMPHASIS_GAIN_DB); //cheby type 1 0.2dB cheby type 1 3rd order 300-2700Hz fs=8000 m_filterStage1 = new CIIRDirectForm1Filter(0.29495028f, 0.0f, -0.29495028f, 1.0f, -0.61384624f, -0.057158668f, FILTER_GAIN_DB); @@ -168,8 +169,8 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) } //Pre-emphasise the data and other stuff. - //for (unsigned int i = 0U; i < nSamples; i++) - // samples[i] = m_preemphasis->filter(samples[i]); + for (unsigned int i = 0U; i < nSamples; i++) + samples[i] = m_preemphasis->filter(samples[i]); // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; From 98cd2404f56575c74975d9e7d770fe68671f3b04 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 09:17:45 +0200 Subject: [PATCH 09/14] Use GNU Radio emphasis filters, add filters generation scripts --- FMControl.cpp | 6 +++--- Tools/DeEmphasis.py | 43 +++++++++++++++++++++++++++++++++++++ Tools/PreEmphasis.py | 51 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 Tools/DeEmphasis.py create mode 100644 Tools/PreEmphasis.py diff --git a/FMControl.cpp b/FMControl.cpp index f1dc045..d558ac7 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -25,7 +25,7 @@ #endif const float DEEMPHASIS_GAIN_DB = 0.0F; -const float PREEMPHASIS_GAIN_DB = 30.0F; +const float PREEMPHASIS_GAIN_DB = 0.0F; const float FILTER_GAIN_DB = 0.0F; const unsigned int FM_MASK = 0x00000FFFU; @@ -39,8 +39,8 @@ m_filterStage1(NULL), m_filterStage2(NULL), m_filterStage3(NULL) { - m_preemphasis = new CIIRDirectForm1Filter(0.38897032f, -0.32900053f, 0.0f, 1.0f, 0.28202918f, 0.0f, PREEMPHASIS_GAIN_DB); - m_deemphasis = new CIIRDirectForm1Filter(1.0f,0.28202918f, 0.0f, 0.38897032f, -0.32900053f, 0.0f, DEEMPHASIS_GAIN_DB); + m_preemphasis = new CIIRDirectForm1Filter(8.315375384336983F,-7.03334621603483F,0.0F,1.0F,0.282029168302153F,0.0F, PREEMPHASIS_GAIN_DB); + m_deemphasis = new CIIRDirectForm1Filter(0.07708787090460224F,0.07708787090460224F,0.0F,1.0F,-0.8458242581907955F,0.0F, DEEMPHASIS_GAIN_DB); //cheby type 1 0.2dB cheby type 1 3rd order 300-2700Hz fs=8000 m_filterStage1 = new CIIRDirectForm1Filter(0.29495028f, 0.0f, -0.29495028f, 1.0f, -0.61384624f, -0.057158668f, FILTER_GAIN_DB); diff --git a/Tools/DeEmphasis.py b/Tools/DeEmphasis.py new file mode 100644 index 0000000..44320c9 --- /dev/null +++ b/Tools/DeEmphasis.py @@ -0,0 +1,43 @@ +#based on https://github.com/gnuradio/gnuradio/blob/master/gr-analog/python/analog/fm_emph.py + +import math +import cmath +import numpy as np +import scipy.signal as signal +import pylab as pl + +tau = 750e-6 +fs = 8000 +fh = 2700 + +# Digital corner frequency +w_c = 1.0 / tau + +# Prewarped analog corner frequency +w_ca = 2.0 * fs * math.tan(w_c / (2.0 * fs)) + +# Resulting digital pole, zero, and gain term from the bilinear +# transformation of H(s) = w_ca / (s + w_ca) to +# H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) +k = -w_ca / (2.0 * fs) +z1 = -1.0 +p1 = (1.0 + k) / (1.0 - k) +b0 = -k / (1.0 - k) + +btaps = [ b0 * 1.0, b0 * -z1, 0 ] +ataps = [ 1.0, -p1, 0 ] + +# Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC + + +taps = np.concatenate((btaps, ataps), axis=0) +print("Taps") +print(*taps, "", sep=",", end="\n") + +f,h = signal.freqz(btaps,ataps, fs=fs) +pl.plot(f, 20*np.log10(np.abs(h))) +pl.xlabel('frequency/Hz') +pl.ylabel('gain/dB') +pl.ylim(top=0,bottom=-30) +pl.xlim(left=0, right=fh*2.5) +pl.show() \ No newline at end of file diff --git a/Tools/PreEmphasis.py b/Tools/PreEmphasis.py new file mode 100644 index 0000000..22c81f6 --- /dev/null +++ b/Tools/PreEmphasis.py @@ -0,0 +1,51 @@ +#based on https://github.com/gnuradio/gnuradio/blob/master/gr-analog/python/analog/fm_emph.py + +import math +import cmath +import numpy as np +import scipy.signal as signal +import pylab as pl + +tau = 750e-6 +fs = 8000 +fh = 2700 + +# Digital corner frequencies +w_cl = 1.0 / tau +w_ch = 2.0 * math.pi * fh + +# Prewarped analog corner frequencies +w_cla = 2.0 * fs * math.tan(w_cl / (2.0 * fs)) +w_cha = 2.0 * fs * math.tan(w_ch / (2.0 * fs)) + +# Resulting digital pole, zero, and gain term from the bilinear +# transformation of H(s) = (s + w_cla) / (s + w_cha) to +# H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) +kl = -w_cla / (2.0 * fs) +kh = -w_cha / (2.0 * fs) +z1 = (1.0 + kl) / (1.0 - kl) +p1 = (1.0 + kh) / (1.0 - kh) +b0 = (1.0 - kl) / (1.0 - kh) + +# Since H(s = infinity) = 1.0, then H(z = -1) = 1.0 and +# this filter has 0 dB gain at fs/2.0. +# That isn't what users are going to expect, so adjust with a +# gain, g, so that H(z = 1) = 1.0 for 0 dB gain at DC. +w_0dB = 2.0 * math.pi * 0.0 +g = abs(1.0 - p1 * cmath.rect(1.0, -w_0dB)) \ +/ (b0 * abs(1.0 - z1 * cmath.rect(1.0, -w_0dB))) + +btaps = [ g * b0 * 1.0, g * b0 * -z1, 0] +ataps = [ 1.0, -p1, 0] + +taps = np.concatenate((btaps, ataps), axis=0) +print("Taps") +print(*taps, "", sep=",", end="\n") + +f,h = signal.freqz(btaps,ataps, fs=fs) +pl.plot(f, 20*np.log10(np.abs(h))) +pl.xlabel('frequency/Hz') +pl.ylabel('gain/dB') +pl.ylim(top=30,bottom=0) +pl.xlim(left=0, right=fh*2.5) +pl.show() \ No newline at end of file From 015edf9b81c196ebbf7784db2ee2782932aafca7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 11:01:53 +0200 Subject: [PATCH 10/14] Simplify readmodem, only one loop --- FMControl.cpp | 90 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index d558ac7..74b3537 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -24,6 +24,8 @@ #include #endif +#define SWAP_BYTES_16(a) (((a >> 8) & 0x00FFU) | ((a << 8) & 0xFF00U)) + const float DEEMPHASIS_GAIN_DB = 0.0F; const float PREEMPHASIS_GAIN_DB = 0.0F; const float FILTER_GAIN_DB = 0.0F; @@ -125,7 +127,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) // Repack the data (8-bit unsigned values containing unsigned 16-bit data) for (unsigned int i = 0U; i < nSamples; i++) { unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = ((sample >> 8) & 0x00FFU) | ((sample << 8) & 0xFF00U);//change endianess to network order, transmit MSB first + out[nOut++] = SWAP_BYTES_16(sample);//change endianess to network order, transmit MSB first } #if defined(DUMP_RF_AUDIO) @@ -155,42 +157,74 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) if(space > 252U) space = 252U; - unsigned char netData[168U];//84 * 2 modem can handle up to 84 samples (252 bytes) at a time - unsigned int length = m_network->read(netData, 168U); + unsigned short netData[84U];//modem can handle up to 84 samples (252 bytes) at a time + unsigned int length = m_network->read((unsigned char*)netData, 84U * sizeof(unsigned short)); + length /= sizeof(unsigned short); if (length == 0U) return 0U; - float samples[84U]; - unsigned int nSamples = 0U; - // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) - for (unsigned int i = 0U; i < length; i += 2U) { - unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; - samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; - } - - //Pre-emphasise the data and other stuff. - for (unsigned int i = 0U; i < nSamples; i++) - samples[i] = m_preemphasis->filter(samples[i]); - - // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) unsigned int pack = 0U; unsigned char* packPointer = (unsigned char*)&pack; - unsigned int j = 0U; - unsigned int i = 0U; - for (; i < nSamples && j < space; i += 2U, j += 3U) { - unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); - unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); + unsigned int nData = 0U; - pack = 0U; - pack = ((unsigned int)sample1) << 12; - pack |= sample2; + for(unsigned int i = 0; i < length; i++) { + unsigned short netSample = SWAP_BYTES_16(netData[i]);//((netData[i] << 8) & 0xFF00U)| ((netData[i] >> 8) & 0x00FFU); + // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) + float sampleFloat = (float(netSample) / 32768.0F) - 1.0F; - data[j] = packPointer[0U]; - data[j + 1U] = packPointer[1U]; - data[j + 2U] = packPointer[2U]; + //preemphasis + sampleFloat = m_preemphasis->filter(sampleFloat); + + // Convert float to 12-bit samples (0 to 4095) + unsigned int sample12bit = (unsigned int)((sampleFloat + 1.0F) * 2048.0F + 0.5F); + + // pack 2 samples onto 3 bytes + if((i & 1U) == 0) { + pack = 0U; + pack = sample12bit << 12; + } else { + pack |= sample12bit; + + data[nData++] = packPointer[0U]; + data[nData++] = packPointer[1U]; + data[nData++] = packPointer[2U]; + } } - return j;//return the number of bytes written + return nData; + + + // float samples[84U]; + // unsigned int nSamples = 0U; + // // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) + // for (unsigned int i = 0U; i < length; i += 2U) { + // unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; + // samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; + // } + + // //Pre-emphasise the data and other stuff. + // for (unsigned int i = 0U; i < nSamples; i++) + // samples[i] = m_preemphasis->filter(samples[i]); + + // // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) + // unsigned int pack = 0U; + // unsigned char* packPointer = (unsigned char*)&pack; + // unsigned int j = 0U; + // unsigned int i = 0U; + // for (; i < nSamples && j < space; i += 2U, j += 3U) { + // unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); + // unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); + + // pack = 0U; + // pack = ((unsigned int)sample1) << 12; + // pack |= sample2; + + // data[j] = packPointer[0U]; + // data[j + 1U] = packPointer[1U]; + // data[j + 2U] = packPointer[2U]; + // } + + // return j;//return the number of bytes written } void CFMControl::clock(unsigned int ms) From bd1aa20803daebfbcfae32b45d3140ec2fe7cca8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 11:37:18 +0200 Subject: [PATCH 11/14] Simplify writeModem, only 2 loops --- FMControl.cpp | 69 +++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 74b3537..72e79a1 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -83,63 +83,46 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) bufferLength = 255U; if (bufferLength >= 3U) { -#if defined(DUMP_RF_AUDIO) - FILE * audiofile = fopen("./audiodump.bin", "ab"); -#endif - bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3 unsigned char bufferData[255U]; m_incomingRFAudio.getData(bufferData, bufferLength); - - unsigned int nSamples = 0; - float samples[85U]; // 255 / 3; - // Unpack the serial data into float values. + unsigned int pack = 0U; + unsigned char* packPointer = (unsigned char*)&pack; + unsigned short out[168U]; // 84 * 2 + unsigned int nOut = 0U; + short unpackedSamples[2U]; + for (unsigned int i = 0U; i < bufferLength; i += 3U) { - short sample1 = 0U; - short sample2 = 0U; - - unsigned int pack = 0U; - unsigned char* packPointer = (unsigned char*)&pack; - + //extract unsigned 12 bit unsigned sample pairs pack into 3 bytes to 16 bit signed packPointer[0U] = bufferData[i]; packPointer[1U] = bufferData[i + 1U]; packPointer[2U] = bufferData[i + 2U]; + unpackedSamples[1U] = short(int(pack & FM_MASK) - 2048); + unpackedSamples[0U] = short(int(pack >> 12) - 2048); - //extract unsigned 12 bit samples to 16 bit signed - sample2 = short(int(pack & FM_MASK) - 2048); - sample1 = short(int(pack >> 12) - 2048); + //process unpacked sample pair + for(unsigned char j = 0U; j < 2U; j++) { + //Convert to float (-1.0 to +1.0) + float sampleFloat = float(unpackedSamples[j]) / 2048.0F; - // Convert from unsigned short (0 - +4095) to float (-1.0 - +1.0) - samples[nSamples++] = float(sample1) / 2048.0F; - samples[nSamples++] = float(sample2) / 2048.0F; + //De-emphasise and remove CTCSS + sampleFloat = m_deemphasis->filter(sampleFloat); + sampleFloat = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(sampleFloat))); + + // Repack the float data to 16 bit unsigned + unsigned short sampleUShort = (unsigned short)((sampleFloat + 1.0F) * 32767.0F + 0.5F); + out[nOut++] = SWAP_BYTES_16(sampleUShort); + } } - //De-emphasise the data and remove CTCSS - for (unsigned int i = 0U; i < nSamples; i++) { - samples[i] = m_deemphasis->filter(samples[i]); - samples[i] = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(samples[i]))); - } - - unsigned short out[170U]; // 85 * 2 - unsigned int nOut = 0U; - - // Repack the data (8-bit unsigned values containing unsigned 16-bit data) - for (unsigned int i = 0U; i < nSamples; i++) { - unsigned short sample = (unsigned short)((samples[i] + 1.0F) * 32767.0F + 0.5F); - out[nOut++] = SWAP_BYTES_16(sample);//change endianess to network order, transmit MSB first - } - -#if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fwrite(out, sizeof(unsigned short), nOut, audiofile); -#endif - #if defined(DUMP_RF_AUDIO) - if(audiofile != NULL) - fclose(audiofile); + FILE * audiofile = fopen("./audiodump.bin", "ab"); + if(audiofile != NULL) { + fwrite(out, sizeof(unsigned short), nOut, audiofile); + fclose(audiofile); + } #endif - return m_network->writeData((unsigned char*)out, nOut * sizeof(unsigned short)); } From af6b7d79da18f8c7f4f71f32f1fbc11e86ba70d8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 11:43:35 +0200 Subject: [PATCH 12/14] Adjust emphasis gains --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index 72e79a1..3f58cb4 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -27,7 +27,7 @@ #define SWAP_BYTES_16(a) (((a >> 8) & 0x00FFU) | ((a << 8) & 0xFF00U)) const float DEEMPHASIS_GAIN_DB = 0.0F; -const float PREEMPHASIS_GAIN_DB = 0.0F; +const float PREEMPHASIS_GAIN_DB = 13.0F; const float FILTER_GAIN_DB = 0.0F; const unsigned int FM_MASK = 0x00000FFFU; From 97a35e69a4215ee2ebefe39f1428f40a7136c4e8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 12:14:16 +0200 Subject: [PATCH 13/14] clean up --- FMControl.cpp | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/FMControl.cpp b/FMControl.cpp index 3f58cb4..8adc9c4 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -175,39 +175,6 @@ unsigned int CFMControl::readModem(unsigned char* data, unsigned int space) } return nData; - - - // float samples[84U]; - // unsigned int nSamples = 0U; - // // Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0) - // for (unsigned int i = 0U; i < length; i += 2U) { - // unsigned short sample = (netData[i + 0U] << 8) | netData[i + 1U]; - // samples[nSamples++] = (float(sample) / 32768.0F) - 1.0F; - // } - - // //Pre-emphasise the data and other stuff. - // for (unsigned int i = 0U; i < nSamples; i++) - // samples[i] = m_preemphasis->filter(samples[i]); - - // // Pack the floating point data (+1.0 to -1.0) to packed 12-bit samples (+2047 - -2048) - // unsigned int pack = 0U; - // unsigned char* packPointer = (unsigned char*)&pack; - // unsigned int j = 0U; - // unsigned int i = 0U; - // for (; i < nSamples && j < space; i += 2U, j += 3U) { - // unsigned short sample1 = (unsigned short)((samples[i] + 1.0F) * 2048.0F + 0.5F); - // unsigned short sample2 = (unsigned short)((samples[i + 1] + 1.0F) * 2048.0F + 0.5F); - - // pack = 0U; - // pack = ((unsigned int)sample1) << 12; - // pack |= sample2; - - // data[j] = packPointer[0U]; - // data[j + 1U] = packPointer[1U]; - // data[j + 2U] = packPointer[2U]; - // } - - // return j;//return the number of bytes written } void CFMControl::clock(unsigned int ms) From 17b49fde883ed2ac79a5720c4e8f9f20396b8e31 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 12:19:20 +0200 Subject: [PATCH 14/14] Typo --- FMControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMControl.cpp b/FMControl.cpp index e8b4230..13c4132 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -94,7 +94,7 @@ bool CFMControl::writeModem(const unsigned char* data, unsigned int length) short unpackedSamples[2U]; for (unsigned int i = 0U; i < bufferLength; i += 3U) { - //extract unsigned 12 bit unsigned sample pairs pack into 3 bytes to 16 bit signed + //extract unsigned 12 bit unsigned sample pairs packed into 3 bytes to 16 bit signed packPointer[0U] = bufferData[i]; packPointer[1U] = bufferData[i + 1U]; packPointer[2U] = bufferData[i + 2U];