1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-22 16:08:39 -05:00

Merge pull request #826 from srcejon/datvmod_dvbs2

Add DVB-S2 modulator
This commit is contained in:
Edouard Griffiths 2021-03-31 18:35:07 +02:00 committed by GitHub
commit 688386e5ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 4123 additions and 76 deletions

View File

@ -9,6 +9,18 @@ set(moddatv_SOURCES
datvmodsettings.cpp
datvmodwebapiadapter.cpp
dvb-s/dvb-s.cpp
dvb-s2/DVB2.cpp
dvb-s2/DVBS2.cpp
dvb-s2/dvb2_bbheader.cpp
dvb-s2/dvb2_bch.cpp
dvb-s2/dvb2_ldpc_encode.cpp
dvb-s2/dvb2_ldpc_tables.cpp
dvb-s2/dvb2_scrambler.cpp
dvb-s2/dvbs2_interleave.cpp
dvb-s2/dvbs2_modulator.cpp
dvb-s2/dvbs2_physical.cpp
dvb-s2/dvbs2_scrambler.cpp
dvb-s2/dvbs2_tables.cpp
)
set(moddatv_HEADERS
@ -20,6 +32,9 @@ set(moddatv_HEADERS
datvmodsettings.h
datvmodwebapiadapter.h
dvb-s/dvb-s.h
dvb-s/dvb-s.h
dvb-s2/DVB2.h
dvb-s2/DVBS2.h
)
include_directories(

View File

@ -225,16 +225,59 @@ void DATVModGUI::on_deltaFrequency_changed(qint64 value)
void DATVModGUI::on_dvbStandard_currentIndexChanged(int index)
{
int idx;
m_settings.m_standard = (DATVModSettings::DVBStandard) index;
ui->fec->blockSignals(true);
ui->rollOff->blockSignals(true);
ui->modulation->blockSignals(true);
ui->fec->clear();
ui->rollOff->clear();
ui->modulation->clear();
if (m_settings.m_standard == DATVModSettings::DVB_S)
{
ui->rollOff->addItem("0.35");
ui->modulation->addItem("BPSK");
ui->modulation->addItem("QPSK");
}
else
{
ui->rollOff->addItem("0.20");
ui->rollOff->addItem("0.25");
ui->rollOff->addItem("0.35");
ui->modulation->addItem("QPSK");
ui->modulation->addItem("8PSK");
ui->modulation->addItem("16APSK");
ui->modulation->addItem("32APSK");
}
ui->rollOff->blockSignals(false);
ui->modulation->blockSignals(false);
m_doApplySettings = false;
idx = ui->rollOff->findText(QString("%1").arg(m_settings.m_rollOff, 0, 'f', 2));
idx = idx == -1 ? 0 : idx;
ui->rollOff->setCurrentIndex(idx);
on_rollOff_currentIndexChanged(idx);
idx = ui->modulation->findText(DATVModSettings::mapModulation(m_settings.m_modulation));
idx = idx == -1 ? 0 : idx;
ui->modulation->setCurrentIndex(idx);
on_modulation_currentIndexChanged(idx);
updateFEC();
m_doApplySettings = true;
applySettings();
}
void DATVModGUI::updateFEC()
{
ui->fec->blockSignals(true);
ui->fec->clear();
if (m_settings.m_standard == DATVModSettings::DVB_S)
{
ui->fec->addItem("1/2");
@ -242,11 +285,8 @@ void DATVModGUI::on_dvbStandard_currentIndexChanged(int index)
ui->fec->addItem("3/4");
ui->fec->addItem("5/6");
ui->fec->addItem("7/8");
ui->rollOff->addItem("0.35");
ui->modulation->addItem("BPSK");
ui->modulation->addItem("QPSK");
}
else
else if (m_settings.m_modulation == DATVModSettings::QPSK)
{
ui->fec->addItem("1/4");
ui->fec->addItem("1/3");
@ -259,29 +299,51 @@ void DATVModGUI::on_dvbStandard_currentIndexChanged(int index)
ui->fec->addItem("5/6");
ui->fec->addItem("8/9");
ui->fec->addItem("9/10");
ui->rollOff->addItem("0.20");
ui->rollOff->addItem("0.25");
ui->rollOff->addItem("0.35");
ui->modulation->addItem("QPSK");
ui->modulation->addItem("8PSK");
ui->modulation->addItem("16APSK");
ui->modulation->addItem("32APSK");
}
else if (m_settings.m_modulation == DATVModSettings::PSK8)
{
ui->fec->addItem("3/5");
ui->fec->addItem("2/3");
ui->fec->addItem("3/4");
ui->fec->addItem("5/6");
ui->fec->addItem("8/9");
ui->fec->addItem("9/10");
}
else if (m_settings.m_modulation == DATVModSettings::APSK16)
{
ui->fec->addItem("2/3");
ui->fec->addItem("3/4");
ui->fec->addItem("4/5");
ui->fec->addItem("5/6");
ui->fec->addItem("8/9");
ui->fec->addItem("9/10");
}
else if (m_settings.m_modulation == DATVModSettings::APSK32)
{
ui->fec->addItem("3/4");
ui->fec->addItem("4/5");
ui->fec->addItem("5/6");
ui->fec->addItem("8/9");
ui->fec->addItem("9/10");
}
ui->fec->setCurrentIndex(ui->fec->findText(DATVModSettings::mapCodeRate(m_settings.m_fec)));
ui->rollOff->setCurrentIndex(ui->rollOff->findText(QString("%1").arg(m_settings.m_rollOff, 0, 'f', 2)));
ui->modulation->setCurrentIndex(ui->modulation->findText(DATVModSettings::mapModulation(m_settings.m_modulation)));
ui->fec->blockSignals(false);
ui->rollOff->blockSignals(false);
ui->modulation->blockSignals(false);
applySettings();
int idx = ui->fec->findText(DATVModSettings::mapCodeRate(m_settings.m_fec));
idx = idx == -1 ? 0 : idx;
ui->fec->setCurrentIndex(idx);
on_fec_currentIndexChanged(idx);
}
void DATVModGUI::on_modulation_currentIndexChanged(int index)
{
m_settings.m_modulation = (DATVModSettings::DATVModulation) index;
if (m_settings.m_standard == DATVModSettings::DVB_S)
m_settings.m_modulation = (DATVModSettings::DATVModulation) index;
else
m_settings.m_modulation = (DATVModSettings::DATVModulation) (index + 1);
m_doApplySettings = false;
updateFEC();
m_doApplySettings = true;
applySettings();
}

View File

@ -84,6 +84,7 @@ private:
void updateWithStreamTime();
void setChannelMarkerBandwidth();
bool handleMessage(const Message& message);
void updateFEC();
void leaveEvent(QEvent*);
void enterEvent(QEvent*);

View File

@ -246,6 +246,11 @@
<string>DVB-S</string>
</property>
</item>
<item>
<property name="text">
<string>DVB-S2</string>
</property>
</item>
</widget>
</item>
<item>

View File

@ -29,8 +29,8 @@
const PluginDescriptor DATVModPlugin::m_pluginDescriptor = {
DATVMod::m_channelId,
QStringLiteral("DATV Modulator"),
QStringLiteral("6.6.3"),
QStringLiteral("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"),
QStringLiteral("6.7.1"),
QStringLiteral("(c) Jon Beniston, M7RCE, Edouard Griffiths, F4EXB. DVB-S2 by G4GUO"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,
QStringLiteral("https://github.com/f4exb/sdrangel")

View File

@ -74,49 +74,10 @@ int DATVModSource::getTSBitrate(const QString& filename)
// Get data bitrate (i.e. excluding FEC overhead)
int DATVModSource::getDVBSDataBitrate(const DATVModSettings& settings)
{
float rsFactor = DVBS::tsPacketLen/(float)DVBS::rsPacketLen;
float convFactor;
float fecFactor;
float plFactor;
float bitsPerSymbol;
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
convFactor = 1.0f/2.0f;
break;
case DATVModSettings::FEC23:
convFactor = 2.0f/3.0f;
break;
case DATVModSettings::FEC34:
convFactor = 3.0f/4.0f;
break;
case DATVModSettings::FEC56:
convFactor = 5.0f/6.0f;
break;
case DATVModSettings::FEC78:
convFactor = 7.0f/8.0f;
break;
case DATVModSettings::FEC45:
convFactor = 4.0f/5.0f;
break;
case DATVModSettings::FEC89:
convFactor = 8.0f/9.0f;
break;
case DATVModSettings::FEC910:
convFactor = 9.0f/10.0f;
break;
case DATVModSettings::FEC14:
convFactor = 1.0f/4.0f;
break;
case DATVModSettings::FEC13:
convFactor = 1.0f/3.0f;
break;
case DATVModSettings::FEC25:
convFactor = 2.0f/5.0f;
break;
case DATVModSettings::FEC35:
convFactor = 3.0f/5.0f;
break;
}
switch (settings.m_modulation)
{
case DATVModSettings::BPSK:
@ -136,16 +97,116 @@ int DATVModSource::getDVBSDataBitrate(const DATVModSettings& settings)
break;
}
return std::round(settings.m_symbolRate * bitsPerSymbol * rsFactor * convFactor);
if (settings.m_standard == DATVModSettings::DVB_S)
{
float rsFactor;
float convFactor;
rsFactor = DVBS::tsPacketLen/(float)DVBS::rsPacketLen;
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
convFactor = 1.0f/2.0f;
break;
case DATVModSettings::FEC23:
convFactor = 2.0f/3.0f;
break;
case DATVModSettings::FEC34:
convFactor = 3.0f/4.0f;
break;
case DATVModSettings::FEC56:
convFactor = 5.0f/6.0f;
break;
case DATVModSettings::FEC78:
convFactor = 7.0f/8.0f;
break;
case DATVModSettings::FEC45:
convFactor = 4.0f/5.0f;
break;
case DATVModSettings::FEC89:
convFactor = 8.0f/9.0f;
break;
case DATVModSettings::FEC910:
convFactor = 9.0f/10.0f;
break;
case DATVModSettings::FEC14:
convFactor = 1.0f/4.0f;
break;
case DATVModSettings::FEC13:
convFactor = 1.0f/3.0f;
break;
case DATVModSettings::FEC25:
convFactor = 2.0f/5.0f;
break;
case DATVModSettings::FEC35:
convFactor = 3.0f/5.0f;
break;
}
fecFactor = rsFactor * convFactor;
plFactor = 1.0f;
}
else
{
// For normal frames
int codedBlockSize = 64800;
int uncodedBlockSize;
int bbHeaderBits = 80;
// See table 5a in DVBS2 spec
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
uncodedBlockSize = 32208;
break;
case DATVModSettings::FEC23:
uncodedBlockSize = 43040;
break;
case DATVModSettings::FEC34:
uncodedBlockSize = 48408;
break;
case DATVModSettings::FEC56:
uncodedBlockSize = 53840;
break;
case DATVModSettings::FEC45:
uncodedBlockSize = 51648;
break;
case DATVModSettings::FEC89:
uncodedBlockSize = 57472;
break;
case DATVModSettings::FEC910:
uncodedBlockSize = 58192;
break;
case DATVModSettings::FEC14:
uncodedBlockSize = 16008;
break;
case DATVModSettings::FEC13:
uncodedBlockSize = 21408;
break;
case DATVModSettings::FEC25:
uncodedBlockSize = 25728;
break;
case DATVModSettings::FEC35:
uncodedBlockSize = 38688;
break;
default:
qDebug() << "DATVModSource::getDVBSDataBitrate: Unsupported DVB-S2 code rate";
break;
}
fecFactor = (uncodedBlockSize-bbHeaderBits)/(float)codedBlockSize;
float symbolsPerFrame = codedBlockSize/bitsPerSymbol;
// 90 symbols for PL header
plFactor = symbolsPerFrame / (symbolsPerFrame + 90.0f);
}
return std::round(settings.m_symbolRate * bitsPerSymbol * fecFactor * plFactor);
}
void DATVModSource::checkBitrates()
{
int dataBitrate = getDVBSDataBitrate(m_settings);
qDebug() << "MPEG-TS bitrate: " << m_mpegTSBitrate;
qDebug() << "DVB-S data bitrate: " << dataBitrate;
qDebug() << "DVB data bitrate: " << dataBitrate;
if (dataBitrate < m_mpegTSBitrate)
qWarning() << "DVB-S data bitrate is lower than the bitrate of the MPEG transport stream";
qWarning() << "DVB data bitrate is lower than the bitrate of the MPEG transport stream";
m_tsRatio = m_mpegTSBitrate/(float)dataBitrate;
}
@ -316,6 +377,12 @@ void DATVModSource::modulateSample()
// Encode using DVB-S
m_symbolCount = m_dvbs.encode(m_mpegTS, m_iqSymbols);
}
else
{
// Encode using DVB-S2
m_symbolCount = m_dvbs2.s2_add_ts_frame((u8 *)m_mpegTS);
m_plFrame = m_dvbs2.pl_get_frame();
}
// Loop file if we reach the end
if ((m_frameIdx*DVBS::tsPacketLen >= m_mpegTSSize) && m_settings.m_tsFilePlayLoop)
@ -372,9 +439,17 @@ void DATVModSource::modulateSample()
q = m_pulseShapeQ.filter(sin(5*M_PI/4));
}
*/
m_symbolIdx++;
m_symbolCount--;
}
else
{
// First 90 symbols of DVB-S2 are pi/2 BPSK, then remaining symbols are in specified modulation
i = m_pulseShapeI.filter(m_plFrame[m_symbolIdx].re/32767.0);
q = m_pulseShapeQ.filter(m_plFrame[m_symbolIdx].im/32767.0);
m_symbolIdx++;
m_symbolCount--;
}
m_symbolIdx++;
m_symbolCount--;
}
}
else
@ -621,6 +696,83 @@ void DATVModSource::applySettings(const DATVModSettings& settings, bool force)
break;
}
}
else
{
m_dvbs2Format.frame_type = FRAME_NORMAL;
m_dvbs2Format.pilots = 0; // PILOTS_OFF;
m_dvbs2Format.dummy_frame = 0;
m_dvbs2Format.null_deletion = 0;
m_dvbs2Format.intface = M_ACM; // Unused?
m_dvbs2Format.broadcasting = 1;
switch (settings.m_modulation)
{
case DATVModSettings::QPSK:
m_dvbs2Format.constellation = M_QPSK;
break;
case DATVModSettings::PSK8:
m_dvbs2Format.constellation = M_8PSK;
break;
case DATVModSettings::APSK16:
m_dvbs2Format.constellation = M_16APSK;
break;
case DATVModSettings::APSK32:
m_dvbs2Format.constellation = M_32APSK;
break;
default:
qDebug() << "DATVModSource::applySettings: Unsupported modulation for DVB-S2";
break;
}
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
m_dvbs2Format.code_rate = CR_1_2;
break;
case DATVModSettings::FEC23:
m_dvbs2Format.code_rate = CR_2_3;
break;
case DATVModSettings::FEC34:
m_dvbs2Format.code_rate = CR_3_4;
break;
case DATVModSettings::FEC56:
m_dvbs2Format.code_rate = CR_5_6;
break;
case DATVModSettings::FEC45:
m_dvbs2Format.code_rate = CR_4_5;
break;
case DATVModSettings::FEC89:
m_dvbs2Format.code_rate = CR_8_9;
break;
case DATVModSettings::FEC910:
m_dvbs2Format.code_rate = CR_9_10;
break;
case DATVModSettings::FEC14:
m_dvbs2Format.code_rate = CR_1_4;
break;
case DATVModSettings::FEC13:
m_dvbs2Format.code_rate = CR_1_3;
break;
case DATVModSettings::FEC25:
m_dvbs2Format.code_rate = CR_2_5;
break;
case DATVModSettings::FEC35:
m_dvbs2Format.code_rate = CR_3_5;
break;
default:
qDebug() << "DATVModSource::getDVBSDataBitrate: Unsupported code rate for DVB-S2";
break;
}
if (settings.m_rollOff == 0.35f)
m_dvbs2Format.roll_off = RO_0_35;
else if (settings.m_rollOff == 0.25f)
m_dvbs2Format.roll_off = RO_0_25;
else
m_dvbs2Format.roll_off = RO_0_20;
m_dvbs2.s2_set_configure(&m_dvbs2Format);
}
if (getMessageQueueToGUI())
{
getMessageQueueToGUI()->push(DATVModReport::MsgReportRates::create(

View File

@ -38,6 +38,7 @@
#include "datvmodsettings.h"
#include "dvb-s/dvb-s.h"
#include "dvb-s2/DVBS2.h"
class MessageQueue;
class QUdpSocket;
@ -88,6 +89,10 @@ private:
int m_samplesPerSymbol;
uint8_t m_iqSymbols[DVBS::m_maxIQSymbols*2];
DVBS2 m_dvbs2;
DVB2FrameFormat m_dvbs2Format;
scmplx *m_plFrame;
QUdpSocket *m_udpSocket; //!< UDP socket to receive MPEG transport stream via
int m_udpByteCount; //!< Count of bytes received via UDP for bitrate calculation
boost::chrono::steady_clock::time_point m_udpTimingStart; //!< When we last started counting UDP bytes

View File

@ -0,0 +1,272 @@
#include "memory.h"
#include "DVB2.h"
//
// Update working parameters for the next frame
// This prevents parameters changing during a frame
//
void DVB2::base_end_of_frame_actions(void)
{
if( m_params_changed )
{
m_format[0] = m_format[1];
ldpc_lookup_generate();
m_params_changed = 0;
}
// reset the pointer
m_frame_offset_bits = 0;
}
//
// This configures the system and calculates
// any required intermediate values
//
int DVB2::set_configure( DVB2FrameFormat *f )
{
int bch_bits = 0;
int error = 0;
if( f->broadcasting )
{
// Set standard parametrs for broadcasting
f->frame_type = FRAME_NORMAL;
f->bb_header.ts_gs = TS_GS_TRANSPORT;
f->bb_header.sis_mis = SIS_MIS_SINGLE;
f->bb_header.ccm_acm = CCM;
f->bb_header.issyi = 0;
f->bb_header.npd = 0;
f->bb_header.upl = 188*8;
f->bb_header.sync = 0x47;
}
f->bb_header.ro = f->roll_off;
// Fill in the mode specific values and bit lengths
if( f->frame_type == FRAME_NORMAL )
{
f->nldpc = 64800;
bch_bits = 192;
f->bch_code = BCH_CODE_N12;
// Apply code rate
switch(f->code_rate )
{
case CR_1_4:
f->q_val = 135;
f->kbch = 16008;
f->bch_code = BCH_CODE_N12;
break;
case CR_1_3:
f->q_val = 120;
f->kbch = 21408;
f->bch_code = BCH_CODE_N12;
break;
case CR_2_5:
f->q_val = 108;
f->kbch = 25728;
f->bch_code = BCH_CODE_N12;
break;
case CR_1_2:
f->q_val = 90;
f->kbch = 32208;
f->bch_code = BCH_CODE_N12;
break;
case CR_3_5:
f->q_val = 72;
f->kbch = 38688;
f->bch_code = BCH_CODE_N12;
break;
case CR_2_3:
bch_bits = 160;
f->q_val = 60;
f->kbch = 43040;
f->bch_code = BCH_CODE_N10;
break;
case CR_3_4:
f->q_val = 45;
f->kbch = 48408;
f->bch_code = BCH_CODE_N12;
break;
case CR_4_5:
f->q_val = 36;
f->kbch = 51648;
f->bch_code = BCH_CODE_N12;
break;
case CR_5_6:
bch_bits = 160;
f->q_val = 30;
f->kbch = 53840;
f->bch_code = BCH_CODE_N10;
break;
case CR_8_9:
bch_bits = 128;
f->q_val = 20;
f->kbch = 57472;
f->bch_code = BCH_CODE_N8;
break;
case CR_9_10:
bch_bits = 128;
f->q_val = 18;
f->kbch = 58192;
f->bch_code = BCH_CODE_N8;
break;
default:
// loggerf("Configuration error DVB2\n");
error = -1;
break;
}
}
if( f->frame_type == FRAME_SHORT )
{
f->nldpc = 16200;
bch_bits = 168;
f->bch_code = BCH_CODE_S12;
// Apply code rate
switch(f->code_rate )
{
case CR_1_4:
f->q_val = 36;
f->kbch = 3072;
break;
case CR_1_3:
f->q_val = 30;
f->kbch = 5232;
break;
case CR_2_5:
f->q_val = 27;
f->kbch = 6312;
break;
case CR_1_2:
f->q_val = 25;
f->kbch = 7032;
break;
case CR_3_5:
f->q_val = 18;
f->kbch = 9552;
break;
case CR_2_3:
f->q_val = 15;
f->kbch = 10632;
break;
case CR_3_4:
f->q_val = 12;
f->kbch = 11712;
break;
case CR_4_5:
f->q_val = 10;
f->kbch = 12432;
break;
case CR_5_6:
f->q_val = 8;
f->kbch = 13152;
break;
case CR_8_9:
f->q_val = 5;
f->kbch = 14232;
break;
case CR_9_10:
error = 1;
f->kbch = 0;
break;
default:
// loggerf("Configuration error DVB2\n");
error = -1;
break;
}
}
if( error == 0 )
{
// Length of the user packets
f->bb_header.upl = 188*8;
// Payload length
f->bb_header.dfl = f->kbch - 80;
// Transport packet sync
f->bb_header.sync = 0x47;
// Start of LDPC bits
f->kldpc = f->kbch + bch_bits;
// Number of padding bits required (not used)
f->padding_bits = 0;
// Number of useable data bits (not used)
f->useable_data_bits = f->kbch - 80;
// Save the configuration, will be updated on next frame
m_format[1] = *f;
// reset various pointers
m_dnp = 0;// No deleted null packets
// Signal we need to update on the next frame.
if( m_params_changed )
base_end_of_frame_actions();
else
m_params_changed = 1;
}
return error;
}
void DVB2::get_configure( DVB2FrameFormat *f )
{
*f = m_format[1];
}
// Points to first byte in transport packet
int DVB2::add_ts_frame_base( u8 *ts )
{
if( m_frame_offset_bits == 0 )
{
// New frame needs to be sent
add_bbheader(); // Add the header
}
// Add a new transport packet
unpack_transport_packet_add_crc( ts );
// Have we reached the end?
if( m_frame_offset_bits == m_format[0].kbch )
{
// Yes so now Scramble the BB frame
bb_randomise();
// BCH encode the BB Frame
bch_encode();
// LDPC encode the BB frame and BCHFEC bits
ldpc_encode();
// Signal to the modulation specific class we have something to send
base_end_of_frame_actions();
return 1;
}
return 0;
}
//
// Dump NULL packets appends a counter to the end of each UP
// it is not implemented at the moment.
//
int DVB2::next_ts_frame_base( u8 *ts )
{
int res = 0;
// See if we need to dump null packets
if( m_format[0].null_deletion == 1 )
{
if(((ts[0]&0x1F) == 0x1F)&&(ts[1] == 0xFF ))
{
// Null packet detected
if( m_dnp < 0xFF )
{
m_dnp++;// Increment the number of null packets
return 0;
}
}
}
// Need to send a new transport packet
res = add_ts_frame_base( ts );
if( res ) m_dnp = 0;// Clear the DNP counter
// return whether it is time to transmit a new frame
return res;
}
DVB2::DVB2(void)
{
// Clear the transport queue
m_tp_q.empty();
init_bb_randomiser();
bch_poly_build_tables();
build_crc8_table();
m_dnp = 0;// No delted null packets
m_frame_offset_bits = 0;
m_params_changed = 1;
}
DVB2::~DVB2(void)
{
}

View File

@ -0,0 +1,218 @@
#ifndef DVB2_H
#define DVB2_H
#include <queue>
#include <deque>
#include <list>
#include <stdio.h>
typedef unsigned int u32;
typedef unsigned char u8;
using namespace std;
// BB HEADER fileds
#define TS_GS_TRANSPORT 3
#define TS_GS_GENERIC_PACKETIZED 0
#define TS_GS_GENERIC_CONTINUOUS 1
#define TS_GS_RESERVED 2
#define SIS_MIS_SINGLE 1
#define SIS_MIS_MULTIPLE 0
#define CCM 1
#define ACM 0
#define ISSYI_ACTIVE 1
#define ISSYI_NOT_ACTIVE 0
#define NPD_ACTIVE 1
#define NPD_NOT_ACTIVE 0
// Rolloff
#define RO_0_35 0
#define RO_0_25 1
#define RO_0_20 2
#define RO_RESERVED 3
// Pilots
#define PILOTS_OFF 0
#define PILOTS_ON 1
typedef struct{
int ts_gs;
int sis_mis;
int ccm_acm;
int issyi;
int npd;
int ro;
int isi;
int upl;
int dfl;
int sync;
int syncd;
}BBHeader;
typedef int Bit;
// The number of useable and stuff bits in a frame
typedef struct{
int data_bits;
int stuff_bits;
}FrameBits;
#define FRAME_SIZE_NORMAL 64800
#define FRAME_SIZE_SHORT 16200
#define LDPC_ENCODE_TABLE_LENGTH (FRAME_SIZE_NORMAL*10)
typedef struct{
int table_length;
Bit d[LDPC_ENCODE_TABLE_LENGTH];
Bit p[LDPC_ENCODE_TABLE_LENGTH];
}Ldpc_encode_table;
#define FRAME_NORMAL 0x00
#define FRAME_SHORT 0x10
#define BB_HEADER_LENGTH_BITS 72
#define CRC8_LENGTH_BITS 8
#define PADDING_LENGTH 200
// Code rates
#define CR_1_4 0
#define CR_1_3 1
#define CR_2_5 2
#define CR_1_2 3
#define CR_3_5 4
#define CR_2_3 5
#define CR_3_4 6
#define CR_4_5 7
#define CR_5_6 8
#define CR_8_9 9
#define CR_9_10 10
// BCH Code
#define BCH_CODE_N8 0
#define BCH_CODE_N10 1
#define BCH_CODE_N12 2
#define BCH_CODE_S12 3
// Constellation
#define M_QPSK 0
#define M_8PSK 1
#define M_16APSK 2
#define M_32APSK 3
//Interface
#define M_ACM 0
#define M_CCM 1
#define M_VCM 2
typedef struct{
int frame_type;
int code_rate;
int roll_off;
int constellation;
int pilots;
int dummy_frame;
int null_deletion;
int intface;
int broadcasting;
// Calculated information, not used by caller
BBHeader bb_header;
int kldpc;
int kbch;
int nldpc;
int q_val;
int bch_code;
int useable_data_bits;
int padding_bits;
int total_bits;
int nr_tps;
int nr_tps_bits;
}DVB2FrameFormat;
class DVB2{
public:
protected:
Bit m_frame[FRAME_SIZE_NORMAL];
DVB2FrameFormat m_format[2];
Bit m_padding[PADDING_LENGTH];
int m_frame_offset_bits;
int m_params_changed;
private:
int m_bbheader[BB_HEADER_LENGTH_BITS+CRC8_LENGTH_BITS];
int m_bb_randomise[FRAME_SIZE_NORMAL];
u32 m_poly_n_8[4];
u32 m_poly_n_10[5];
u32 m_poly_n_12[6];
u32 m_poly_s_12[6];
u8 m_crc_tab[256];
u8 m_dnp; // Deleted null packet
// Transport packet queue
queue <u8> m_tp_q;
// LDPC tables
const static int ldpc_tab_1_4N[45][13];
const static int ldpc_tab_1_3N[60][13];
const static int ldpc_tab_2_5N[72][13];
const static int ldpc_tab_1_2N[90][9];
const static int ldpc_tab_3_5N[108][13];
const static int ldpc_tab_2_3N[120][14];
const static int ldpc_tab_3_4N[135][13];
const static int ldpc_tab_4_5N[144][12];
const static int ldpc_tab_5_6N[150][14];
const static int ldpc_tab_8_9N[160][5];
const static int ldpc_tab_9_10N[162][5];
const static int ldpc_tab_1_4S[9][13];
const static int ldpc_tab_1_3S[15][13];
const static int ldpc_tab_2_5S[18][13];
const static int ldpc_tab_1_2S[20][9];
const static int ldpc_tab_3_5S[27][13];
const static int ldpc_tab_2_3S[30][14];
const static int ldpc_tab_3_4S[33][13];
const static int ldpc_tab_4_5S[35][4];
const static int ldpc_tab_5_6S[37][14];
const static int ldpc_tab_8_9S[40][5];
Ldpc_encode_table m_ldpc_encode;
void bb_randomise(void);
void init_scrambler(void);
void init_bb_randomiser(void);
void ldpc_lookup_generate(void);
void ldpc_encode( void );
int add_transport_packet( u8 *pkt, Bit *b );
void build_crc8_table( void );
u8 calc_crc8( u8 *b, int len );
int add_crc8_bits( Bit *in, int length );
void unpack_transport_packet_add_crc( u8 *ts );
void add_bbheader( void );
void poly_reverse( int *pin, int *pout, int len );
void poly_pack( const int *pin, u32* pout, int len );
int poly_mult( const int *ina, int lena, const int *inb, int lenb, int *out );
void bch_poly_build_tables( void );
void reg_4_shift( u32 *sr );
void reg_5_shift( u32 *sr );
void reg_6_shift( u32 *sr );
Bit bch_n_8_encode( Bit *in, int len );
Bit bch_n_10_encode( Bit *in, int len );
Bit bch_n_12_encode( Bit *in, int len );
Bit bch_s_12_encode( Bit *in, int len );
int bch_encode( void );
int add_ts_frame_base( u8 *ts );
void ldpc_encode_test();
void base_end_of_frame_actions(void);
protected:
int set_configure( DVB2FrameFormat *f );
void get_configure( DVB2FrameFormat *f );
int next_ts_frame_base( u8 *ts );
public:
// encode a new transport packet
// virtual void physical(void);
DVB2();
~DVB2();
};
#endif

View File

@ -0,0 +1,156 @@
#include "memory.h"
#include "DVBS2.h"
//
// called at the end of a frame
//
void DVBS2::end_of_frame_actions(void)
{
if( m_s2_config_updated )
{
modulator_configuration();
m_s2_config_updated = 0;
}
}
int DVBS2::is_valid( int mod, int coderate )
{
if( mod == M_QPSK )
{
if(coderate == CR_1_4) return 0;
if(coderate == CR_1_3) return 0;
if(coderate == CR_2_5) return 0;
if(coderate == CR_1_2) return 0;
if(coderate == CR_3_5) return 0;
if(coderate == CR_2_3) return 0;
if(coderate == CR_3_4) return 0;
if(coderate == CR_4_5) return 0;
if(coderate == CR_5_6) return 0;
if(coderate == CR_8_9) return 0;
if(coderate == CR_9_10) return 0;
}
if( mod == M_8PSK )
{
if(coderate == CR_3_5) return 0;
if(coderate == CR_2_3) return 0;
if(coderate == CR_3_4) return 0;
if(coderate == CR_5_6) return 0;
if(coderate == CR_8_9) return 0;
if(coderate == CR_9_10) return 0;
}
if( mod == M_16APSK )
{
if(coderate == CR_2_3) return 0;
if(coderate == CR_3_4) return 0;
if(coderate == CR_4_5) return 0;
if(coderate == CR_5_6) return 0;
if(coderate == CR_8_9) return 0;
if(coderate == CR_9_10) return 0;
}
if( mod == M_32APSK )
{
if(coderate == CR_3_4) return 0;
if(coderate == CR_4_5) return 0;
if(coderate == CR_5_6) return 0;
if(coderate == CR_8_9) return 0;
if(coderate == CR_9_10) return 0;
}
return -1;
}
//
// index 0 and 1 will only be different when being reconfigured.
// Use index 1 as this will be applied in the following transmit
// frames
//
void DVBS2::calc_efficiency( void )
{
double p,m,a,s,b,po;
// Calculate the number of symbols in the payload
p = 0;a = 0; m = 0;
if( m_format[1].frame_type == FRAME_NORMAL ) p = (double)FRAME_SIZE_NORMAL;
if( m_format[1].frame_type == FRAME_SHORT ) p = (double)FRAME_SIZE_SHORT;
if( m_format[1].constellation == M_QPSK ) m = 2.0;
if( m_format[1].constellation == M_8PSK ) m = 3.0;
if( m_format[1].constellation == M_16APSK ) m = 4.0;
if( m_format[1].constellation == M_32APSK ) m = 5.0;
s = p/m;//Number of symbols per frame
// PL header overhead
if( m_format[1].pilots )
{
po = (s/(90*16))-1;// 1 pilot every 16 blocks (of 90 symbols)
po = po*36; // No pilot at the end
a = s/(90+po+s);
}
else
{
a = s/(90+s);// No pilots
}
// Modulation efficiency
a = a*m;
// Take into account pilot symbols
// TBD
// Now calculate the useable data as percentage of the frame
b = ((double)m_format[1].useable_data_bits)/p;
// Now calculate the efficiency by multiplying the
// useable bits efficiency by the modulation efficiency
m_efficiency = b*a;
}
//
// Multiply the efficiency value by the symbol rate
// to get the useable bitrate
//
double DVBS2::s2_get_efficiency( void )
{
return m_efficiency;
}
int DVBS2::s2_set_configure( DVB2FrameFormat *f )
{
if( is_valid( f->constellation, f->code_rate ) == 0 )
{
if( set_configure( f ) == 0 )
{
calc_efficiency();
m_s2_config_updated = 1;
m_configured = 1;
return 0;
}
}
return -1;
}
void DVBS2::s2_get_configure( DVB2FrameFormat *f )
{
get_configure( f );
}
int DVBS2::s2_add_ts_frame( u8 *ts )
{
int res = 0;
if (m_configured == 0) return 0;
// Call base class
if( next_ts_frame_base( ts ) )
{
// Interleave and pack
s2_interleave();
// create the header
s2_pl_header_create();
// Add the data
res = s2_pl_data_pack();
// Do any updates required for the next frame
end_of_frame_actions();
}
return res;
}
void DVBS2::physical( void )
{
}
DVBS2::DVBS2()
{
m_configured = 0;
modulator_configuration();
build_symbol_scrambler_table();
pl_build_dummy();
}

View File

@ -0,0 +1,65 @@
#include "DVB2.h"
#ifndef __SCMPLX__
typedef struct{
short re;
short im;
}scmplx;
#endif
#ifndef DVBS2_H
#define DVBS2_H
#ifndef M_PI
#define M_PI 3.14159f
#endif
#define loggerf printf
class DVBS2 : public DVB2{
private:
const static unsigned long g[6];
const static int ph_scram_tab[64];
const static int ph_sync_seq[26];
scmplx m_bpsk[2][2];
scmplx m_qpsk[4];
scmplx m_8psk[8];
scmplx m_16apsk[16];
scmplx m_32apsk[32];
scmplx m_pl[FRAME_SIZE_NORMAL];
scmplx m_pl_dummy[FRAME_SIZE_NORMAL];
int m_cscram[FRAME_SIZE_NORMAL];
int m_iframe[FRAME_SIZE_NORMAL];
int m_payload_symbols;
int m_dummy_frame_length;
int m_configured;
double m_efficiency;
int m_s2_config_updated;
void b_64_7_code( unsigned char in, int *out );
void s2_pl_header_encode( u8 modcod, u8 type, int *out);
void modulator_configuration(void);
void s2_interleave( void );
void s2_pl_header_create(void);
int s2_pl_data_pack( void );
void pl_scramble_symbols( scmplx *fs, int len );
void pl_scramble_dummy_symbols( int len );
void pl_build_dummy( void );
int parity_chk( long a, long b);
void build_symbol_scrambler_table( void );
void calc_efficiency( void );
void end_of_frame_actions(void);
public:
int is_valid(int mod, int coderate);
double s2_get_efficiency( void );
void physical(void);
int s2_set_configure( DVB2FrameFormat *f );
void s2_get_configure( DVB2FrameFormat *f );
scmplx *pl_get_frame(void);
scmplx *pl_get_dummy( int &len );
int s2_add_ts_frame( u8 *ts );
DVBS2();
};
#endif

View File

@ -0,0 +1,149 @@
#include "DVB2.h"
#include "memory.h"
//
// This file adds the BB header and new transport packets
//
#define CRC_POLY 0xAB
// Reversed
#define CRC_POLYR 0xD5
void DVB2::build_crc8_table( void )
{
int r,crc;
for( int i = 0; i < 256; i++ )
{
r = i;
crc = 0;
for( int j = 7; j >= 0; j-- )
{
if((r&(1<<j)?1:0) ^ ((crc&0x80)?1:0))
crc = (crc<<1)^CRC_POLYR;
else
crc <<= 1;
}
m_crc_tab[i] = crc;
}
}
u8 DVB2::calc_crc8( u8 *b, int len )
{
u8 crc = 0;
for( int i = 0; i < len; i++ )
{
crc = m_crc_tab[b[i]^crc];
}
return crc;
}
//
// MSB is sent first
//
// The polynomial has been reversed, this is only used for the BB header
//
int DVB2::add_crc8_bits( Bit *in, int length )
{
int crc = 0;
int b;
int i = 0;
for( int n = 0; n < length; n++ )
{
b = in[i++] ^ (crc&0x01);
crc >>= 1;
if( b ) crc ^= CRC_POLY;
}
for( int n = 0; n < 8; n++ )
{
in[i++] = (crc&(1<<n))? 1 : 0;
}
return 8;// Length of CRC
}
//
// Formatted into a binary array
//
void DVB2::add_bbheader( void )
{
int temp;
BBHeader *h = &m_format[0].bb_header;
m_frame[0] = h->ts_gs>>1;
m_frame[1] = h->ts_gs&1;
m_frame[2] = h->sis_mis;
m_frame[3] = h->ccm_acm;
m_frame[4] = h->issyi&1;
m_frame[5] = h->npd&1;
m_frame[6] = h->ro>>1;
m_frame[7] = h->ro&1;
m_frame_offset_bits = 8;
if( h->sis_mis == SIS_MIS_MULTIPLE )
{
temp = h->isi;
for( int n = 7; n >= 0; n-- )
{
m_frame[m_frame_offset_bits++] = temp&(1<<n)? 1 : 0;
}
}
else
{
for( int n = 7; n >= 0 ; n-- )
{
m_frame[m_frame_offset_bits++] = 0;
}
}
temp = h->upl;
for( int n = 15; n >= 0; n-- )
{
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
}
temp = h->dfl;
for( int n = 15; n >= 0; n-- )
{
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
}
temp = h->sync;
for( int n = 7; n >= 0; n-- )
{
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
}
// Calculate syncd, this should point to the MSB of the CRC
temp = m_tp_q.size();
if( temp == 0 )
temp = 187*8;
else
temp = (temp-1)*8;
//temp = h->syncd;// Syncd
for( int n = 15; n >= 0; n-- )
{
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
}
// Add CRC to BB header, at end
int len = BB_HEADER_LENGTH_BITS;
m_frame_offset_bits += add_crc8_bits( m_frame, len );
}
void DVB2::unpack_transport_packet_add_crc( u8 *ts )
{
// CRC is added in place of sync byte at end of packet
// skip the header 0x47
u8 crc = calc_crc8( &ts[1], 188-1 );
// Add the transport packet to the transport queue
for( int i = 1; i < 188; i++ ) m_tp_q.push( ts[i] );
// Add the crc
m_tp_q.push(crc);
// now pull off the transport queue and fill the frame
while((m_tp_q.size()!= 0)&&(m_frame_offset_bits!=m_format[0].kbch))
{
// Add to the frame bit array
u8 b = m_tp_q.front();
m_tp_q.pop();
for( int n = 7; n >= 0; n-- )
{
m_frame[m_frame_offset_bits++] = b&(1<<n)? 1 : 0;
}
}
}

View File

@ -0,0 +1,408 @@
// polymult.cpp : Defines the entry point for the console application.
//
#include "stdio.h"
#include "stdlib.h"
#include "memory.h"
#include "DVBS2.h"
//
// Display routines.
//
void display_poly( int *in, int len )
{
loggerf("\n");
for( int i = 0; i < len; i++ )
{
if(in[i] == 1 )
{
if( i == 0 )
loggerf("1");
else
if( i == 1 )
loggerf("+x");
else
loggerf("+x^%d",i);
}
}
loggerf("\n");
}
//
// length is in bits
//
void display_poly_pack( unsigned int *in, int len )
{
(void) in;
// loggerf("\n");
for( int i = 0; i < len/32; i++ )
{
// loggerf("%.8X",in[i]);
}
switch((len%32)/8)
{
case 0:
break;
case 1:
// loggerf("%.2X",in[(len/32)]>>24);
break;
case 2:
// loggerf("%.2X",in[(len/32)]>>24);
// loggerf("%.2X",in[(len/32)]>>16);
break;
case 3:
// loggerf("%.2X",in[(len/32)]>>24);
// loggerf("%.2X",in[(len/32)]>>16);
// loggerf("%.2X",in[(len/32)]>>8);
break;
}
// loggerf("\n");
}
//
// Polynomial calculation routines
//
// multiply polynomials
//
int DVB2::poly_mult( const int *ina, int lena, const int *inb, int lenb, int *out )
{
memset( out, 0, sizeof(int)*(lena+lenb));
for( int i = 0; i < lena; i++ )
{
for( int j = 0; j < lenb; j++ )
{
if( ina[i]*inb[j] > 0 ) out[i+j]++;// count number of terms for this pwr of x
}
}
int max=0;
for( int i = 0; i < lena+lenb; i++ )
{
out[i] = out[i]&1;// If even ignore the term
if(out[i]) max = i;
}
// return the size of array to house the result.
return max+1;
}
//
// Pack the polynomial into a 32 bit array
//
void DVB2::poly_pack( const int *pin, u32* pout, int len )
{
int lw = len/32;
int ptr = 0;
u32 temp;
if( len % 32 ) lw++;
for( int i = 0; i < lw; i++ )
{
temp = 0x80000000;
pout[i] = 0;
for( int j = 0; j < 32; j++ )
{
if( pin[ptr++] ) pout[i] |= temp;
temp >>= 1;
}
}
}
void DVB2::poly_reverse( int *pin, int *pout, int len )
{
int c;
c = len-1;
for( int i = 0; i < len; i++ )
{
pout[c--] = pin[i];
}
}
//
// Shift a 128 bit register
//
void inline DVB2::reg_4_shift( u32 *sr )
{
sr[3] = (sr[3]>>1) | (sr[2]<<31);
sr[2] = (sr[2]>>1) | (sr[1]<<31);
sr[1] = (sr[1]>>1) | (sr[0]<<31);
sr[0] = (sr[0]>>1);
}
//
// Shift 160 bits
//
void inline DVB2::reg_5_shift( u32 *sr )
{
sr[4] = (sr[4]>>1) | (sr[3]<<31);
sr[3] = (sr[3]>>1) | (sr[2]<<31);
sr[2] = (sr[2]>>1) | (sr[1]<<31);
sr[1] = (sr[1]>>1) | (sr[0]<<31);
sr[0] = (sr[0]>>1);
}
//
// Shift 192 bits
//
void inline DVB2::reg_6_shift( u32 *sr )
{
sr[5] = (sr[5]>>1) | (sr[4]<<31);
sr[4] = (sr[4]>>1) | (sr[3]<<31);
sr[3] = (sr[3]>>1) | (sr[2]<<31);
sr[2] = (sr[2]>>1) | (sr[1]<<31);
sr[1] = (sr[1]>>1) | (sr[0]<<31);
sr[0] = (sr[0]>>1);
}
//
// Take an bit array, bch encode it and place the result in a bit array
// The input length is in bits.
//
Bit DVB2::bch_n_8_encode( Bit *in, int len )
{
Bit b;
int i;
u32 shift[4];
//Zero the shift register
memset( shift,0,sizeof(u32)*4);
for( i = 0; i < len; i++ )
{
b = in[i]^(shift[3]&1);
reg_4_shift( shift );
if( b )
{
shift[0] ^= m_poly_n_8[0];
shift[1] ^= m_poly_n_8[1];
shift[2] ^= m_poly_n_8[2];
shift[3] ^= m_poly_n_8[3];
}
}
// Now add the parity bits to the output
for( int n = 0; n < 128; n++ )
{
in[i++] = shift[3]&1;
reg_4_shift( shift );
}
return i;
}
Bit DVB2::bch_n_10_encode( Bit *in,int len )
{
Bit b;
int i;
u32 shift[5];
//Zero the shift register
memset( shift,0,sizeof(u32)*5);
for( i = 0; i < len; i++ )
{
b = in[i]^(shift[4]&1);
reg_5_shift( shift );
if(b)
{
shift[0] ^= m_poly_n_10[0];
shift[1] ^= m_poly_n_10[1];
shift[2] ^= m_poly_n_10[2];
shift[3] ^= m_poly_n_10[3];
shift[4] ^= m_poly_n_10[4];
}
}
// Now add the parity bits to the output
for( int n = 0; n < 160; n++ )
{
in[i++] = shift[4]&1;
reg_5_shift( shift );
}
return i;
}
Bit DVB2::bch_n_12_encode( Bit *in, int len )
{
Bit b;
int i;
u32 shift[6];
//Zero the shift register
memset( shift,0,sizeof(u32)*6);
// MSB of the codeword first
for( i = 0; i < len; i++ )
{
b = in[i] ^ (shift[5]&1);
reg_6_shift( shift );
if(b)
{
shift[0] ^= m_poly_n_12[0];
shift[1] ^= m_poly_n_12[1];
shift[2] ^= m_poly_n_12[2];
shift[3] ^= m_poly_n_12[3];
shift[4] ^= m_poly_n_12[4];
shift[5] ^= m_poly_n_12[5];
}
}
// Now add the parity bits to the output
for( int n = 0; n < 192; n++ )
{
in[i++] = shift[5]&1;
reg_6_shift( shift );
}
return i;
}
Bit DVB2::bch_s_12_encode( Bit *in, int len )
{
Bit b;
int i;
u32 shift[6];
//Zero the shift register
memset( shift,0,sizeof(u32)*6);
for( i = 0; i < len; i++ )
{
b = (in[i] ^ ((shift[5]&0x01000000)?1:0));
reg_6_shift( shift );
if(b)
{
shift[0] ^= m_poly_s_12[0];
shift[1] ^= m_poly_s_12[1];
shift[2] ^= m_poly_s_12[2];
shift[3] ^= m_poly_s_12[3];
shift[4] ^= m_poly_s_12[4];
shift[5] ^= m_poly_s_12[5];
}
}
// Now add the parity bits to the output
for( int n = 0; n < 168; n++ )
{
in[i++] = (shift[5]&0x01000000) ? 1:0;
reg_6_shift( shift );
}
return i;
}
int DVB2::bch_encode( void )
{
int res;
int len = m_format[0].kbch;
switch(m_format[0].bch_code)
{
case BCH_CODE_N8:
res = bch_n_8_encode( m_frame, len );
break;
case BCH_CODE_N10:
res = bch_n_10_encode( m_frame, len );
break;
case BCH_CODE_N12:
res = bch_n_12_encode( m_frame, len );
break;
case BCH_CODE_S12:
res = bch_s_12_encode( m_frame, len );
break;
default:
printf("BCH error situation\n");
res = 0;
break;
}
return res;
}
//
//
//
void DVB2::bch_poly_build_tables( void )
{
// Normal polynomials
const int polyn01[]={1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,1};
const int polyn02[]={1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,0,1};
const int polyn03[]={1,0,1,1,1,1,0,1,1,1,1,1,0,0,0,0,1};
const int polyn04[]={1,0,1,0,1,0,1,0,0,1,0,1,1,0,1,0,1};
const int polyn05[]={1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,1};
const int polyn06[]={1,0,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1};
const int polyn07[]={1,0,1,0,0,1,1,0,1,1,1,1,0,1,0,1,1};
const int polyn08[]={1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,0,1};
const int polyn09[]={1,0,0,0,0,1,0,1,0,1,1,1,0,0,0,0,1};
const int polyn10[]={1,1,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1};
const int polyn11[]={1,0,1,1,0,1,0,0,0,1,0,1,1,1,0,0,1};
const int polyn12[]={1,1,0,0,0,1,1,1,0,1,0,1,1,0,0,0,1};
// Short polynomials
const int polys01[]={1,1,0,1,0,1,0,0,0,0,0,0,0,0,1};
const int polys02[]={1,0,0,0,0,0,1,0,1,0,0,1,0,0,1};
const int polys03[]={1,1,1,0,0,0,1,0,0,1,1,0,0,0,1};
const int polys04[]={1,0,0,0,1,0,0,1,1,0,1,0,1,0,1};
const int polys05[]={1,0,1,0,1,0,1,0,1,1,0,1,0,1,1};
const int polys06[]={1,0,0,1,0,0,0,1,1,1,0,0,0,1,1};
const int polys07[]={1,0,1,0,0,1,1,1,0,0,1,1,0,1,1};
const int polys08[]={1,0,0,0,0,1,0,0,1,1,1,1,0,0,1};
const int polys09[]={1,1,1,1,0,0,0,0,0,1,1,0,0,0,1};
const int polys10[]={1,0,0,1,0,0,1,0,0,1,0,1,1,0,1};
const int polys11[]={1,0,0,0,1,0,0,0,0,0,0,1,1,0,1};
const int polys12[]={1,1,1,1,0,1,1,1,1,0,1,0,0,1,1};
int len;
int polyout[3][2000];
len = poly_mult( polyn01, 17, polyn02, 17, polyout[0] );
len = poly_mult( polyn03, 17, polyout[0], len, polyout[1] );
len = poly_mult( polyn04, 17, polyout[1], len, polyout[0] );
len = poly_mult( polyn05, 17, polyout[0], len, polyout[1] );
len = poly_mult( polyn06, 17, polyout[1], len, polyout[0] );
len = poly_mult( polyn07, 17, polyout[0], len, polyout[1] );
len = poly_mult( polyn08, 17, polyout[1], len, polyout[0] );
poly_pack( polyout[0], m_poly_n_8, 128 );
// display_poly_pack( m_poly_n_8, 128);
len = poly_mult( polyn09, 17, polyout[0], len, polyout[1] );
len = poly_mult( polyn10, 17, polyout[1], len, polyout[0] );
poly_pack( polyout[0], m_poly_n_10, 160 );
// display_poly_pack( m_poly_n_10, 160);
len = poly_mult( polyn11, 17, polyout[0], len, polyout[1] );
len = poly_mult( polyn12, 17, polyout[1], len, polyout[0] );
poly_pack( polyout[0], m_poly_n_12, 192 );
// display_poly_pack( m_poly_n_12, 192);
// display_poly( polyout[0], len );//12
len = poly_mult( polys01, 15, polys02, 15, polyout[0] );
len = poly_mult( polys03, 15, polyout[0], len, polyout[1] );
len = poly_mult( polys04, 15, polyout[1], len, polyout[0] );
len = poly_mult( polys05, 15, polyout[0], len, polyout[1] );
len = poly_mult( polys06, 15, polyout[1], len, polyout[0] );
len = poly_mult( polys07, 15, polyout[0], len, polyout[1] );
len = poly_mult( polys08, 15, polyout[1], len, polyout[0] );
len = poly_mult( polys09, 15, polyout[0], len, polyout[1] );
len = poly_mult( polys10, 15, polyout[1], len, polyout[0] );
len = poly_mult( polys11, 15, polyout[0], len, polyout[1] );
len = poly_mult( polys12, 15, polyout[1], len, polyout[0] );
poly_pack( polyout[0], m_poly_s_12, 168 );
// display_poly_pack( m_poly_s_12, 168);
/*
// test
int pt1[] = {1,1};
int pt2[] = {1,1,1};
int pt3[] = {1,0,1,1,1,1};
len = poly_mult( pt1, 2, pt2, 3, polyout[0] );
len = poly_mult( pt3, 6, polyout[0], len, polyout[1] );
display_poly( polyout[1], len );
poly_pack( polyout[1], m_poly_s_12, len );
display_poly_pack( m_poly_s_12, 8 );
u32 shift[6];
shift[0] = 0x80000000;
shift[1] = 0x00000000;
shift[2] = 0x00000000;
shift[3] = 0x00000000;
shift[4] = 0x00000000;
shift[5] = 0x00000000;
for( int i = 0; i < 192; i++ )
{
display_poly_pack( shift, 192 );
reg_6_shift( shift );
}
// display_poly( polyout[0], len );//12
// display_poly_pack( m_poly_s_12, 168 );// Wont work because of shift register length
*/
}

View File

@ -0,0 +1,157 @@
#include "memory.h"
#include "DVB2.h"
/*
for( int row = 0; row < rows; row++ )
{
for( int n = 0; n < 360; n++ )
{
for( int col = 1; col <= table_name[row][0]; col++ )
{
// parity bit location, position from start of block
m_ldpc_encode.p[index] = m_format.kldpc + (table_name[row][col] + (n*m_format.q_val))%pbits;
// data bit to be accumulated
m_ldpc_encode.d[index] = im;
index++;
}
im++;
}
}
*/
#define LDPC_BF( TABLE_NAME, ROWS ) \
for( int row = 0; row < ROWS; row++ ) \
{ \
for( int n = 0; n < 360; n++ ) \
{ \
for( int col = 1; col <= TABLE_NAME[row][0]; col++ ) \
{ \
m_ldpc_encode.p[index] = (TABLE_NAME[row][col] + (n*q))%pbits; \
m_ldpc_encode.d[index] = im; \
index++; \
} \
im++; \
} \
}
/*
//
// Generate the lookup tables for the ldpc mode
//
void DVBS2::ldpc_lookup_generate( void )
{
int im;
int index;
int pbits;
int uc;
int rows;
index = 0;
im = 0;
if(m_format.frame_type == FRAME_NORMAL)
{
if(m_format.code_rate == CR_2_3)
{
uc = m_format.kldpc;
pbits = m_format.nldpc - m_format.kldpc; //number of parity bits
rows = 120;
for( int row = 0; row < rows; row++ )// for each row
{
for( int n = 0; n < 360; n++ )
{
for( int col = 1; col <= ldpc_tab_2_3N[row][0]; col++ )
{
// parity bit location, position from start of block
m_ldpc_encode.p[index] = m_format.kldpc + (ldpc_tab_2_3N[row][col] + (n*m_format.q_val))%pbits;
// data bit to be accumulated
m_ldpc_encode.d[index] = im;
index++;
}
im++;
}
}
}
}
m_ldpc_encode.length = index;
}
*/
void DVB2::ldpc_lookup_generate( void )
{
int im;
int index;
int pbits;
int q;
index = 0;
im = 0;
pbits = m_format[0].nldpc - m_format[0].kldpc; //number of parity bits
q = m_format[0].q_val;
if(m_format[0].frame_type == FRAME_NORMAL)
{
if( m_format[0].code_rate == CR_1_4 ) LDPC_BF( ldpc_tab_1_4N, 45 );
if( m_format[0].code_rate == CR_1_3 ) LDPC_BF( ldpc_tab_1_3N, 60 );
if( m_format[0].code_rate == CR_2_5 ) LDPC_BF( ldpc_tab_2_5N, 72 );
if( m_format[0].code_rate == CR_1_2 ) LDPC_BF( ldpc_tab_1_2N, 90 );
if( m_format[0].code_rate == CR_3_5 ) LDPC_BF( ldpc_tab_3_5N, 108 );
if( m_format[0].code_rate == CR_2_3 ) LDPC_BF( ldpc_tab_2_3N, 120 );
if( m_format[0].code_rate == CR_3_4 ) LDPC_BF( ldpc_tab_3_4N, 135 );
if( m_format[0].code_rate == CR_4_5 ) LDPC_BF( ldpc_tab_4_5N, 144 );
if( m_format[0].code_rate == CR_5_6 ) LDPC_BF( ldpc_tab_5_6N, 150 );
if( m_format[0].code_rate == CR_8_9 ) LDPC_BF( ldpc_tab_8_9N, 160 );
if( m_format[0].code_rate == CR_9_10) LDPC_BF( ldpc_tab_9_10N, 162 );
}
if(m_format[0].frame_type == FRAME_SHORT)
{
if( m_format[0].code_rate == CR_1_4 ) LDPC_BF( ldpc_tab_1_4S, 9 );
if( m_format[0].code_rate == CR_1_3 ) LDPC_BF( ldpc_tab_1_3S, 15 );
if( m_format[0].code_rate == CR_2_5 ) LDPC_BF( ldpc_tab_2_5S, 18 );
if( m_format[0].code_rate == CR_1_2 ) LDPC_BF( ldpc_tab_1_2S, 20 );
if( m_format[0].code_rate == CR_3_5 ) LDPC_BF( ldpc_tab_3_5S, 27 );
if( m_format[0].code_rate == CR_2_3 ) LDPC_BF( ldpc_tab_2_3S, 30 );
if( m_format[0].code_rate == CR_3_4 ) LDPC_BF( ldpc_tab_3_4S, 33 );
if( m_format[0].code_rate == CR_4_5 ) LDPC_BF( ldpc_tab_4_5S, 35 );
if( m_format[0].code_rate == CR_5_6 ) LDPC_BF( ldpc_tab_5_6S, 37 );
if( m_format[0].code_rate == CR_8_9 ) LDPC_BF( ldpc_tab_8_9S, 40 );
}
m_ldpc_encode.table_length = index;
}
void DVB2::ldpc_encode( void )
{
Bit *d,*p;
// Calculate the number of parity bits
int plen = m_format[0].nldpc - m_format[0].kldpc;
d = m_frame;
p = &m_frame[m_format[0].kldpc];
// First zero all the parity bits
memset( p, 0, sizeof(Bit)*plen);
// now do the parity checking
for( int i = 0; i < m_ldpc_encode.table_length; i++ )
{
p[m_ldpc_encode.p[i]] ^= d[m_ldpc_encode.d[i]];
}
for (int i = 1; i < plen; i++)
{
p[i] ^= p[i - 1];
}
}
void DVB2::ldpc_encode_test( void )
{
if(1)// m_format.code_rate == CR_1_2 )
{
printf("\n\nEncode length %d\n",m_ldpc_encode.table_length);
printf("Parity start %d\n",m_format[0].kldpc);
for( int i = 0; i < m_ldpc_encode.table_length; i++ )
{
if(m_ldpc_encode.d[i] == 0 )
{
printf("%d+%d\n",m_ldpc_encode.p[i],m_ldpc_encode.d[i]);
}
}
printf("Encode test end\n\n");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
#include "DVB2.h"
void DVB2::init_bb_randomiser(void)
{
int sr = 0x4A80;
for( int i = 0; i < FRAME_SIZE_NORMAL; i++ )
{
int b = ((sr)^(sr>>1))&1;
m_bb_randomise[i] = b;
sr >>= 1;
if( b ) sr |= 0x4000;
}
}
//
// Randomise the data bits
//
void DVB2::bb_randomise(void)
{
for( int i = 0; i < m_format[0].kbch; i++ )
{
m_frame[i] ^= m_bb_randomise[i];
}
}

View File

@ -0,0 +1,89 @@
#include "memory.h"
#include "DVBS2.h"
//
// The output is bit packed ready for modulating
//
void DVBS2::s2_interleave( void )
{
int index=0;
int rows=0;
int frame_size = m_format[0].nldpc;
if( m_format[0].constellation == M_QPSK )
{
rows = frame_size/2;
m_payload_symbols = rows;
for( int i = 0; i < rows; i++ )
{
m_iframe[i] = (m_frame[index++]<<1);
m_iframe[i] |= m_frame[index++];
}
return;
}
if( m_format[0].constellation == M_8PSK )
{
if( m_format[0].code_rate == CR_3_5 )
{
rows = frame_size/3;
m_payload_symbols = rows;
Bit *c1,*c2,*c3;
c1 = &m_frame[rows*2];
c2 = &m_frame[rows];
c3 = &m_frame[0];
for( int i = 0; i < rows; i++ )
{
m_iframe[i] = (c1[i]<<2) | (c2[i]<<1) | (c3[i]);
}
}
else
{
rows = frame_size/3;
m_payload_symbols = rows;
Bit *c1,*c2,*c3;
c1 = &m_frame[0];
c2 = &m_frame[rows];
c3 = &m_frame[rows*2];
for( int i = 0; i < rows; i++ )
{
m_iframe[i] = (c1[i]<<2) | (c2[i]<<1) | (c3[i]);
}
}
return;
}
if( m_format[0].constellation == M_16APSK )
{
rows = frame_size/4;
m_payload_symbols = rows;
Bit *c1,*c2,*c3,*c4;
c1 = &m_frame[0];
c2 = &m_frame[rows];
c3 = &m_frame[rows*2];
c4 = &m_frame[rows*3];
for( int i = 0; i < rows; i++ )
{
m_iframe[i] = (c1[i]<<3) | (c2[i]<<2) | (c3[i]<<1) | (c4[i]);
}
return;
}
if( m_format[0].constellation == M_32APSK )
{
rows = frame_size/5;
m_payload_symbols = rows;
Bit *c1,*c2,*c3,*c4,*c5;
c1 = &m_frame[0];
c2 = &m_frame[rows];
c3 = &m_frame[rows*2];
c4 = &m_frame[rows*3];
c5 = &m_frame[rows*4];
for( int i = 0; i < rows; i++ )
{
m_iframe[i] = (c1[i]<<4) | (c2[i]<<3) | (c3[i]<<2) | (c4[i]<<1) | c5[i];
}
return;
}
}

View File

@ -0,0 +1,209 @@
#include "math.h"
#include "DVBS2.h"
#define CP 0x7FFF
void DVBS2::modulator_configuration()
{
double r0,r1,r2,r3;
double m = 1.0;
if (m_format[0].constellation == M_32APSK)
r0 = 0.9*m;// I am not sure why this needs to be 0.9 but 32APSK does not work if == 1.0
else
r0 = 1.0*m;// Don't use 0.9 for other mods, as that results in worse MER
r1 = m;
// BPSK
m_bpsk[0][0].re = (short)((r0*cos(1*M_PI/4.0))*CP);
m_bpsk[0][0].im = (short)((r0*sin(1*M_PI/4.0))*CP);
m_bpsk[0][1].re = (short)((r0*cos(5*M_PI/4.0))*CP);
m_bpsk[0][1].im = (short)((r0*sin(5*M_PI/4.0))*CP);
m_bpsk[1][0].re = (short)((r0*cos(3*M_PI/4.0))*CP);
m_bpsk[1][0].im = (short)((r0*sin(3*M_PI/4.0))*CP);
m_bpsk[1][1].re = (short)((r0*cos(7*M_PI/4.0))*CP);
m_bpsk[1][1].im = (short)((r0*sin(7*M_PI/4.0))*CP);
// QPSK
m_qpsk[0].re = (short)((r1*cos(M_PI/4.0))*CP);
m_qpsk[0].im = (short)((r1*sin(M_PI/4.0))*CP);
m_qpsk[1].re = (short)((r1*cos(7*M_PI/4.0))*CP);
m_qpsk[1].im = (short)((r1*sin(7*M_PI/4.0))*CP);
m_qpsk[2].re = (short)((r1*cos(3*M_PI/4.0))*CP);
m_qpsk[2].im = (short)((r1*sin(3*M_PI/4.0))*CP);
m_qpsk[3].re = (short)((r1*cos(5*M_PI/4.0))*CP);
m_qpsk[3].im = (short)((r1*sin(5*M_PI/4.0))*CP);
// 8PSK
m_8psk[0].re = (short)((r1*cos(M_PI/4.0))*CP);
m_8psk[0].im = (short)((r1*sin(M_PI/4.0))*CP);
m_8psk[1].re = (short)((r1*cos(0.0))*CP);
m_8psk[1].im = (short)((r1*sin(0.0))*CP);
m_8psk[2].re = (short)((r1*cos(4*M_PI/4.0))*CP);
m_8psk[2].im = (short)((r1*sin(4*M_PI/4.0))*CP);
m_8psk[3].re = (short)((r1*cos(5*M_PI/4.0))*CP);
m_8psk[3].im = (short)((r1*sin(5*M_PI/4.0))*CP);
m_8psk[4].re = (short)((r1*cos(2*M_PI/4.0))*CP);
m_8psk[4].im = (short)((r1*sin(2*M_PI/4.0))*CP);
m_8psk[5].re = (short)((r1*cos(7*M_PI/4.0))*CP);
m_8psk[5].im = (short)((r1*sin(7*M_PI/4.0))*CP);
m_8psk[6].re = (short)((r1*cos(3*M_PI/4.0))*CP);
m_8psk[6].im = (short)((r1*sin(3*M_PI/4.0))*CP);
m_8psk[7].re = (short)((r1*cos(6*M_PI/4.0))*CP);
m_8psk[7].im = (short)((r1*sin(6*M_PI/4.0))*CP);
// 16 APSK
r2 = m;
switch( m_format[0].code_rate )
{
case CR_2_3:
r1 = r2/3.15;
break;
case CR_3_4:
r1 = r2/2.85;
break;
case CR_4_5:
r1 = r2/2.75;
break;
case CR_5_6:
r1 = r2/2.70;
break;
case CR_8_9:
r1 = r2/2.60;
break;
case CR_9_10:
r1 = r2/2.57;
break;
default:
// Illegal
r1 = 0;
break;
}
m_16apsk[0].re = (short)((r2*cos(M_PI/4.0))*CP);
m_16apsk[0].im = (short)((r2*sin(M_PI/4.0))*CP);
m_16apsk[1].re = (short)((r2*cos(-M_PI/4.0))*CP);
m_16apsk[1].im = (short)((r2*sin(-M_PI/4.0))*CP);
m_16apsk[2].re = (short)((r2*cos(3*M_PI/4.0))*CP);
m_16apsk[2].im = (short)((r2*sin(3*M_PI/4.0))*CP);
m_16apsk[3].re = (short)((r2*cos(-3*M_PI/4.0))*CP);
m_16apsk[3].im = (short)((r2*sin(-3*M_PI/4.0))*CP);
m_16apsk[4].re = (short)((r2*cos(M_PI/12.0))*CP);
m_16apsk[4].im = (short)((r2*sin(M_PI/12.0))*CP);
m_16apsk[5].re = (short)((r2*cos(-M_PI/12.0))*CP);
m_16apsk[5].im = (short)((r2*sin(-M_PI/12.0))*CP);
m_16apsk[6].re = (short)((r2*cos(11*M_PI/12.0))*CP);
m_16apsk[6].im = (short)((r2*sin(11*M_PI/12.0))*CP);
m_16apsk[7].re = (short)((r2*cos(-11*M_PI/12.0))*CP);
m_16apsk[7].im = (short)((r2*sin(-11*M_PI/12.0))*CP);
m_16apsk[8].re = (short)((r2*cos(5*M_PI/12.0))*CP);
m_16apsk[8].im = (short)((r2*sin(5*M_PI/12.0))*CP);
m_16apsk[9].re = (short)((r2*cos(-5*M_PI/12.0))*CP);
m_16apsk[9].im = (short)((r2*sin(-5*M_PI/12.0))*CP);
m_16apsk[10].re = (short)((r2*cos(7*M_PI/12.0))*CP);
m_16apsk[10].im = (short)((r2*sin(7*M_PI/12.0))*CP);
m_16apsk[11].re = (short)((r2*cos(-7*M_PI/12.0))*CP);
m_16apsk[11].im = (short)((r2*sin(-7*M_PI/12.0))*CP);
m_16apsk[12].re = (short)((r1*cos(M_PI/4.0))*CP);
m_16apsk[12].im = (short)((r1*sin(M_PI/4.0))*CP);
m_16apsk[13].re = (short)((r1*cos(-M_PI/4.0))*CP);
m_16apsk[13].im = (short)((r1*sin(-M_PI/4.0))*CP);
m_16apsk[14].re = (short)((r1*cos(3*M_PI/4.0))*CP);
m_16apsk[14].im = (short)((r1*sin(3*M_PI/4.0))*CP);
m_16apsk[15].re = (short)((r1*cos(-3*M_PI/4.0))*CP);
m_16apsk[15].im = (short)((r1*sin(-3*M_PI/4.0))*CP);
// 32 APSK
r3 = m;
switch( m_format[0].code_rate )
{
case CR_3_4:
r1 = r3/5.27;
r2 = r1*2.84;
break;
case CR_4_5:
r1 = r3/4.87;
r2 = r1*2.72;
break;
case CR_5_6:
r1 = r3/4.64;
r2 = r1*2.64;
break;
case CR_8_9:
r1 = r3/4.33;
r2 = r1*2.54;
break;
case CR_9_10:
r1 = r3/4.30;
r2 = r1*2.53;
break;
default:
// Illegal
r1 = 0;
r2 = 0;
break;
}
m_32apsk[0].re = (short)((r2*cos(M_PI/4.0))*CP);
m_32apsk[0].im = (short)((r2*sin(M_PI/4.0))*CP);
m_32apsk[1].re = (short)((r2*cos(5*M_PI/12.0))*CP);
m_32apsk[1].im = (short)((r2*sin(5*M_PI/12.0))*CP);
m_32apsk[2].re = (short)((r2*cos(-M_PI/4.0))*CP);
m_32apsk[2].im = (short)((r2*sin(-M_PI/4.0))*CP);
m_32apsk[3].re = (short)((r2*cos(-5*M_PI/12.0))*CP);
m_32apsk[3].im = (short)((r2*sin(-5*M_PI/12.0))*CP);
m_32apsk[4].re = (short)((r2*cos(3*M_PI/4.0))*CP);
m_32apsk[4].im = (short)((r2*sin(3*M_PI/4.0))*CP);
m_32apsk[5].re = (short)((r2*cos(7*M_PI/12.0))*CP);
m_32apsk[5].im = (short)((r2*sin(7*M_PI/12.0))*CP);
m_32apsk[6].re = (short)((r2*cos(-3*M_PI/4.0))*CP);
m_32apsk[6].im = (short)((r2*sin(-3*M_PI/4.0))*CP);
m_32apsk[7].re = (short)((r2*cos(-7*M_PI/12.0))*CP);
m_32apsk[7].im = (short)((r2*sin(-7*M_PI/12.0))*CP);
m_32apsk[8].re = (short)((r3*cos(M_PI/8.0))*CP);
m_32apsk[8].im = (short)((r3*sin(M_PI/8.0))*CP);
m_32apsk[9].re = (short)((r3*cos(3*M_PI/8.0))*CP);
m_32apsk[9].im = (short)((r3*sin(3*M_PI/8.0))*CP);
m_32apsk[10].re = (short)((r3*cos(-M_PI/4.0))*CP);
m_32apsk[10].im = (short)((r3*sin(-M_PI/4.0))*CP);
m_32apsk[11].re = (short)((r3*cos(-M_PI/2.0))*CP);
m_32apsk[11].im = (short)((r3*sin(-M_PI/2.0))*CP);
m_32apsk[12].re = (short)((r3*cos(3*M_PI/4.0))*CP);
m_32apsk[12].im = (short)((r3*sin(3*M_PI/4.0))*CP);
m_32apsk[13].re = (short)((r3*cos(M_PI/2.0))*CP);
m_32apsk[13].im = (short)((r3*sin(M_PI/2.0))*CP);
m_32apsk[14].re = (short)((r3*cos(-7*M_PI/8.0))*CP);
m_32apsk[14].im = (short)((r3*sin(-7*M_PI/8.0))*CP);
m_32apsk[15].re = (short)((r3*cos(-5*M_PI/8.0))*CP);
m_32apsk[15].im = (short)((r3*sin(-5*M_PI/8.0))*CP);
m_32apsk[16].re = (short)((r2*cos(M_PI/12.0))*CP);
m_32apsk[16].im = (short)((r2*sin(M_PI/12.0))*CP);
m_32apsk[17].re = (short)((r1*cos(M_PI/4.0))*CP);
m_32apsk[17].im = (short)((r1*sin(M_PI/4.0))*CP);
m_32apsk[18].re = (short)((r2*cos(-M_PI/12.0))*CP);
m_32apsk[18].im = (short)((r2*sin(-M_PI/12.0))*CP);
m_32apsk[19].re = (short)((r1*cos(-M_PI/4.0))*CP);
m_32apsk[19].im = (short)((r1*sin(-M_PI/4.0))*CP);
m_32apsk[20].re = (short)((r2*cos(11*M_PI/12.0))*CP);
m_32apsk[20].im = (short)((r2*sin(11*M_PI/12.0))*CP);
m_32apsk[21].re = (short)((r1*cos(3*M_PI/4.0))*CP);
m_32apsk[21].im = (short)((r1*sin(3*M_PI/4.0))*CP);
m_32apsk[22].re = (short)((r2*cos(-11*M_PI/12.0))*CP);
m_32apsk[22].im = (short)((r2*sin(-11*M_PI/12.0))*CP);
m_32apsk[23].re = (short)((r1*cos(-3*M_PI/4.0))*CP);
m_32apsk[23].im = (short)((r1*sin(-3*M_PI/4.0))*CP);
m_32apsk[24].re = (short)((r3*cos(0.0))*CP);
m_32apsk[24].im = (short)((r3*sin(0.0))*CP);
m_32apsk[25].re = (short)((r3*cos(M_PI/4.0))*CP);
m_32apsk[25].im = (short)((r3*sin(M_PI/4.0))*CP);
m_32apsk[26].re = (short)((r3*cos(-M_PI/8.0))*CP);
m_32apsk[26].im = (short)((r3*sin(-M_PI/8.0))*CP);
m_32apsk[27].re = (short)((r3*cos(-3*M_PI/8.0))*CP);
m_32apsk[27].im = (short)((r3*sin(-3*M_PI/8.0))*CP);
m_32apsk[28].re = (short)((r3*cos(7*M_PI/8.0))*CP);
m_32apsk[28].im = (short)((r3*sin(7*M_PI/8.0))*CP);
m_32apsk[29].re = (short)((r3*cos(5*M_PI/8.0))*CP);
m_32apsk[29].im = (short)((r3*sin(5*M_PI/8.0))*CP);
m_32apsk[30].re = (short)((r3*cos(M_PI))*CP);
m_32apsk[30].im = (short)((r3*sin(M_PI))*CP);
m_32apsk[31].re = (short)((r3*cos(-3*M_PI/4.0))*CP);
m_32apsk[31].im = (short)((r3*sin(-3*M_PI/4.0))*CP);
}

View File

@ -0,0 +1,332 @@
#include "DVBS2.h"
void DVBS2::b_64_7_code( unsigned char in, int *out )
{
unsigned long temp,bit;
temp = 0;
if(in&0x40) temp ^= g[0];
if(in&0x20) temp ^= g[1];
if(in&0x10) temp ^= g[2];
if(in&0x08) temp ^= g[3];
if(in&0x04) temp ^= g[4];
if(in&0x02) temp ^= g[5];
bit = 0x80000000;
for( int m = 0; m < 32; m++ )
{
out[(m*2)] = (temp&bit)?1:0;
out[(m*2)+1] = out[m*2]^(in&0x01);
bit >>= 1;
}
// Randomise it
for( int m = 0; m < 64; m++ )
{
out[m] = out[m] ^ ph_scram_tab[m];
}
}
//[MODCOD 6:2 ][TYPE 1:0 ]
void DVBS2::s2_pl_header_encode( u8 modcod, u8 type, int *out)
{
unsigned char code;
code = (modcod<<2) | type;
//printf("MODCOD %d TYPE %d %d\n",modcod,type,code);
// Add the modcod and type information and scramble it
b_64_7_code( code, out );
}
void DVBS2::s2_pl_header_create(void)
{
int type, modcod;
modcod = 0;
if( m_format[0].frame_type == FRAME_NORMAL )
type = 0;
else
type = 2;
if( m_format[0].pilots ) type |= 1;
// Mode and code rate
if( m_format[0].constellation == M_QPSK )
{
switch( m_format[0].code_rate )
{
case CR_1_4:
modcod = 1;
break;
case CR_1_3:
modcod = 2;
break;
case CR_2_5:
modcod = 3;
break;
case CR_1_2:
modcod = 4;
break;
case CR_3_5:
modcod = 5;
break;
case CR_2_3:
modcod = 6;
break;
case CR_3_4:
modcod = 7;
break;
case CR_4_5:
modcod = 8;
break;
case CR_5_6:
modcod = 9;
break;
case CR_8_9:
modcod = 10;
break;
case CR_9_10:
modcod = 11;
break;
default:
modcod = 0;
break;
}
}
if( m_format[0].constellation == M_8PSK )
{
switch( m_format[0].code_rate )
{
case CR_3_5:
modcod = 12;
break;
case CR_2_3:
modcod = 13;
break;
case CR_3_4:
modcod = 14;
break;
case CR_5_6:
modcod = 15;
break;
case CR_8_9:
modcod = 16;
break;
case CR_9_10:
modcod = 17;
break;
default:
modcod = 0;
break;
}
}
if( m_format[0].constellation == M_16APSK )
{
switch( m_format[0].code_rate )
{
case CR_2_3:
modcod = 18;
break;
case CR_3_4:
modcod = 19;
break;
case CR_4_5:
modcod = 20;
break;
case CR_5_6:
modcod = 21;
break;
case CR_8_9:
modcod = 22;
break;
case CR_9_10:
modcod = 23;
break;
default:
modcod = 0;
break;
}
}
if( m_format[0].constellation == M_32APSK )
{
switch( m_format[0].code_rate )
{
case CR_3_4:
modcod = 24;
break;
case CR_4_5:
modcod = 25;
break;
case CR_5_6:
modcod = 26;
break;
case CR_8_9:
modcod = 27;
break;
case CR_9_10:
modcod = 28;
break;
default:
modcod = 0;
break;
}
}
// Now create the PL header.
int b[90];
// Add the sync sequence SOF
for( int i = 0; i < 26; i++ ) b[i] = ph_sync_seq[i];
// Add the mode and code
s2_pl_header_encode( modcod, type, &b[26] );
// BPSK modulate and add the header
for( int i = 0; i < 90; i++ )
{
m_pl[i] = m_bpsk[i&1][b[i]];
}
}
//
// m_symbols is the total number of complex symbols in the frame
// Modulate the data starting at symbol 90
//
int DVBS2::s2_pl_data_pack( void )
{
int m = 0;
int n = 90;// Jump over header
int blocks = m_payload_symbols/90;
int block_count = 0;
// See if PSK
if( m_format[0].constellation == M_QPSK )
{
for( int i = 0; i < blocks; i++ )
{
for( int j = 0; j < 90; j++ )
{
m_pl[n++] = m_qpsk[m_iframe[m++]&0x3];
}
block_count = (block_count+1)%16;
if((block_count == 0)&&(i<blocks-1))
{
if( m_format[0].pilots )
{
// Add pilots if needed
for( int k = 0; k < 36; k++ )
{
m_pl[n++] = m_bpsk[0][0];
}
}
}
}
}
// See if 8 PSK
if( m_format[0].constellation == M_8PSK )
{
for( int i = 0; i < blocks; i++ )
{
for( int j = 0; j < 90; j++ )
{
m_pl[n++] = m_8psk[m_iframe[m++]&0x7];
}
block_count = (block_count+1)%16;
if((block_count == 0)&&(i<blocks-1))
{
if( m_format[0].pilots )
{
// Add pilots if needed
for( int k = 0; k < 36; k++ )
{
m_pl[n++] = m_bpsk[0][0];
}
}
}
}
}
// See if 16 PSK
if( m_format[0].constellation == M_16APSK )
{
for( int i = 0; i < blocks; i++ )
{
for( int j = 0; j < 90; j++ )
{
m_pl[n++] = m_16apsk[m_iframe[m++]&0xF];
}
block_count = (block_count+1)%16;
if((block_count == 0)&&(i<blocks-1))
{
if( m_format[0].pilots )
{
// Add pilots if needed
for( int k = 0; k < 36; k++ )
{
m_pl[n++] = m_bpsk[0][0];
}
}
}
}
}
// See if 32 APSK
if( m_format[0].constellation == M_32APSK )
{
for( int i = 0; i < blocks; i++ )
{
for( int j = 0; j < 90; j++ )
{
m_pl[n++] = m_32apsk[m_iframe[m++]&0x1F];
}
block_count = (block_count+1)%16;
if((block_count == 0)&&(i<blocks-1))
{
if( m_format[0].pilots )
{
// Add pilots if needed
for( int k = 0; k < 36; k++ )
{
m_pl[n++] = m_bpsk[0][0];
}
}
}
}
}
// Now apply the scrambler to the data part not the header
pl_scramble_symbols( &m_pl[90], n - 90 );
// Return the length
return n;
}
//
// This is not used for Broadcast mode
//
void DVBS2::pl_build_dummy( void )
{
int n = 0;
int b[90];
// Add the sync sequence SOF
for( int i = 0; i < 26; i++ ) b[i] = ph_sync_seq[i];
// Add the mode and code and sync sequence
s2_pl_header_encode( 0, 0, &b[26] );
// BPSK Modulate
for( int i = 0; i < 90; i++ )
{
m_pl[i].re = m_bpsk[i&1][b[i]].re;
m_pl[i].im = m_bpsk[i&1][b[i]].im;
}
n += (90*36);
pl_scramble_dummy_symbols( n );
m_dummy_frame_length = n;
}
scmplx * DVBS2::pl_get_frame( void )
{
return m_pl;
}
scmplx * DVBS2::pl_get_dummy( int &len )
{
scmplx * frame;
len = m_dummy_frame_length;
frame = m_pl_dummy;
return frame;
}

View File

@ -0,0 +1,110 @@
#include "DVBS2.h"
int DVBS2::parity_chk( long a, long b)
{
int c = 0;
a = a & b;
for( int i = 0; i < 18; i++ )
{
if( a&(1L<<i)) c++;
}
return c&1;
}
//
// This is not time sensitive and is only run at start up
//
void DVBS2::build_symbol_scrambler_table( void )
{
long x,y;
int xa,xb,xc,ya,yb,yc;
int rn,zna,znb;
// Initialisation
x = 0x00001;
y = 0x3FFFF;
for( int i = 0; i < FRAME_SIZE_NORMAL; i++ )
{
xa = parity_chk( x, 0x8050 );
xb = parity_chk( x, 0x0081 );
xc = x&1;
x >>= 1;
if( xb ) x |= 0x20000;
ya = parity_chk( y, 0x04A1 );
yb = parity_chk( y, 0xFF60 );
yc = y&1;
y >>= 1;
if( ya ) y |= 0x20000;
zna = xc ^ yc;
znb = xa ^ yb;
rn = (znb<<1) + zna;
m_cscram[i] = rn;
}
}
void DVBS2::pl_scramble_symbols( scmplx *fs, int len )
{
scmplx x;
// Start at the end of the PL Header.
for( int n = 0; n < len; n++ )
{
switch( m_cscram[n] )
{
case 0:
// Do nothing
break;
case 1:
x = fs[n];
fs[n].re = -x.im;
fs[n].im = x.re;
break;
case 2:
fs[n].re = -fs[n].re;
fs[n].im = -fs[n].im;
break;
case 03:
x = fs[n];
fs[n].re = x.im;
fs[n].im = -x.re;
break;
}
}
}
void DVBS2::pl_scramble_dummy_symbols( int len )
{
scmplx x;
int p = 0;
x = m_bpsk[0][0];
for( int n = 90; n < len; n++ )
{
switch( m_cscram[p] )
{
case 0:
// Do nothing
m_pl_dummy[n].re = x.re;
m_pl_dummy[n].im = x.im;
break;
case 1:
m_pl_dummy[n].re = -x.im;
m_pl_dummy[n].im = x.re;
break;
case 2:
m_pl_dummy[n].re = -x.re;
m_pl_dummy[n].im = -x.im;
break;
case 3:
m_pl_dummy[n].re = x.im;
m_pl_dummy[n].im = -x.re;
break;
}
p++;
}
}

View File

@ -0,0 +1,19 @@
#include "DVBS2.h"
//
// Modcod error correction
//
const unsigned long DVBS2::g[6]=
{
0x55555555,0x33333333,0x0F0F0F0F,0x00FF00FF,0x0000FFFF,0xFFFFFFFF
};
const int DVBS2::ph_scram_tab[64]=
{
0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,0,0,1,0,0,1,
0,1,0,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1,0
};
const int DVBS2::ph_sync_seq[26]=
{
0,1,1,0,0,0,1,1,0,1,0,0,1,0,1,1,1,0,1,0,0,0,0,0,1,0
};

View File

@ -0,0 +1 @@
This DVB-S2 code is from https://github.com/G4GUO/

View File

@ -2,7 +2,7 @@
<h2>Introduction</h2>
This plugin can be used to transmit a digital amateur TV signal in the DVB-S standard. The plugin requires the video and audio to be transmitted to be in an MPEG transport stream.
This plugin can be used to transmit a digital amateur TV signal in the DVB-S or DVB-S2 standards. The plugin requires the video and audio to be transmitted to be in an MPEG transport stream.
The MPEG transport stream can either be read from a file or streamed via UDP.
The MPEG transport stream must (for now) be created outside of SDRangel, using software such as ffmpeg. The MPEG transport stream can contain video compressed using codecs such as MPEG-2, h264 or h265 (HEVC).
@ -11,6 +11,8 @@ The DATV modulator plugin just performs channel coding and modulation of the tra
DVB-S includes: scrambling, Reed-Solomon RS(204,188,T=8) coding, convolutional interleaving (I=12), convolutional encoding (code rate=1/2, with optional puncturing to rates of 2/3, 3/4, 5/6 and 7/8) and BPSK or QPSK modulation.
DVB-S2 includes: scrambling, BCH encoder, LDPC encoder, bit interleaver and QPSK, 8PSK, 16APSK or 32APSK modulation.
<h2>Interface</h2>
![DATV Modulator plugin GUI](../../../doc/img/DATVMod_plugin.png)
@ -44,7 +46,7 @@ Use this button to toggle mute for this channel. The radio waves on the icon are
<h3>6: Standard</h3>
Select the DVB standard to use for channel coding and modulation. Currenty only DVB-S is supported.
Select the DVB standard to use for channel coding and modulation. This can be either DVB-S or DVB-S2.
<h3>7: Symbol rate</h3>
@ -67,15 +69,17 @@ When using UDP, the packet size should be an integer multiple of the MPEG transp
Forward error correction code rate. This controls the number of bits sent to help the receiver to correct errors.
A code rate of 1/2 has the highest overhead (corresponding to a lower data rate), but allows the most amount of errors to be correct.
7/8 has the least overhead (corresponding to higher data rates), but will allow the fewest amount of errors to be corrected.
7/8 (DVB-S) or 9/10 (DVB-S2) has the least overhead (corresponding to higher data rates), but will allow the fewest amount of errors to be corrected.
<h3>11: Modulation</h3>
Select the modulation to be used. This can either be BPSK or QPSK. BPSK transmits a single bit per symbol, whereas QPSK transmits two bits per symbol, so has twice the bitrate.
Select the modulation to be used. For DVB-S, this can either be BPSK or QPSK. For DVB-S2, this can be QPSK, 8PSK, 16APSK or 32PSK.
BPSK transmits a single bit per symbol, whereas QPSK transmits two bits per symbol, so has twice the bitrate. Similar, 8PSK is 3 bits per symbol, 16APSK 4 and 32PSK 5. BPSK, QPSK and 8PSK only modulate phase. 16APSK and 32APKS modulate both phase and amplitude.
<h3>12: Roll off</h3>
Roll-off for the root raised cosine filter. For DVB-S, this should be 0.35.
Roll-off for the root raised cosine filter. For DVB-S, this should be 0.35. For DVB-S2 this can be 0.2, 0.25 or 0.35.
<h3>13: UDP IP address</h3>
@ -121,11 +125,11 @@ This slider can be used to randomly set the current position in the file when fi
An MPEG transport stream file can be created from a video file using ffpmeg:
ffmpeg -i input.avi -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -y mpeg.ts
ffmpeg -i input.avi -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -y mpeg.ts
To stream from a video camera via UDP (on Windows):
ffmpeg -f dshow -i video="c922 Pro Stream Webcam":audio="Microphone (C922 Pro Stream Webcam)" -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -flush_packets 0 "udp://127.0.0.1:5004?pkt_size=1316&bitrate=600000"
ffmpeg -f dshow -i video="c922 Pro Stream Webcam":audio="Microphone (C922 Pro Stream Webcam)" -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -flush_packets 0 "udp://127.0.0.1:5004?pkt_size=1316&bitrate=600000"
You can list camera devices with: