Skip to content

Commit ffa8e8a

Browse files
authored
Merge pull request #35 from Digitelektro/develop
Develop
2 parents 51ba2b7 + 8754cdf commit ffa8e8a

28 files changed

Lines changed: 776 additions & 400 deletions

CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ include(ExternalProject)
44

55
project(Meteordemod LANGUAGES CXX)
66

7-
set(CMAKE_CXX_STANDARD 14)
7+
set(CMAKE_CXX_STANDARD 17)
88
set(CMAKE_CXX_STANDARD_REQUIRED ON)
99
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
1010

@@ -93,6 +93,12 @@ add_executable(meteordemod
9393
DSP/meteordemodulator.cpp
9494
DSP/agc.cpp
9595
DSP/pll.cpp
96+
DSP/meteorcostas.cpp
97+
DSP/phasecontrolloop.cpp
98+
DSP/polyphasebank.cpp
99+
DSP/mm.cpp
100+
DSP/window.cpp
101+
DSP/windowedsinc.cpp
96102
DSP/filter.cpp
97103
DSP/iqsource.cpp
98104
DSP/wavreader.cpp

DSP/agc.cpp

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,16 @@
22

33
namespace DSP {
44

5-
Agc::Agc()
6-
: mWindowSize(AGC_WINSIZE)
7-
, mAvg(AGC_TARGET)
5+
Agc::Agc(float targetAmplitude, float maxGain, float windowSize, float biasWindowSize)
6+
: mWindowSize(windowSize)
7+
, mAvg(targetAmplitude)
88
, mGain(1)
9-
, mTargetAmplitude(AGC_TARGET)
9+
, mMaxGain(maxGain)
10+
, mTargetAmplitude(targetAmplitude)
11+
, mBiasWindowSize(biasWindowSize)
1012
, mBias(0)
1113
{
1214

1315
}
1416

15-
Agc::complex Agc::process(complex sample)
16-
{
17-
float rho;
18-
19-
mBias = (mBias * static_cast<float>(AGC_BIAS_WINSIZE - 1) + sample) / static_cast<float>(AGC_BIAS_WINSIZE);
20-
sample -= mBias;
21-
22-
// Update the sample magnitude average
23-
rho = sqrtf(std::real(sample) * std::real(sample) + std::imag(sample) * std::imag(sample));
24-
mAvg = (mAvg * (mWindowSize - 1) + rho) / mWindowSize;
25-
26-
mGain = mTargetAmplitude / mAvg;
27-
if (mGain > AGC_MAX_GAIN) {
28-
mGain = AGC_MAX_GAIN;
29-
}
30-
return sample * mGain;
31-
}
32-
3317
} //namespace DSP

DSP/agc.h

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,31 @@ class Agc
1111
typedef std::complex<float> complex;
1212

1313
public:
14-
Agc();
14+
Agc(float targetAmplitude, float maxGain = 20, float windowSize = 1024*64, float biasWindowSize = 256*1024);
1515

16-
complex process(complex sample);
16+
inline complex process(complex sample){
17+
float rho;
18+
19+
mBias = (mBias * static_cast<float>(mBiasWindowSize - 1) + sample) / static_cast<float>(mBiasWindowSize);
20+
sample -= mBias;
21+
22+
// Update the sample magnitude average
23+
rho = std::abs(sample);
24+
mAvg = (mAvg * (mWindowSize - 1) + rho) / mWindowSize;
25+
26+
mGain = mTargetAmplitude / mAvg;
27+
if (mGain > mMaxGain) {
28+
mGain = mMaxGain;
29+
}
30+
return sample * mGain;
31+
}
32+
33+
inline void process(const complex *inSamples, complex *outsamples, unsigned int count) {
34+
for(unsigned int i = 0; i < count; i++) {
35+
*outsamples = process(*inSamples++);
36+
outsamples++;
37+
}
38+
}
1739

1840
public:
1941
float getGain() const {
@@ -24,14 +46,10 @@ class Agc
2446
uint32_t mWindowSize;
2547
float mAvg;
2648
float mGain;
49+
float mMaxGain;
2750
float mTargetAmplitude;
51+
float mBiasWindowSize;
2852
complex mBias;
29-
30-
private:
31-
static constexpr uint32_t AGC_WINSIZE = 1024*64;
32-
static constexpr uint32_t AGC_TARGET = 180;
33-
static constexpr uint32_t AGC_MAX_GAIN = 20;
34-
static constexpr uint32_t AGC_BIAS_WINSIZE = 256*1024;
3553
};
3654

3755
} //namespace DSP

