/**************************************************************************** Copyright 2005,2006 Virginia Polytechnic Institute and State University This file is part of the OSSIE Signal Processing Library. OSSIE Signal Processing Library 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. OSSIE Signal Processing Library 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 OSSIE Signal Processing Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ****************************************************************************/ /**Converted to C by ismael.gomez at tsc.upc.edu */ #include #include #include #include "modem.h" void rotate(int I_in, int Q_in, float theta, int *I_out, int *Q_out); // // 0 1 // void ModulateASK( int symbol_in, int *I_out, int *Q_out) { *Q_out = 0; switch ( symbol_in ) { case 0: *I_out = 0; break; case 1: *I_out = ASK_LEVEL; break; default: Log("ERROR: Unknown symbol for BPSK: %d\n",symbol_in); return; } } // // 0 1 // void ModulateBPSK( int symbol_in, int *I_out, int *Q_out) { *Q_out = 0; switch ( symbol_in ) { case 0: *I_out = -BPSK_LEVEL; break; case 1: *I_out = BPSK_LEVEL; break; default: Log("ERROR: Unknown symbol for BPSK: %d\n",symbol_in); return; } } // // 10 // 11 00 // 01 // void ModulateQPSK( int symbol_in, int *I_out, int *Q_out) { switch ( symbol_in ) { case 0: *I_out = QPSK_LEVEL; *Q_out = 0; break; case 1: *I_out = 0; *Q_out = -QPSK_LEVEL; break; case 2: *I_out = 0; *Q_out = QPSK_LEVEL; break; case 3: *I_out = -QPSK_LEVEL; *Q_out = 0; break; default: Log("ERROR: Unknown symbol for QPSK: %d\n",symbol_in); return ; } } // // 10 00 // 11 01 // void ModulateQAM4( int symbol_in, int *I_out, int *Q_out) { switch ( symbol_in ) { case 0: *I_out = QAM4_LEVEL; *Q_out = QAM4_LEVEL; break; case 1: *I_out = QAM4_LEVEL; *Q_out = -QAM4_LEVEL; break; case 2: *I_out = -QAM4_LEVEL; *Q_out = QAM4_LEVEL; break; case 3: *I_out = -QAM4_LEVEL; *Q_out = -QAM4_LEVEL; break; default: Log("ERROR: Unknown symbol for QAM4: %d\n",symbol_in); return ; } } // // 101 // 100 001 // 110 000 // 111 010 // 011 // void Modulate8PSK( int symbol_in, int *I_out, int *Q_out) { switch ( symbol_in ) { case 0: *I_out = PSK8_LEVEL_2; *Q_out = 0; break; case 1: *I_out = PSK8_LEVEL_1; *Q_out = PSK8_LEVEL_1; break; case 2: *I_out = PSK8_LEVEL_1; *Q_out = -PSK8_LEVEL_1; break; case 3: *I_out = 0; *Q_out = -PSK8_LEVEL_2; break; case 4: *I_out = -PSK8_LEVEL_1; *Q_out = PSK8_LEVEL_1; break; case 5: *I_out = 0; *Q_out = PSK8_LEVEL_2; break; case 6: *I_out = -PSK8_LEVEL_2; *Q_out = 0; break; case 7: *I_out = -PSK8_LEVEL_1; *Q_out = -PSK8_LEVEL_1; break; default: Log("ERROR: Unknown symbol for PSK8: %d\n",symbol_in); return ; } } // // 0000 0100 1100 1000 // 0001 0101 1101 1001 // 0011 0111 1111 1011 // 0010 0110 1110 1010 // void Modulate16QAM( int symbol_in, int *I_out, int *Q_out) { switch ( symbol_in ) { case 0: *I_out = -QAM16_LEVEL_2; *Q_out = QAM16_LEVEL_2; break; case 1: *I_out = -QAM16_LEVEL_2; *Q_out = QAM16_LEVEL_1; break; case 2: *I_out = -QAM16_LEVEL_2; *Q_out = -QAM16_LEVEL_2; break; case 3: *I_out = -QAM16_LEVEL_2; *Q_out = -QAM16_LEVEL_1; break; case 4: *I_out = -QAM16_LEVEL_1; *Q_out = QAM16_LEVEL_2; break; case 5: *I_out = -QAM16_LEVEL_1; *Q_out = QAM16_LEVEL_1; break; case 6: *I_out = -QAM16_LEVEL_1; *Q_out = -QAM16_LEVEL_2; break; case 7: *I_out = -QAM16_LEVEL_1; *Q_out = -QAM16_LEVEL_1; break; case 8: *I_out = QAM16_LEVEL_2; *Q_out = QAM16_LEVEL_2; break; case 9: *I_out = QAM16_LEVEL_2; *Q_out = QAM16_LEVEL_1; break; case 10: *I_out = QAM16_LEVEL_2; *Q_out = -QAM16_LEVEL_2; break; case 11: *I_out = QAM16_LEVEL_2; *Q_out = -QAM16_LEVEL_1; break; case 12: *I_out = QAM16_LEVEL_1; *Q_out = QAM16_LEVEL_2; break; case 13: *I_out = QAM16_LEVEL_1; *Q_out = QAM16_LEVEL_1; break; case 14: *I_out = QAM16_LEVEL_1; *Q_out = -QAM16_LEVEL_2; break; case 15: *I_out = QAM16_LEVEL_1; *Q_out = -QAM16_LEVEL_1; break; default: Log("ERROR: Unknown symbol for QAM16: %d\n",symbol_in); return ; } } // // 10 11 01 00 // void Modulate4PAM( int symbol_in, int *I_out, int *Q_out) { *Q_out = 0; switch ( symbol_in ) { case 0: *I_out = PAM4_LEVEL_2; break; case 1: *I_out = PAM4_LEVEL_1; break; case 2: *I_out = -PAM4_LEVEL_2; break; case 3: *I_out = -PAM4_LEVEL_1; break; default: Log("ERROR: Unknown symbol for PAM4: %d\n",symbol_in); return ; } } // // 0 1 // void DemodulateASK( int I_in, int Q_in, int *symbol_out) { *symbol_out = ( I_in > ASK_LEVEL/2 ) ? 1 : 0; } // // 0 1 // void DemodulateBPSK( int I_in, int Q_in, int *symbol_out) { *symbol_out = ( I_in > 0 ) ? 1 : 0; } // // 10 00 // 11 01 // void DemodulateQAM4( int I_in, int Q_in, int *symbol_out) { unsigned int b0, b1; *symbol_out = 0; b0 = ( I_in > 0 ) ? 0 : 1; b1 = ( Q_in > 0 ) ? 0 : 1; *symbol_out = (b0 << 1) + b1; } // // 10 // 11 00 // 01 // void DemodulateQPSK( int I_in, int Q_in, int *symbol_out) { // rotate constellation counter-clockwise by 45 degrees // NOTE: pi/4 = 0.785398163397448 int I, Q; rotate(I_in, Q_in, 0.785398f, &I, &Q); DemodulateQAM4(I, Q, symbol_out); } // // 101 // 100 001 // 110 000 // 111 010 // 011 // void Demodulate8PSK( int I_in, int Q_in, int *symbol_out) { unsigned int b0, b1, b2; // rotate constellation counter-clockwise by 22.5 degrees // NOTE: pi/8 = 0.392699081698724 int I, Q; rotate(I_in, Q_in, 0.392699f, &I, &Q); b0 = ( I > 0 ) ? 0 : 1; b1 = ( Q > 0 ) ? 0 : 1; if ( ( Q>I && -I>Q ) || ( Q>-I && I>Q ) ) b2 = 0; else b2 = 1; *symbol_out = (b0 << 2) + (b1 << 1) + b2; } // // 0000 0100 1100 1000 // 0001 0101 1101 1001 // 0011 0111 1111 1011 // 0010 0110 1110 1010 // void Demodulate16QAM( int I_in, int Q_in, int *symbol_out) { unsigned int b0, b1, b2, b3; b0 = ( I_in > 0 ) ? 1 : 0; b1 = ( abs(I_in) > QAM16_THRESHOLD ) ? 0 : 1; b2 = ( Q_in > 0 ) ? 0 : 1; b3 = ( abs(Q_in) > QAM16_THRESHOLD ) ? 0 : 1; *symbol_out = (b0 << 3) + (b1 << 2) + (b2 << 1) + b3; } // // 10 11 01 00 // void Demodulate4PAM( int I_in, int Q_in, int *symbol_out) { unsigned int b0, b1; if ( I_in > 0 ) { b0 = 0; b1 = ( I_in > PAM4_THRESHOLD ) ? 0 : 1; } else { b0 = 1; b1 = ( I_in < -PAM4_THRESHOLD ) ? 0 : 1; } *symbol_out = (b0 << 1) + b1; } void rotate(int I_in, int Q_in, float theta, int *I_out, int *Q_out) { ///\todo: use CORDIC mixer to perform this operation more efficiently float c = cosf(theta); float s = sinf(theta); *I_out = (int) ( (float) (I_in*c) - (float) (Q_in*s) ); *Q_out = (int) ( (float) (I_in*s) + (float) (Q_in*c) ); } // Converts symbol to bit sequence void ConvertSymbolToBits(unsigned int s, char * bitsOut, int bitsPerSymbol) { unsigned int i; for (i=0; i>= 1; } } // Converts bit sequence to symbol void ConvertBitsToSymbol(char * bitsIn, unsigned int *s, int bitsPerSymbol) { unsigned int i; *s = 0; for (i=0; i 0) ? 1 : 0; } } int getbitspersymbol(int modulation) { switch(modulation) { case MOD_BPSK: return 1; case MOD_QPSK: return 2; case MOD_QAM4: return 2; case MOD_QAM16: return 4; case MOD_ASK: return 1; default: Log("Unknown modulation %d\n",modulation); return 0; } } void Modulate(int modulation, int symbol, int *I_out, int *Q_out) { switch(modulation) { case MOD_BPSK: ModulateBPSK(symbol,I_out,Q_out); break; case MOD_QPSK: ModulateQPSK(symbol,I_out,Q_out); break; case MOD_QAM4: ModulateQAM4(symbol,I_out,Q_out); break; case MOD_QAM16: Modulate16QAM(symbol,I_out,Q_out); break; case MOD_ASK: ModulateASK(symbol,I_out,Q_out); break; default: Log("Unknown modulation %d\n",modulation); break; } } void Demodulate(int modulation, int I_out, int Q_out, int *symbol) { switch(modulation) { case MOD_BPSK: DemodulateBPSK(I_out,Q_out,symbol); break; case MOD_QPSK: DemodulateQPSK(I_out,Q_out,symbol); break; case MOD_QAM4: DemodulateQAM4(I_out,Q_out,symbol); break; case MOD_QAM16: Demodulate16QAM(I_out,Q_out,symbol); break; case MOD_ASK: DemodulateASK(I_out,Q_out,symbol); break; default: Log("Unknown modulation %d\n",modulation); break; } }