/** Passband Demonstrator applet * @author Robert John Morton UK-YE572246C * @version 29 October 2007 Traces 3 graphs of a tuned circuit's attenuation of a signal over a range of -12 to +12 kHz from a centre frequency. The red trace shows the off- tune signal attenuation produced by a single tuned circuit with a 'Q' of 1000. The green trace shows the off-tune attenuation produced by passing the signal through two tuned circuits in succession both of which have a 'Q' of 300. The blue trace shows the effect of passing the signal through 4 tuned circuits in succession, each of which has a 'Q' of only 100. */ import java.awt.*; import javax.swing.*; import java.awt.image.BufferedImage; public class passband extends JPanel implements Runnable { // Uses the default font. boolean finished = false; int X = 300, // x-coord of display window (in pixels) Y = 270, // y-coord of display window (in pixels) plots = -120, // horizontal pixel number -120 to +120 y, // vertical pixel number 0 to -200 xbias = 160, // x co-ordinate of tuned frequency of circuit ybias = 23, // y co-ordinate of zero attenuation line oldx1 = 0, // last time's plots for the three traces oldy1 = 0, oldx2 = 0, oldy2 = 0, oldx3 = 0, oldy3 = 0; double L = .0000003422, // Inductance in Henries C = .0000003422, // Capacitance in Farads R1 = .001, // Resistance in Ohms to give a Q of 1000 R2 = .003, // to give a Q of 333 R3 = .01, // to give a Q of 100 R1S = R1 * R1, // Square of Q = 300 resistance R2S = R2 * R2, // Square of Q = 100 resistance R3S = R3 * R3; // Square of Q = 30 resistance Color t1 = new Color(255,128,0), // trace1 colour t2 = new Color(0,255,128), // trace2 colour t3 = new Color(0,128,255), // trace3 colour gr = new Color(64,64,64), // graticule colour tx = new Color(255,255,255), // text colour bg = new Color(0,0,0); // black background private BufferedImage I = null; // reference for off-screen image private Graphics2D h; // graphics reference for off-screen image private volatile Thread T; // declare a thread reference variable private long δt = 50; // total Time Frame for plot update cycle private long t; // time at which next cycle is due to begin passband() { setBackground(bg); // set panel's background colour /* Create the off-screen image buffer, get its graphics context reference, set its background colour then fill it completely with its background colour. */ I = new BufferedImage(X,Y,BufferedImage.TYPE_INT_RGB); h = I.createGraphics(); h.setColor(bg); h.fillRect(0,0,X,Y); int sbias = 8; // bias to make kHz numbering line up String s = ""; /* Draw the grey vertical graticule lines every 10 pixels on the of-screen image. */ for (int x = -120 ; x < 121 ; x += 10) { h.setColor(gr); h.drawLine(x + xbias,ybias,x + xbias,ybias + 200); // Put numbers in the horizontal scale every 5 kHz from -10 to +10 if (x == -100) { s = "-10"; sbias = 10; } else if (x == -50) { s = "-5"; sbias = 6; } else if (x == 0) { s = "0"; sbias = 2; } else if (x == 50) { s = "5"; sbias = 3; } else if (x == 100) { s = "10"; sbias = 6; } else sbias = 0; // if this line is a multiple of 5kHz, then number it. if (sbias > 0) { h.setColor(tx); h.drawString(s,x + xbias - sbias,ybias + 215); } } // Every 20 pixels going downwards, draw a horizontal graticule line for(y = 0 ; y < 101 ; y += 10) { h.setColor(gr); h.drawLine(xbias - 119,y + y + ybias,xbias + 119,y + y + ybias); // Number every line except the top and bottom ones h.setColor(tx); if(y > 0 && y < 100) h.drawString("-" + y,xbias - 145,y + y + ybias + 4); } h.drawString("kHz",xbias - 8,ybias + 232); // put in the kHz label h.drawString("dBe",xbias - 150,ybias + 3); // put in the dBe label t = System.currentTimeMillis() + δt; // set end of first time frame T = new Thread(this); // create the run thread T.start(); // start the run thread } public void run(){ // run the T thread while(T != null){ // loop while thread is alive if(plots < 121) // If not yet finished, newplot(); // do the next plot. /* Get the time remaining in the current time-frame, imposing a lower limit of 5 milliseconds. Sleep for this remaining time, while allowing external events to interrupt the thread. */ long s = t - System.currentTimeMillis(); if(s < 5) s = 5; try { T.sleep(s); } catch (InterruptedException e) { } // Set the time at which the next time frame will finish. t = System.currentTimeMillis() + δt; } } public void stop() { T = null; } // kill the program thread private void newplot() { /* COMPUTE THE CURRENT ANGULAR FREQUENCY = plots [the number of pixels from the resonant frequency-centre] times [100 x 2pi to convert to radians/second] times the absolute centre frequency of 465kHz in radians/second. */ double w = plots * 628.31853 + 2921681.164; /* COMPUTE REACTANCE OF CIRCUIT AT THIS FREQUENCY = the inductive reactance wL times the capacitative reactance 1/wC. */ double X = w * L - (1 / (w * C)); X = X * X; // square of total reactance /* COMPUTE AND PLOT THE ATTENUATION FOR A SINGLE TUNED CIRCUIT OF Q = 1000 */ y = atten(R1,R1S,X,1); // compute y pixel co-ordinate PlotLine(t1,oldx1,oldy1); // and draw the current plot oldx1 = plots; // set this time's new co-ordinates oldy1 = y; // as next time's old co-ordinates // ... AND FOR A PAIR OF TUNED CIRCUITS IN CASCADE EACH OF Q = 300 y = atten(R2,R2S,X,2); // compute y pixel co-ordinate PlotLine(t2,oldx2,oldy2); // and draw the current plot oldx2 = plots; // set this time's new co-ordinates oldy2 = y; // as next time's old co-ordinates // ... AND FOUR TUNED CIRCUITS IN CASCADE EACH OF Q = 100 y = atten(R3,R3S,X,4); // compute y pixel co-ordinate PlotLine(t3,oldx3,oldy3); // and draw the current plot oldx3 = plots; // compute y pixel co-ordinate oldy3 = y; // and draw the current plot. repaint(); plots++; // advance to the next plot } //COMPUTE THE SIGNAL ATTENUATION int atten(double R, double RR, double X, int n) { double z = Math.sqrt(RR + X) / R, // the circuit's impedance Z = 1; // its compounded impedance /* For each circuit in cascade, raise the impedance for a single circuit to the power equal to the number of cascaded circuits and return it as a number of natural log decibels [doubled because of the y-scale]. */ for(int i = 0 ; i < n ; i++) Z = Z * z; return (int)(40 * Math.log(Z)); } void PlotLine(Color fg, int oldx, int oldy) { /* If beyond the first time through and 'y' has not overshot the graticule then set the required colour for this trace and draw a line from the previous point to the new point. */ if (plots > -120 && y < 200) { h.setColor(fg); h.drawLine(xbias + oldx,ybias + oldy,xbias + plots,ybias + y); } } public void paint(Graphics g) { // (re)draw the screen image g.drawImage(I,0,0,null); // from the off-screen image buffer } }