DSP/filter.cpp

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,31 @@ FilterBase::FilterBase(int taps)
99

1010
}
1111

12-
FilterBase::complex FilterBase::process(const FilterBase::complex &in)
12+
RRCFilter::RRCFilter(int taps, float beta, float symbolrate, float samplerate)
13+
: FilterBase(taps)
1314
{
14-
complex out = 0.0f;
15-
16-
mMemory.push_front(in);
17-
mMemory.pop_back();
18-
19-
std::list<complex>::const_reverse_iterator it = mMemory.crbegin();
20-
21-
for(int i = mTaps - 1; i >=0; --i, ++it) {
22-
out += (*it) * mCoeffs[i];
23-
}
24-
return out;
25-
}
26-
27-
RRCFilter::RRCFilter(unsigned order, unsigned factor, float osf, float alpha)
28-
:FilterBase(order * 2 + 1)
29-
{
30-
for (uint16_t i=0; i < mTaps; i++) {
31-
mCoeffs.emplace_back(computeCoeffs(i, mTaps, osf * factor, alpha));
32-
}
33-
15+
computeCoeffs(taps, beta, samplerate / symbolrate);
3416
mMemory.resize(mTaps, 0);
3517
}
3618

37-
float RRCFilter::computeCoeffs(int stageNo, uint16_t taps, float osf, float alpha)
19+
void RRCFilter::computeCoeffs(int taps, float beta, float Ts)
3820
{
3921
float coeff;
40-
float t;
41-
float interm;
42-
int order;
43-
44-
order = (taps - 1)/2;
45-
46-
if (order == stageNo) {
47-
return 1 - alpha + 4 * alpha / M_PI;
22+
float half = taps / 2.0f;
23+
float limit = Ts / (4.0 * beta);
24+
for (int i = 0; i < taps; i++) {
25+
float t = (float)i - half + 0.5;
26+
if (t == 0.0) {
27+
coeff = (1.0f + beta * (4.0f / M_PI - 1.0f)) / Ts;
28+
}
29+
else if (t == limit || t == -limit) {
30+
coeff = ((1.0f + 2.0f / M_PI) * sinf(M_PI / (4.0f * beta)) + (1.0f - 2.0f / M_PI)*cos(M_PI / (4.0f * beta))) * beta / (Ts * sqrtf(2.0f));
31+
}
32+
else {
33+
coeff = ((sinf((1.0f - beta) * M_PI * t / Ts) + cosf((1.0f + beta) * M_PI * t / Ts) * 4.0f * beta * t / Ts) / ((1.0f - (4.0f * beta * t / Ts) * (4.0f * beta * t / Ts)) * M_PI * t / Ts)) / Ts;
34+
}
35+
mCoeffs.emplace_back(coeff);
4836
}
49-
50-
t = std::abs(order - stageNo) / osf;
51-
coeff = std::sin(M_PI * t * (1 - alpha)) + 4 * alpha * t * std::cos(M_PI * t * (1 + alpha));
52-
interm = M_PI * t * (1 - (4 * alpha * t) * (4 * alpha * t));
53-
54-
return coeff / interm;
5537
}
5638

5739
} //namespace DSP

DSP/filter.h

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,27 @@ class FilterBase
1414
public:
1515
FilterBase(int taps);
1616
virtual ~FilterBase() {}
17-
complex process(const complex &in);
17+
18+
inline complex process(const complex &in) {
19+
complex out = 0.0f;
20+
21+
mMemory.push_front(in);
22+
mMemory.pop_back();
23+
24+
std::list<complex>::const_reverse_iterator it = mMemory.crbegin();
25+
26+
for(int i = mTaps - 1; i >=0; --i, ++it) {
27+
out += (*it) * mCoeffs[i];
28+
}
29+
return out;
30+
}
31+
32+
inline void process(const complex *inSamples, complex *outSamples, unsigned int count) {
33+
for(unsigned int i = 0; i < count; i++) {
34+
*outSamples = process(*inSamples++);
35+
outSamples++;
36+
}
37+
}
1838

1939
protected:
2040
std::vector<float> mCoeffs;
@@ -24,10 +44,10 @@ class FilterBase
2444

2545
class RRCFilter : public FilterBase {
2646
public:
27-
RRCFilter(unsigned order, unsigned factor, float osf, float alpha);
47+
RRCFilter(int taps, float beta, float symbolrate, float samplerate);
2848

2949
private:
30-
float computeCoeffs(int stageNo, uint16_t taps, float osf, float alpha);
50+
void computeCoeffs(int taps, float beta, float Ts);
3151
};
3252

3353
} //namespace DSP

