mirror of
https://github.com/g4klx/MMDVM.git
synced 2026-10-15 16:24:11 +02:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc785e3225 | ||
|
|
be0690e587 | ||
|
|
69e39e36b0 | ||
|
|
b2f33fd4d2 | ||
|
|
200199c5d4 | ||
|
|
1465d6f91d | ||
|
|
373aed13c8 | ||
|
|
b23620ede3 | ||
|
|
da87afc8d4 | ||
|
|
626a280d27 | ||
|
|
4b267c2e1e | ||
|
|
cf18f95a92 | ||
|
|
dac0f26e5d | ||
|
|
13993891ec | ||
|
|
849c2a0f50 | ||
|
|
172ac615a8 | ||
|
|
30031d8e95 | ||
|
|
b2de5defa4 | ||
|
|
177c7548ae | ||
|
|
b9bfc36e6f | ||
|
|
980c529107 | ||
|
|
5156ca13b7 | ||
|
|
d08a3690b0 | ||
|
|
e8ed77241c | ||
|
|
82dcc44a2d | ||
|
|
93a8e63233 | ||
|
|
4ffaa62855 | ||
|
|
f9530ee82a | ||
|
|
d66c6d7f9c | ||
|
|
458a3d2d24 | ||
|
|
6f4c19c006 | ||
|
|
a31cf3d6f8 | ||
|
|
3fb0631953 | ||
|
|
028d0cf609 | ||
|
|
6824d5662a | ||
|
|
1bc8726046 | ||
|
|
05c8c130b6 | ||
|
|
5051a13711 | ||
|
|
103116e410 | ||
|
|
d973238596 | ||
|
|
4d664c4aa4 |
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||
* Copyright (C) 2020 by Phil Taylor M0VSE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "Config.h"
|
||||
#include "Globals.h"
|
||||
#include "CalFM.h"
|
||||
|
||||
|
||||
const struct TONE_TABLE {
|
||||
uint16_t frequency;
|
||||
uint16_t length;
|
||||
q31_t increment;
|
||||
} TONE_TABLE_DATA[] = {
|
||||
{2495U, 10U, 223248821},
|
||||
{2079U, 12U, 186025772},
|
||||
{1633U, 15U, 146118367},
|
||||
{1247U, 19U, 111579672},
|
||||
{1039U, 23U, 93012886},
|
||||
{956U, 25U, 85541432}};
|
||||
|
||||
const uint8_t TONE_TABLE_DATA_LEN = 6U;
|
||||
|
||||
CCalFM::CCalFM() :
|
||||
m_tone(NULL),
|
||||
m_frequency(0),
|
||||
m_length(0),
|
||||
m_level(128*32),
|
||||
m_transmit(false),
|
||||
m_lastState(STATE_IDLE),
|
||||
m_audioSeq(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CCalFM::process()
|
||||
{
|
||||
const TONE_TABLE* entry = NULL;
|
||||
|
||||
if (m_modemState!=m_lastState)
|
||||
{
|
||||
switch (m_modemState) {
|
||||
case STATE_FMCAL10K:
|
||||
m_frequency=956U;
|
||||
break;
|
||||
case STATE_FMCAL12K:
|
||||
m_frequency=1039U;
|
||||
break;
|
||||
case STATE_FMCAL15K:
|
||||
m_frequency=1247U;
|
||||
break;
|
||||
case STATE_FMCAL20K:
|
||||
m_frequency=1633U;
|
||||
break;
|
||||
case STATE_FMCAL25K:
|
||||
m_frequency=2079U;
|
||||
break;
|
||||
case STATE_FMCAL30K:
|
||||
m_frequency=2495U;
|
||||
break;
|
||||
default:
|
||||
m_frequency=0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0U; i < TONE_TABLE_DATA_LEN; i++) {
|
||||
if (TONE_TABLE_DATA[i].frequency == m_frequency) {
|
||||
entry = TONE_TABLE_DATA + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry == NULL)
|
||||
return;
|
||||
|
||||
m_length = entry->length;
|
||||
|
||||
delete[] m_tone;
|
||||
m_tone = new q15_t[m_length];
|
||||
|
||||
q31_t arg = 0;
|
||||
for (uint16_t i = 0U; i < m_length; i++) {
|
||||
q63_t value = ::arm_sin_q31(arg) * q63_t(m_level);
|
||||
m_tone[i] = q15_t(__SSAT((value >> 31), 16));
|
||||
|
||||
arg += entry->increment;
|
||||
}
|
||||
|
||||
m_lastState=m_modemState;
|
||||
}
|
||||
|
||||
if (m_transmit)
|
||||
{
|
||||
uint16_t space = io.getSpace();
|
||||
while (space > m_length)
|
||||
{
|
||||
io.write(m_modemState,m_tone,m_length);
|
||||
space -= m_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t CCalFM::write(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (length != 1U)
|
||||
return 4U;
|
||||
|
||||
m_transmit = data[0U] == 1U;
|
||||
|
||||
return 0U;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||
* Copyright (C) 2020 by Phil Taylor M0VSE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(CALFM_H)
|
||||
#define CALFM_H
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
class CCalFM {
|
||||
public:
|
||||
CCalFM();
|
||||
|
||||
void process();
|
||||
void fm10kcal();
|
||||
void fm12k5cal();
|
||||
void fm15kcal();
|
||||
void fm20kcal();
|
||||
void fm25kcal();
|
||||
void fm30kcal();
|
||||
|
||||
uint8_t write(const uint8_t* data, uint8_t length);
|
||||
|
||||
private:
|
||||
uint16_t m_frequency;
|
||||
uint16_t m_length;
|
||||
q15_t* m_tone;
|
||||
q15_t m_level;
|
||||
bool m_transmit;
|
||||
uint8_t m_audioSeq;
|
||||
uint8_t m_lastState;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,12 +36,15 @@ m_kerchunkTimer(),
|
||||
m_ackMinTimer(),
|
||||
m_ackDelayTimer(),
|
||||
m_hangTimer(),
|
||||
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),
|
||||
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz
|
||||
m_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
|
||||
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
|
||||
m_preemphasis(32768, 13967, 0, 32768, -18801, 0),//75µS 24kHz sampling rate
|
||||
m_deemphasis (32768, -18801, 0, 32768, 13967, 0),//75µS 24kHz sampling rate
|
||||
m_blanking(),
|
||||
m_useCOS(true),
|
||||
m_rxBoost(1U)
|
||||
m_rfAudioBoost(1U),
|
||||
m_downsampler(1024)//Size might need adjustement
|
||||
{
|
||||
}
|
||||
|
||||
@@ -74,17 +77,19 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
||||
} else if (CTCSS_NOT_READY(ctcssState) && m_modemState == STATE_FM && i == length - 1) {
|
||||
//Not enough samples for CTCSS but we already are in FM, trigger the state machine
|
||||
//but do not trigger the state machine on every single sample, save CPU!
|
||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||
stateMachine(validCTCSS && cos, i + 1U);
|
||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||
stateMachine(validCTCSS && cos, i + 1U);
|
||||
}
|
||||
|
||||
// Only let audio through when relaying audio
|
||||
if (m_state == FS_RELAYING || m_state == FS_KERCHUNK)
|
||||
currentSample = m_blanking.process(currentSample);
|
||||
else
|
||||
currentSample = 0U;
|
||||
|
||||
currentSample *= m_rxBoost;
|
||||
// Only let audio through when relaying audio
|
||||
if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) {
|
||||
currentSample = m_deemphasis.filter(currentSample);
|
||||
m_downsampler.addSample(currentSample);
|
||||
currentSample = m_blanking.process(currentSample);
|
||||
currentSample *= m_rfAudioBoost;
|
||||
} else {
|
||||
currentSample = 0;
|
||||
}
|
||||
|
||||
if (!m_callsign.isRunning())
|
||||
currentSample += m_rfAck.getHighAudio();
|
||||
@@ -99,7 +104,9 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
||||
if (!m_callsign.isRunning() && !m_rfAck.isRunning())
|
||||
currentSample += m_timeoutTone.getAudio();
|
||||
|
||||
currentSample = q15_t(m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample))));
|
||||
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
||||
|
||||
currentSample = m_preemphasis.filter(currentSample);
|
||||
|
||||
currentSample += m_ctcssTX.getAudio();
|
||||
|
||||
@@ -144,10 +151,10 @@ uint8_t CFM::setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_
|
||||
return m_rfAck.setParams(rfAck, speed, frequency, level, level);
|
||||
}
|
||||
|
||||
uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rxBoost, uint8_t maxDev)
|
||||
uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
|
||||
{
|
||||
m_useCOS = useCOS;
|
||||
m_rxBoost = q15_t(rxBoost);
|
||||
m_useCOS = useCOS;
|
||||
m_rfAudioBoost = q15_t(rfAudioBoost);
|
||||
|
||||
m_timeoutTimer.setTimeout(timeout, 0U);
|
||||
m_kerchunkTimer.setTimeout(kerchunkTime, 0U);
|
||||
@@ -156,7 +163,7 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque
|
||||
m_timeoutTone.setParams(timeoutLevel);
|
||||
m_blanking.setParams(maxDev, timeoutLevel);
|
||||
|
||||
uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssThreshold);
|
||||
uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssThreshold, rxLevel);
|
||||
if (ret != 0U)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "FMKeyer.h"
|
||||
#include "FMTimer.h"
|
||||
#include "FMDirectForm1.h"
|
||||
#include "FMDownsampler.h"
|
||||
|
||||
enum FM_STATE {
|
||||
FS_LISTENING,
|
||||
@@ -54,7 +55,7 @@ public:
|
||||
|
||||
uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd);
|
||||
uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level);
|
||||
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rxBoost, uint8_t maxDev);
|
||||
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
|
||||
|
||||
private:
|
||||
CFMKeyer m_callsign;
|
||||
@@ -75,9 +76,12 @@ private:
|
||||
CFMDirectFormI m_filterStage1;
|
||||
CFMDirectFormI m_filterStage2;
|
||||
CFMDirectFormI m_filterStage3;
|
||||
CFMDirectFormI m_preemphasis;
|
||||
CFMDirectFormI m_deemphasis;
|
||||
CFMBlanking m_blanking;
|
||||
bool m_useCOS;
|
||||
q15_t m_rxBoost;
|
||||
q15_t m_rfAudioBoost;
|
||||
CFMDownsampler m_downsampler;
|
||||
|
||||
void stateMachine(bool validSignal, uint8_t length);
|
||||
void listeningState(bool validSignal);
|
||||
|
||||
+13
-4
@@ -86,12 +86,15 @@ m_threshold(0),
|
||||
m_count(0U),
|
||||
m_q0(0),
|
||||
m_q1(0),
|
||||
m_result(CTS_NONE)
|
||||
m_result(CTS_NONE),
|
||||
m_rxLevelInverse(1)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t threshold)
|
||||
uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t threshold, uint8_t level)
|
||||
{
|
||||
m_rxLevelInverse = 511 / q15_t(level);
|
||||
|
||||
m_coeffDivTwo = 0;
|
||||
|
||||
for (uint8_t i = 0U; i < CTCSS_TABLE_DATA_LEN; i++) {
|
||||
@@ -111,7 +114,9 @@ uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t threshold)
|
||||
|
||||
CTCSSState CFMCTCSSRX::process(q15_t sample)
|
||||
{
|
||||
m_result = m_result & (~CTS_READY);
|
||||
q31_t sample31 = q31_t(sample) * m_rxLevelInverse;
|
||||
|
||||
m_result = m_result & (~CTS_READY);
|
||||
|
||||
q31_t q2 = m_q1;
|
||||
m_q1 = m_q0;
|
||||
@@ -122,7 +127,7 @@ CTCSSState CFMCTCSSRX::process(q15_t sample)
|
||||
q31_t t3 = t2 * 2;
|
||||
|
||||
// m_q0 = m_coeffDivTwo * m_q1 * 2 - q2 + sample
|
||||
m_q0 = t3 - q2 + q31_t(sample);
|
||||
m_q0 = t3 - q2 + sample31;
|
||||
|
||||
m_count++;
|
||||
if (m_count == N) {
|
||||
@@ -144,12 +149,16 @@ CTCSSState CFMCTCSSRX::process(q15_t sample)
|
||||
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||
q31_t value = t2 + t4 - t9;
|
||||
|
||||
bool previousCTCSSValid = CTCSS_VALID(m_result);
|
||||
m_result = m_result | CTS_READY;
|
||||
if (value >= m_threshold)
|
||||
m_result = m_result | CTS_VALID;
|
||||
else
|
||||
m_result = m_result & ~CTS_VALID;
|
||||
|
||||
if(previousCTCSSValid != CTCSS_VALID(m_result))
|
||||
DEBUG4("CTCSS Value / Threshold / Valid", value, m_threshold, CTCSS_VALID(m_result));
|
||||
|
||||
m_count = 0U;
|
||||
m_q0 = 0;
|
||||
m_q1 = 0;
|
||||
|
||||
+9
-8
@@ -53,21 +53,22 @@ class CFMCTCSSRX {
|
||||
public:
|
||||
CFMCTCSSRX();
|
||||
|
||||
uint8_t setParams(uint8_t frequency, uint8_t threshold);
|
||||
uint8_t setParams(uint8_t frequency, uint8_t threshold, uint8_t level);
|
||||
|
||||
CTCSSState process(q15_t samples);
|
||||
CTCSSState process(q15_t sample);
|
||||
|
||||
CTCSSState getState();
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
q63_t m_coeffDivTwo;
|
||||
q31_t m_threshold;
|
||||
uint16_t m_count;
|
||||
q31_t m_q0;
|
||||
q31_t m_q1;
|
||||
CTCSSState m_result;
|
||||
q63_t m_coeffDivTwo;
|
||||
q31_t m_threshold;
|
||||
uint16_t m_count;
|
||||
q31_t m_q0;
|
||||
q31_t m_q1;
|
||||
CTCSSState m_result;
|
||||
q15_t m_rxLevelInverse;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+54
-55
@@ -23,59 +23,58 @@
|
||||
const struct TX_CTCSS_TABLE {
|
||||
uint8_t frequency;
|
||||
uint16_t length;
|
||||
q15_t increment;
|
||||
q31_t increment;
|
||||
} TX_CTCSS_TABLE_DATA[] = {
|
||||
{ 67U, 358U, 92},
|
||||
{ 69U, 346U, 95},
|
||||
{ 71U, 334U, 99},
|
||||
{ 74U, 323U, 102},
|
||||
{ 77U, 312U, 106},
|
||||
{ 79U, 301U, 109},
|
||||
{ 82U, 291U, 113},
|
||||
{ 85U, 281U, 117},
|
||||
{ 88U, 271U, 121},
|
||||
{ 91U, 262U, 125},
|
||||
{ 94U, 253U, 130},
|
||||
{ 97U, 246U, 133},
|
||||
{100U, 240U, 137},
|
||||
{103U, 232U, 142},
|
||||
{107U, 224U, 147},
|
||||
{110U, 216U, 152},
|
||||
{114U, 209U, 157},
|
||||
{118U, 202U, 163},
|
||||
{123U, 195U, 168},
|
||||
{127U, 189U, 174},
|
||||
{131U, 182U, 180},
|
||||
{136U, 176U, 187},
|
||||
{141U, 170U, 193},
|
||||
{146U, 164U, 200},
|
||||
{151U, 159U, 207},
|
||||
{156U, 153U, 214},
|
||||
{159U, 150U, 219},
|
||||
{162U, 148U, 222},
|
||||
{165U, 145U, 226},
|
||||
{167U, 143U, 230},
|
||||
{171U, 140U, 234},
|
||||
{173U, 138U, 238},
|
||||
{177U, 135U, 243},
|
||||
{179U, 133U, 246},
|
||||
{183U, 131U, 251},
|
||||
{186U, 129U, 255},
|
||||
{189U, 126U, 260},
|
||||
{192U, 124U, 264},
|
||||
{196U, 122U, 269},
|
||||
{199U, 120U, 273},
|
||||
{203U, 118U, 278},
|
||||
{206U, 116U, 282},
|
||||
{210U, 114U, 288},
|
||||
{218U, 110U, 298},
|
||||
{225U, 106U, 309},
|
||||
{229U, 105U, 313},
|
||||
{233U, 103U, 319},
|
||||
{241U, 99U, 331},
|
||||
{250U, 96U, 342},
|
||||
{254U, 94U, 347}
|
||||
};
|
||||
{ 67U, 358U, 5995059},
|
||||
{ 69U, 346U, 6200860},
|
||||
{ 71U, 334U, 6433504},
|
||||
{ 74U, 323U, 6657200},
|
||||
{ 77U, 312U, 6889844},
|
||||
{ 79U, 301U, 7131436},
|
||||
{ 82U, 291U, 7381976},
|
||||
{ 85U, 281U, 7641463},
|
||||
{ 88U, 271U, 7918846},
|
||||
{ 91U, 262U, 8187282},
|
||||
{ 94U, 253U, 8482561},
|
||||
{ 97U, 246U, 8715205},
|
||||
{100U, 240U, 8947849},
|
||||
{103U, 232U, 9261024},
|
||||
{107U, 224U, 9592094},
|
||||
{110U, 216U, 9923165},
|
||||
{114U, 209U, 10272131},
|
||||
{118U, 202U, 10630045},
|
||||
{123U, 195U, 11005854},
|
||||
{127U, 189U, 11390612},
|
||||
{131U, 182U, 11793265},
|
||||
{136U, 176U, 12213814},
|
||||
{141U, 170U, 12643310},
|
||||
{146U, 164U, 13081755},
|
||||
{151U, 159U, 13547043},
|
||||
{156U, 153U, 14021279},
|
||||
{159U, 150U, 14298662},
|
||||
{162U, 148U, 14513411},
|
||||
{165U, 145U, 14808690},
|
||||
{167U, 143U, 15023438},
|
||||
{171U, 140U, 15327665},
|
||||
{173U, 138U, 15551361},
|
||||
{177U, 135U, 15864536},
|
||||
{179U, 133U, 16097180},
|
||||
{183U, 131U, 16419303},
|
||||
{186U, 129U, 16660894},
|
||||
{189U, 126U, 16991965},
|
||||
{192U, 124U, 17251452},
|
||||
{196U, 122U, 17591471},
|
||||
{199U, 120U, 17850958},
|
||||
{203U, 118U, 18208872},
|
||||
{206U, 116U, 18477308},
|
||||
{210U, 114U, 18853117},
|
||||
{218U, 110U, 19515258},
|
||||
{225U, 106U, 20195295},
|
||||
{229U, 105U, 20499521},
|
||||
{233U, 103U, 20902175},
|
||||
{241U, 99U, 21635898},
|
||||
{250U, 96U, 22396465},
|
||||
{254U, 94U, 22736484}};
|
||||
|
||||
const uint8_t CTCSS_TABLE_DATA_LEN = 50U;
|
||||
|
||||
@@ -105,10 +104,10 @@ uint8_t CFMCTCSSTX::setParams(uint8_t frequency, uint8_t level)
|
||||
delete[] m_values;
|
||||
m_values = new q15_t[m_length];
|
||||
|
||||
q15_t arg = 0;
|
||||
q31_t arg = 0;
|
||||
for (uint16_t i = 0U; i < m_length; i++) {
|
||||
q31_t value = ::arm_sin_q15(arg) * q15_t(level * 13);
|
||||
m_values[i] = q15_t(__SSAT((value >> 15), 16));
|
||||
q63_t value = ::arm_sin_q31(arg) * q63_t(level * 13);
|
||||
m_values[i] = q15_t(__SSAT((value >> 31), 16));
|
||||
|
||||
arg += entry->increment;
|
||||
}
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ public:
|
||||
inline q15_t filter(const q15_t in)
|
||||
{
|
||||
// calculate the output
|
||||
register q31_t out_upscaled = c_b0 * in //F4FXL puting stauration here made everything quiet, not sure why
|
||||
register q31_t out_upscaled = c_b0 * in
|
||||
+ c_b1 * m_x1
|
||||
+ c_b2 * m_x2
|
||||
- c_a1 * m_y1
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "FMDownsampleRB.h"
|
||||
|
||||
CFMDownsampleRB::CFMDownsampleRB(uint16_t length) :
|
||||
m_length(length),
|
||||
m_head(0U),
|
||||
m_tail(0U),
|
||||
m_full(false),
|
||||
m_overflow(false)
|
||||
{
|
||||
m_samples = new uint8_t[length];
|
||||
}
|
||||
|
||||
uint16_t CFMDownsampleRB::getSpace() const
|
||||
{
|
||||
uint16_t n = 0U;
|
||||
|
||||
if (m_tail == m_head)
|
||||
n = m_full ? 0U : m_length;
|
||||
else if (m_tail < m_head)
|
||||
n = m_length - m_head + m_tail;
|
||||
else
|
||||
n = m_tail - m_head;
|
||||
|
||||
if (n > m_length)
|
||||
n = 0U;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
uint16_t CFMDownsampleRB::getData() const
|
||||
{
|
||||
if (m_tail == m_head)
|
||||
return m_full ? m_length : 0U;
|
||||
else if (m_tail < m_head)
|
||||
return m_head - m_tail;
|
||||
else
|
||||
return m_length - m_tail + m_head;
|
||||
}
|
||||
|
||||
bool CFMDownsampleRB::put(uint8_t sample)
|
||||
{
|
||||
if (m_full) {
|
||||
m_overflow = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_samples[m_head] = sample;
|
||||
|
||||
m_head++;
|
||||
if (m_head >= m_length)
|
||||
m_head = 0U;
|
||||
|
||||
if (m_head == m_tail)
|
||||
m_full = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFMDownsampleRB::get(uint8_t& sample)
|
||||
{
|
||||
if (m_head == m_tail && !m_full)
|
||||
return false;
|
||||
|
||||
sample = m_samples[m_tail];
|
||||
|
||||
m_full = false;
|
||||
|
||||
m_tail++;
|
||||
if (m_tail >= m_length)
|
||||
m_tail = 0U;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFMDownsampleRB::hasOverflowed()
|
||||
{
|
||||
bool overflow = m_overflow;
|
||||
|
||||
m_overflow = false;
|
||||
|
||||
return overflow;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(FMRB_H)
|
||||
#define FMRB_H
|
||||
|
||||
#if defined(STM32F4XX)
|
||||
#include "stm32f4xx.h"
|
||||
#elif defined(STM32F7XX)
|
||||
#include "stm32f7xx.h"
|
||||
#elif defined(STM32F105xC)
|
||||
#include "stm32f1xx.h"
|
||||
#include <cstddef>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__) || defined(STM32F105xC)
|
||||
#define ARM_MATH_CM3
|
||||
#elif defined(STM32F7XX)
|
||||
#define ARM_MATH_CM7
|
||||
#elif defined(STM32F4XX) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#define ARM_MATH_CM4
|
||||
#else
|
||||
#error "Unknown processor type"
|
||||
#endif
|
||||
|
||||
#include <arm_math.h>
|
||||
|
||||
class CFMDownsampleRB {
|
||||
public:
|
||||
CFMDownsampleRB(uint16_t length);
|
||||
|
||||
uint16_t getSpace() const;
|
||||
|
||||
uint16_t getData() const;
|
||||
|
||||
bool put(uint8_t sample);
|
||||
|
||||
bool get(uint8_t& sample);
|
||||
|
||||
bool hasOverflowed();
|
||||
|
||||
private:
|
||||
uint16_t m_length;
|
||||
volatile uint8_t* m_samples;
|
||||
volatile uint16_t m_head;
|
||||
volatile uint16_t m_tail;
|
||||
volatile bool m_full;
|
||||
bool m_overflow;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "Config.h"
|
||||
#include "FMDownsampler.h"
|
||||
|
||||
|
||||
CFMDownsampler::CFMDownsampler(uint16_t length) :
|
||||
m_ringBuffer(length),//length might need tweaking
|
||||
m_packIndex(0),
|
||||
m_downSampleIndex(0)
|
||||
{
|
||||
m_samplePack = 0;
|
||||
}
|
||||
|
||||
void CFMDownsampler::addSample(q15_t sample)
|
||||
{
|
||||
//only take one of three samples
|
||||
if(m_downSampleIndex == 0) {
|
||||
switch(m_packIndex){
|
||||
case 0:
|
||||
m_samplePack = int32_t(sample) << 12;
|
||||
break;
|
||||
case 1:{
|
||||
m_samplePack |= int32_t(sample);
|
||||
|
||||
//we did not use MSB; skip it
|
||||
m_ringBuffer.put(m_samplePackBytes[1]);
|
||||
m_ringBuffer.put(m_samplePackBytes[2]);
|
||||
m_ringBuffer.put(m_samplePackBytes[3]);
|
||||
|
||||
m_samplePack = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//should never happen
|
||||
break;
|
||||
}
|
||||
m_packIndex++;
|
||||
if(m_packIndex >= 2)
|
||||
m_packIndex = 0;
|
||||
}
|
||||
|
||||
m_downSampleIndex++;
|
||||
if(m_downSampleIndex >= 3)
|
||||
m_downSampleIndex = 0;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(FMDOWNSAMPLER_H)
|
||||
#define FMDOWNSAMPLER_H
|
||||
|
||||
#include "Config.h"
|
||||
#include "FMDownsampleRB.h"
|
||||
|
||||
class CFMDownsampler {
|
||||
public:
|
||||
CFMDownsampler(uint16_t length);
|
||||
void addSample(q15_t sample);
|
||||
inline bool getPackedData(uint8_t& data){ return m_ringBuffer.get(data); };
|
||||
inline bool hasOverflowed() { return m_ringBuffer.hasOverflowed(); };
|
||||
|
||||
private:
|
||||
CFMDownsampleRB m_ringBuffer;
|
||||
union {
|
||||
int32_t m_samplePack;
|
||||
int8_t m_samplePackBytes[4];
|
||||
};
|
||||
uint8_t m_packIndex;
|
||||
uint8_t m_downSampleIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -63,7 +63,13 @@ enum MMDVM_STATE {
|
||||
STATE_DMRCAL = 98,
|
||||
STATE_DSTARCAL = 99,
|
||||
STATE_INTCAL = 100,
|
||||
STATE_POCSAGCAL = 101
|
||||
STATE_POCSAGCAL = 101,
|
||||
STATE_FMCAL10K = 102,
|
||||
STATE_FMCAL12K = 103,
|
||||
STATE_FMCAL15K = 104,
|
||||
STATE_FMCAL20K = 105,
|
||||
STATE_FMCAL25K = 106,
|
||||
STATE_FMCAL30K = 107
|
||||
};
|
||||
|
||||
#include "SerialPort.h"
|
||||
@@ -83,6 +89,7 @@ enum MMDVM_STATE {
|
||||
#include "POCSAGTX.h"
|
||||
#include "CalDStarRX.h"
|
||||
#include "CalDStarTX.h"
|
||||
#include "CalFM.h"
|
||||
#include "CalDMR.h"
|
||||
#include "CalP25.h"
|
||||
#include "CalNXDN.h"
|
||||
@@ -152,6 +159,7 @@ extern CFM fm;
|
||||
extern CCalDStarRX calDStarRX;
|
||||
extern CCalDStarTX calDStarTX;
|
||||
extern CCalDMR calDMR;
|
||||
extern CCalFM calFM;
|
||||
extern CCalP25 calP25;
|
||||
extern CCalNXDN calNXDN;
|
||||
extern CCalPOCSAG calPOCSAG;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -67,6 +67,7 @@ CCalDStarTX calDStarTX;
|
||||
CCalDMR calDMR;
|
||||
CCalP25 calP25;
|
||||
CCalNXDN calNXDN;
|
||||
CCalFM calFM;
|
||||
CCalPOCSAG calPOCSAG;
|
||||
CCalRSSI calRSSI;
|
||||
|
||||
@@ -127,6 +128,9 @@ void loop()
|
||||
if (m_modemState == STATE_POCSAGCAL)
|
||||
calPOCSAG.process();
|
||||
|
||||
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K ||m_modemState == STATE_FMCAL30K)
|
||||
calFM.process();
|
||||
|
||||
if (m_modemState == STATE_IDLE)
|
||||
cwIdTX.process();
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ CFM fm;
|
||||
CCalDStarRX calDStarRX;
|
||||
CCalDStarTX calDStarTX;
|
||||
CCalDMR calDMR;
|
||||
CCalFM calFM;
|
||||
CCalP25 calP25;
|
||||
CCalNXDN calNXDN;
|
||||
CCalPOCSAG calPOCSAG;
|
||||
@@ -115,6 +116,9 @@ void loop()
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||
calDMR.process();
|
||||
|
||||
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
|
||||
calFM.process();
|
||||
|
||||
if (m_modemState == STATE_P25CAL1K)
|
||||
calP25.process();
|
||||
|
||||
|
||||
@@ -273,6 +273,7 @@
|
||||
<File name="CalDStarTX.cpp" path="CalDStarTX.cpp" type="1"/>
|
||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source" path="" type="2"/>
|
||||
<File name="CalDMR.h" path="CalDMR.h" type="1"/>
|
||||
<File name="CalFM.h" path="CalFM.h" type="1"/>
|
||||
<File name="DMRDMOTX.h" path="DMRDMOTX.h" type="1"/>
|
||||
<File name="IODue.cpp" path="IODue.cpp" type="1"/>
|
||||
<File name="DMRTX.cpp" path="DMRTX.cpp" type="1"/>
|
||||
@@ -290,6 +291,7 @@
|
||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver" path="" type="2"/>
|
||||
<File name="DMRDefines.h" path="DMRDefines.h" type="1"/>
|
||||
<File name="CalDMR.cpp" path="CalDMR.cpp" type="1"/>
|
||||
<File name="CalFM.cpp" path="CalFM.cpp" type="1"/>
|
||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_adc.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_adc.h" type="1"/>
|
||||
<File name="SerialSTM.cpp" path="SerialSTM.cpp" type="1"/>
|
||||
<File name="STM32F4XX_Lib/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a" path="STM32F4XX_Lib/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a" type="1"/>
|
||||
@@ -335,4 +337,4 @@
|
||||
<File name="YSFTX.cpp" path="YSFTX.cpp" type="1"/>
|
||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_gpio.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_gpio.c" type="1"/>
|
||||
</Files>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
+26
-8
@@ -101,7 +101,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U;
|
||||
#define HW_TYPE "MMDVM"
|
||||
#endif
|
||||
|
||||
#define DESCRIPTION "20200425 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)"
|
||||
#define DESCRIPTION "20200429 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)"
|
||||
|
||||
#if defined(GITVERSION)
|
||||
#define concat(h, a, b, c) h " " a " " b " GitID #" c ""
|
||||
@@ -287,7 +287,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
|
||||
MMDVM_STATE modemState = MMDVM_STATE(data[3U]);
|
||||
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL)
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL && modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
return 4U;
|
||||
if (modemState == STATE_DSTAR && !dstarEnable)
|
||||
return 4U;
|
||||
@@ -408,7 +408,7 @@ uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint8_t length)
|
||||
|
||||
uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (length < 10U)
|
||||
if (length < 11U)
|
||||
return 4U;
|
||||
|
||||
uint16_t timeout = data[0U] * 5U;
|
||||
@@ -423,10 +423,11 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length)
|
||||
|
||||
bool useCOS = (data[7U] & 0x01U) == 0x01U;
|
||||
|
||||
uint8_t rxBoost = data[8U];
|
||||
uint8_t rfAudioBoost = data[8U];
|
||||
uint8_t maxDev = data[9U];
|
||||
uint8_t rxLevel = data[10U];
|
||||
|
||||
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, rxBoost, maxDev);
|
||||
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, rfAudioBoost, maxDev, rxLevel);
|
||||
}
|
||||
|
||||
uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
||||
@@ -439,7 +440,7 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
||||
if (modemState == m_modemState)
|
||||
return 0U;
|
||||
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL)
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL && modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
return 4U;
|
||||
if (modemState == STATE_DSTAR && !m_dstarEnable)
|
||||
return 4U;
|
||||
@@ -497,8 +498,23 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
||||
case STATE_LFCAL:
|
||||
DEBUG1("Mode set to 80 Hz Calibrate");
|
||||
break;
|
||||
case STATE_DMRCAL1K:
|
||||
DEBUG1("Mode set to DMR BS 1031 Hz Calibrate");
|
||||
case STATE_FMCAL10K:
|
||||
DEBUG1("Mode set to FM 10Khz Calibrate");
|
||||
break;
|
||||
case STATE_FMCAL12K:
|
||||
DEBUG1("Mode set to FM 12.5Khz Calibrate");
|
||||
break;
|
||||
case STATE_FMCAL15K:
|
||||
DEBUG1("Mode set to FM 15Khz Calibrate");
|
||||
break;
|
||||
case STATE_FMCAL20K:
|
||||
DEBUG1("Mode set to FM 20Khz Calibrate");
|
||||
break;
|
||||
case STATE_FMCAL25K:
|
||||
DEBUG1("Mode set to FM 10Khz Calibrate");
|
||||
break;
|
||||
case STATE_FMCAL30K:
|
||||
DEBUG1("Mode set to FM 30Khz Calibrate");
|
||||
break;
|
||||
case STATE_P25CAL1K:
|
||||
DEBUG1("Mode set to P25 1011 Hz Calibrate");
|
||||
@@ -647,6 +663,8 @@ void CSerialPort::process()
|
||||
err = calDStarTX.write(m_buffer + 3U, m_len - 3U);
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||
err = calDMR.write(m_buffer + 3U, m_len - 3U);
|
||||
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
|
||||
err = calFM.write(m_buffer + 3U, m_len - 3U);
|
||||
if (m_modemState == STATE_P25CAL1K)
|
||||
err = calP25.write(m_buffer + 3U, m_len - 3U);
|
||||
if (m_modemState == STATE_NXDNCAL1K)
|
||||
|
||||
@@ -17,21 +17,22 @@ f2 = 2700
|
||||
rp = 0.2
|
||||
|
||||
# scaling factor in bits, do not change !
|
||||
q = 15
|
||||
q = 0
|
||||
# scaling factor as facor...
|
||||
scaling_factor = 2**q
|
||||
|
||||
# let's generate a sequence of 2nd order IIR filters
|
||||
#sos = signal.butter(2,[f1/fs*2,f2/fs*2],'pass',output='sos')
|
||||
sos = signal.cheby1(3,rp,[f1/fs*2,f2/fs*2],'bandpass', output='sos')
|
||||
sos = signal.cheby1(3,rp,[f1, f2],'bandpass', output='sos', fs=fs)
|
||||
#sos = signal.cheby1(1, rp, 2122, 'lowpass', output='sos', fs=fs) #deemphasis filter
|
||||
#sos = signal.cheby1(1, rp, 2122, 'highpass', output='sos', fs=fs) #deemphasis filter
|
||||
|
||||
sos = np.round((sos) * scaling_factor)
|
||||
#sos = np.round((sos) * scaling_factor)
|
||||
|
||||
# print coefficients
|
||||
for biquad in sos:
|
||||
for coeff in biquad:
|
||||
print(int(coeff),",",sep="",end="")
|
||||
#print((coeff),",",sep="",end="")
|
||||
#print(int(coeff),",",sep="",end="")
|
||||
print((coeff),",",sep="",end="")
|
||||
print("")
|
||||
|
||||
# plot the frequency response
|
||||
@@ -0,0 +1,58 @@
|
||||
% GNU Octave script to generate pre and deemphasis filters
|
||||
% https://dsp.stackexchange.com/questions/34605/biquad-cookbook-formula-for-broadcast-fm-de-emphasis
|
||||
% PACKAGES
|
||||
|
||||
pkg load control
|
||||
pkg load signal
|
||||
|
||||
clear all;
|
||||
clc;
|
||||
|
||||
fs = 24000;
|
||||
samplingtime = 1/fs;
|
||||
|
||||
% analog prototype
|
||||
A2 = [1];
|
||||
B2 = [0.000075 1];
|
||||
|
||||
% Pre
|
||||
Ds = tf(B2, A2);
|
||||
% De
|
||||
% Ds = tf(A2, B2);
|
||||
|
||||
Ds = Ds/dcgain(Ds);
|
||||
|
||||
% MZT
|
||||
T1 = 0.000075; % 75us
|
||||
z1 = -exp(-1.0/(fs*T1));
|
||||
p1 = 1+z1;
|
||||
|
||||
a0 = 1.0;
|
||||
a1 = p1;
|
||||
a2 = 0;
|
||||
|
||||
b0 = 1.0;
|
||||
b1 = z1;
|
||||
b2 = 0;
|
||||
|
||||
% swap between a1, b1 to select pre- or de-emphasis
|
||||
|
||||
# Pre
|
||||
Bmzt = [b0 a1 b2]
|
||||
Amzt = [a0 b1 a2]
|
||||
% De
|
||||
% Bmzt = [b0 b1 b2]
|
||||
% Amzt = [a0 a1 a2]
|
||||
|
||||
DzMZT = tf(Amzt, Bmzt, samplingtime);
|
||||
DzMZT = DzMZT/dcgain(DzMZT);
|
||||
|
||||
%% Plot
|
||||
wmin = 2 * pi * 20.0; % 20Hz
|
||||
wmax = 2 * pi * ((fs/2.0) - (fs/2 - 20000)); %20kHz
|
||||
|
||||
figure(1);
|
||||
bode(Ds, 'b', DzMZT, 'c', {wmin, wmax});
|
||||
legend('Analog prototype', 'MZT 2nd order','location', 'northwest');
|
||||
grid on;
|
||||
pause();
|
||||
Reference in New Issue
Block a user