Search code examples
javasignal-processingjfreechart

BPSK modulation in Java


I want to perform BPSK modulation and plot the modulated signal in Java. But I am unable to figure it out.

I have encoded the signal successfully but when I multiply carrier and base band signal and then plot it, I get an awkward signal.

For plotting purposes I am using the JFreeChart library. For plotting configurations I have made the following class:

public class XYLineChart_AWT extends ApplicationFrame 
{
public XYLineChart_AWT( String applicationTitle, String chartTitle,XYSeries,data)           
{
  super(applicationTitle);
  final XYSeriesCollection dataset = new XYSeriesCollection( );          
  dataset.addSeries( data );
  JFreeChart xylineChart = ChartFactory.createXYLineChart(
     chartTitle ,
     "Time(sec)" ,
     "Amplitude" ,
     dataset ,
     PlotOrientation.VERTICAL ,
     true , true , false);

  ChartPanel chartPanel = new ChartPanel( xylineChart );
  chartPanel.setPreferredSize( new java.awt.Dimension( 560 , 367 ) );
  final XYPlot plot = xylineChart.getXYPlot( );
   org.jfree.chart.axis.ValueAxis domain = plot.getDomainAxis();
    domain.setAutoRange(true);
    org.jfree.chart.axis.ValueAxis range = plot.getRangeAxis();
    range.setRange(-5, 5);
  XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer( );
  renderer.setSeriesPaint( 0 , Color.DARK_GRAY );

  renderer.setSeriesStroke( 0 , new BasicStroke( 4.0f ) );

  plot.setRenderer( renderer ); 
  setContentPane( chartPanel ); 
 }
}

That is what I have tried. Please guide me: What am I doing wrong?

This is the code where i perform modulation. Requirement for number of samples is 2048 so I have repeated the 8 bit encoded sequence 2048/8 times:

fc = Integer.parseInt(ddlFrequency.getSelectedItem().toString());
   int A = 5;
   for(int i = 0;i<2048;i++){
     for(int j = 0;j<8;j++){
         baseband[i] = encodedBit[j];
     }  
   }
   for(int i = 0;i<2048;i++){
     g[i] = baseband[i]*(A*Math.toRadians(Math.sin(2*Math.PI*fc*i)));  
   }

This is where the signal is plotted on clicking a button:

final XYSeries data = new XYSeries( "" );
  for(int i = 0; i<2048;i++){
      data.add( i , g[i] );
      //data.add( i/2 , encodedBit[i] );
  }     

    XYLineChart_AWT chart = new XYLineChart_AWT("Plot", "Modulated Signal  Plot" , data);
  chart.pack( );          
  RefineryUtilities.centerFrameOnScreen( chart );          
  chart.setVisible( true );

Here is what I get on plot:

enter image description here


Solution

  • As @gpasch mentioned, you should be multiplying your encoded baseband signal with the carrier tone. But as you do so, there are a few things which you should be careful about.

    First with fc being an integer frequency in your implementation, the phase argument to sin is always a multiple of 2*Math.PI and correspondingly the value of the sin is always 0. Instead, the frequency fc of the carrier tone should be normalized by the sampling rate say fs:

    A*Math.sin(2*Math.PI*fc/((float) fs)*i)
    

    Then, the baseband signal has to be held for at least half a cycle of the carrier (and ideally more). You mentioned that you want to transmit your 8 bits over 2048 samples (or 256 samples per bit), so that means that your carrier frequency should be higher than 0.5*fs/256.0 (where the 0.5 factor is to account for the half cycle, and 256 is the number of samples per bit). For example if fs is 2048Hz then it means you should have fc>4Hz. You would also want fc to be less than the Nyquist rate 0.5*fs (and in general less if you want to have a smooth carrier). For example a fairly common audio sampling rate of fs=8000Hz would be suitable for 16 < fc < ~1000. In either case there isn't too much to worry, but you should keep that in mind.

    Now to hold that baseband signal you had the right idea to repeat the encodedBit, though your implementation didn't quite achieve that. To get the desired effect you shouldn't be repeating the 8 bit sequence 256 times, but rather repeating one bit 256 times, then the next bit and so on. To do this, you'd have to invert the order of your loops. Also, make sure all those repeated bits are stored at different locations in the baseband buffer, so your destination index should keep incrementing:

    int blockSize   = 2048/8;
    int outputIndex = 0;
    for(int j = 0;j<8;j++){
      for(int i = 0;i<blockSize;i++){
        baseband[outputIndex] = encodedBit[j];
        outputIndex++;
      }  
    }
    

    Finally, not shown in your posted code, to represent a BPSK signal your encodedBit buffer should contain values which are either +1 or -1. If instead they are 0s and 1s, then you can perform the conversion with 2*encodedBit[j]-1:

    int blockSize   = 2048/8;
    int outputIndex = 0;
    for(int j = 0;j<8;j++){
      for(int i = 0;i<blockSize;i++){
        baseband[outputIndex] = 2*encodedBit[j]-1;
        outputIndex++;
      }  
    }