DSP/meteorcostas.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "meteorcostas.h"
2+
3+
namespace DSP {
4+
5+
MeteorCostas::MeteorCostas(float bandWidth, float initPhase, float initFreq, float minFreq, float maxFreq, bool brokenModulation)
6+
: PLL(bandWidth, initPhase, initFreq, minFreq, maxFreq)
7+
, mPllOriginalBandwidth(bandWidth)
8+
, mBrokenModulation(brokenModulation)
9+
, mError(0.0f)
10+
, mLockDetector(0.0f)
11+
, mIsLocked(false)
12+
, mIsLockedOnce(false)
13+
{
14+
15+
}
16+
17+
} // namespace DSP

DSP/meteorcostas.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#ifndef DSP_METEORCOSTAS_H
2+
#define DSP_METEORCOSTAS_H
3+
4+
#include "pll.h"
5+
#include <algorithm>
6+
7+
namespace DSP {
8+
9+
class MeteorCostas : public PLL
10+
{
11+
private:
12+
static constexpr float cLockDetectionTreshold = 0.22;
13+
static constexpr float cUnLockDetectionTreshold = 0.25;
14+
static constexpr float cLockFilterCoeff = 0.00001f;
15+
16+
public:
17+
MeteorCostas(float bandWidth, float initPhase = 0.0f, float initFreq = 0.0f, float minFreq = -M_PI, float maxFreq = M_PI, bool brokenModulation = false);
18+
19+
inline virtual complex process(const complex &sample) override {
20+
complex retval;
21+
retval = sample * complex(cosf(-mPhase), sinf(-mPhase));
22+
mError = errorFunction(retval);
23+
advance(mError);
24+
return retval;
25+
}
26+
27+
inline virtual void process(const complex *insamples, complex *outsampes, unsigned int count) {
28+
for(unsigned int i = 0; i < count; i++) {
29+
*outsampes++ = process(*insamples++);
30+
}
31+
}
32+
33+
protected:
34+
float errorFunction(complex value) {
35+
float error;
36+
if(mBrokenModulation) {
37+
const float PHASE1 = 0.47439988279190737;
38+
const float PHASE2 = 2.1777839908413044;
39+
const float PHASE3 = 3.8682349942715186;
40+
const float PHASE4 = -0.29067248091319986;
41+
42+
float phase = atan2f(value.imag(), value.real());
43+
float dp1 = normalizePhase(phase - PHASE1);
44+
float dp2 = normalizePhase(phase - PHASE2);
45+
float dp3 = normalizePhase(phase - PHASE3);
46+
float dp4 = normalizePhase(phase - PHASE4);
47+
float lowest = dp1;
48+
if (fabsf(dp2) < fabsf(lowest)) { lowest = dp2; }
49+
if (fabsf(dp3) < fabsf(lowest)) { lowest = dp3; }
50+
if (fabsf(dp4) < fabsf(lowest)) { lowest = dp4; }
51+
error = lowest * std::abs(value);
52+
} else {
53+
error = (step(value.real()) * value.imag()) - (step(value.imag()) * value.real());
54+
}
55+
56+
mLockDetector = std::abs(error) * cLockFilterCoeff + mLockDetector * (1.0f - cLockFilterCoeff);
57+
58+
if(mLockDetector < cLockDetectionTreshold && !mIsLocked) {
59+
mIsLocked = true;
60+
setBandWidth(mPllOriginalBandwidth/5.0f);
61+
} else if(mLockDetector > cUnLockDetectionTreshold && mIsLocked) {
62+
mIsLocked = false;
63+
setBandWidth(mPllOriginalBandwidth);
64+
}
65+
66+
if(mLockDetector < cLockDetectionTreshold) {
67+
mIsLockedOnce = true;
68+
}
69+
70+
return std::clamp(error, -1.0f, 1.0f);
71+
}
72+
73+
inline float step(float val) {
74+
return val > 0 ? 1.0f : -1.0f;
75+
}
76+
77+
public:
78+
inline float getError() const {
79+
return mLockDetector;
80+
}
81+
inline bool isLocked() const {
82+
return mIsLocked;
83+
}
84+
inline bool isLockedOnce() const {
85+
return mIsLockedOnce;
86+
}
87+
88+
protected:
89+
float mPllOriginalBandwidth;
90+
bool mBrokenModulation;
91+
float mError;
92+
float mLockDetector;
93+
bool mIsLocked;
94+
bool mIsLockedOnce;
95+
};
96+
97+
} // namespace DSP
98+
99+
#endif // DSP_METEORCOSTAS_H

0 commit comments

Comments
 (0)