/****************************************************************************/ /* Valve Body Simulation */ /****************************************************************************/ /* */ /** * @version 1, 10/5/2000 * @author Andrew Silveri */ import java.awt.*; import java.applet.*; import java.lang.*; import java.util.*; import java.io.*; /** * Shift * This provides for running the application as an applet. */ public class shift extends Applet { /** global variables **/ public static reg_mod window; // actual window object /**************************** Init() ****************************************/ // Note: only required for applets public void init() { // create user interface window = new reg_mod(); window.setTitle("Shift Simulation"); window.pack(); window.start(); window.show(); window.reshape(10,10,750,450); } } /** * Reg_mod extends the Frame class in order to create a top level window with a title. * The runnable interface allows reg_mod to run without subclassing thread by instantiating * a thread instance and passing itself in as the target. */ class reg_mod extends Frame implements Runnable { final static double DTHYD = 0.00003; final static double DT2 = 0.000015; final static double DT6 = 0.000005; final static double RHO = 0.00007957; final static double BETAL = 220000; final static double CEEDEE = 0.6; final static double AIRMIX = 0.05; final static double AREAMAX = 0.0314; final int PAUSE_LENGTH = 20; // millisecs to pause between ticks /* variables for double-buffered painting... */ Image offScreenImage = null; Graphics offScreenGraphics = null; Dimension offScreenSize = null; /* user interface objects */ Panel controlPanel = new Panel(); Panel Display = new Panel(); MenuBar mb; // menu bar object Menu m1, m2, m3; // first sub menu objects MenuItem mi1_1, mi1_2, mi1_3; MenuItem mi3_1, mi3_2, mi3_3; Button back_up = new Button(" Acc. Back + "); Button back_down = new Button(" Acc. Back - "); Button sol1 = new Button(" SS1 off "); Button reset = new Button(" Reset "); /* hash table for plotting */ static Hashtable plot_vars = new Hashtable(); /* vector is a growable array */ Vector graphs = new Vector(); static Vector plot_var = new Vector(); /* dynamic variables */ Accumulator accum; s12_valve valve12; lm_valve line_mod; band_clutch servo; solenoid ss1; /** * rktime is displayed on the screen as "Time", * it is incremented by DT2 for each integration step * and is used as a comparator to update the screen after * a redraw */ public double rktime; /** * next_time is used to create a time delta to compare against rktime */ public double next_time; /** * raw_back is the accumulator back pressure created by the Acc Back + and - * buttons it is clipped between 2.5 and 100 and initialized to zero */ public double raw_back; /* main thread */ Thread mainThread; boolean isRunning = false; boolean first = true; static boolean help_on = false; /**************************************************************************** reg_mod() ****************************************************************************/ public reg_mod() { init(); } /** * Creates the menu bar and control buttons and adds them to the window. * Initializes all values to zero. */ public void init() { setLayout(new BorderLayout()); mb = new MenuBar(); // create the menu bar setMenuBar(mb); // add the menu bar to this window /* assign names to buttons and add to menu bar and sub menus */ m1 = new Menu("File"); mb.add(m1); mi1_1 = new MenuItem(" New Graph "); m1.add(mi1_1); m1.addSeparator(); mi1_2 = new MenuItem(" Exit "); m1.add(mi1_2); m3 = new Menu("Help"); mb.add(m3); mi3_1 = new MenuItem(" Instructions... "); m3.add(mi3_1); /* add buttons */ controlPanel.add(sol1); controlPanel.add(back_up); controlPanel.add(back_down); controlPanel.add(reset); add("South", controlPanel); add("Center", Display); valve12 = new s12_valve(); line_mod = new lm_valve(); accum = new Accumulator(); servo = new band_clutch(); ss1 = new solenoid(); /* initialize values to zero */ accum.init( 0.0, false, valve12, line_mod ); valve12.init( 0.0, 0.0, ss1 ); line_mod.init( 0.0 ); servo.init( 0.0, valve12 ); ss1.init( false, valve12 ); rktime = 0.0; raw_back = 0.0; } /**************************************************************************** draw_Spring() Draws the accumulator spring ****************************************************************************/ static void draw_Spring( int state, Graphics g, int x_start, int x_end, int y1, int y2 ) { int length = x_end - x_start; int x1 = x_start + length/6; int x2 = x_start + length/3; int x3 = x_start + length/2; int x4 = x_start + 2*length/3; int x5 = x_start + 5*length/6; int x6 = x_start + length; if ( state >= 0 ) { g.drawLine( x_start, y1, x1, y2 ); g.drawLine( x1, y1, x2, y2); g.drawLine( x2, y1, x3, y2); g.drawLine( x3, y1, x4, y2); g.drawLine( x4, y1, x5, y2); g.drawLine( x5, y1, x6, y2); } if ( state <= 0 ) { g.drawLine( x1, y2, x1, y1); g.drawLine( x2, y2, x2, y1); g.drawLine( x3, y2, x3, y1); g.drawLine( x4, y2, x4, y1); g.drawLine( x5, y2, x5, y1); } } /**************************************************************************** sqrtt() Square root function ****************************************************************************/ static double sqrtt( double arg ) { if ( arg == 0.0 ) return( 0.0 ); else if ( arg < 0.0 ) return ( -Math.sqrt( -arg ) ); else return ( Math.sqrt( arg ) ); } /**************************************************************************** pressColor() The transmission oil color(red) gets more vivid as pressure builds. ****************************************************************************/ static Color pressColor( double pressure ) { int red = 0; Color press_color; if ( pressure >= 120.0 ) red = 255; else if ( pressure <= 0.0 ) red = 0; else if ( pressure < 30.0 ) red = (int)( 100.0 * pressure / 30.0 ); else red = (int)( 155.0 * (pressure-30.0) / 90.0 + 100.0 ); press_color = new Color( 255, 255-red, 255-red ); return press_color; } /**************************************************************************** printPress() ****************************************************************************/ static String printPress( double pressure ) { String out = " "; String press = Double.toString( pressure ); int index1, length; int index2; length = press.length(); index1 = press.indexOf(".") + 4; index2 = press.indexOf("e"); if ( index1 > length ) index1 = length; if ( (index1 >= index2) && (index2 > 0) ) index1 = index2 - 1; out = press.substring( 0, index1 ); return out; } /** *Integral step time of 15 microseconds */ public void integration() { /** step 0 **/ ss1.intgrt( -1 ); accum.intgrt( -1 ); servo.intgrt( -1 ); valve12.intgrt( -1 ); line_mod.feed = ( 0.002 * raw_back ) + ( 0.998 * line_mod.feed ); /* Graph the elements every 25 milliseconds */ if ( rktime > next_time ) { for( Enumeration e=graphs.elements(); e.hasMoreElements(); ) { Graph elem = (Graph)e.nextElement(); if ( elem.state ) { elem.redraw(); } else { elem.dispose(); graphs.removeElement( elem ); } } next_time = rktime + 0.025; /* update the screen */ update(Display.getGraphics()); try { Thread.sleep(PAUSE_LENGTH); } catch (InterruptedException e) { } } /** step 1 **/ ss1.deriv( 0 ); valve12.deriv( 0 ); accum.deriv( 0 ); servo.deriv( 0 ); rktime += DT2; ss1.intgrt( 0 ); accum.intgrt( 0 ); servo.intgrt( 0 ); valve12.intgrt( 0 ); /** step 2 **/ ss1.deriv( 1 ); accum.deriv( 1 ); servo.deriv( 1 ); valve12.deriv( 1 ); ss1.intgrt( 1 ); accum.intgrt( 1 ); servo.intgrt( 1 ); valve12.intgrt( 1 ); /** step 3 **/ ss1.deriv( 2 ); accum.deriv( 2 ); servo.deriv( 2 ); valve12.deriv( 2 ); rktime += DT2; ss1.intgrt( 2 ); accum.intgrt( 2 ); servo.intgrt( 2 ); valve12.intgrt( 2 ); /** step 4 **/ ss1.deriv( 3 ); accum.deriv( 3 ); servo.deriv( 3 ); valve12.deriv( 3 ); ss1.intgrt( 3 ); accum.intgrt( 3 ); servo.intgrt( 3 ); valve12.intgrt( 3 ); } /** *Integrate while SS1 is on */ public void run() { while ( true ) { integration(); } // end while } // end run /** *Start Integral */ public void start() { mainThread = new Thread(this); mainThread.start(); // calls back to run method in "this" isRunning = true; } /** * Stop Integral */ public void stop() { if (mainThread != null) { mainThread.stop(); isRunning = false; mainThread = null; } } /** * Use double buffering to prevent flickering images. */ public final void update(Graphics g) { /* implements no-flicker graphics using double buffering */ Dimension dim = size(); if((offScreenImage == null) || (dim.width != offScreenSize.width) || (dim.height != offScreenSize.height)) { offScreenImage = createImage(dim.width, dim.height); offScreenSize = dim; offScreenGraphics = offScreenImage.getGraphics(); } offScreenGraphics.clearRect(0, 0, offScreenSize.width, offScreenSize.height); paint(offScreenGraphics); g.drawImage(offScreenImage, 0, 0, null); } /** * Paint the window graphics. If help is pressed in the menu then also paint * valvebody component descriptions. */ public void paint(Graphics g) { if ( first ) { Font f = new Font("Times Roman",Font.BOLD,12); g.setFont(f); first = false; } g.drawString("Time: " + reg_mod.printPress( rktime ), 10, 10); accum.paint(g); valve12.paint(g); servo.paint(g); ss1.paint(g); // paint help if ( help_on ) { g.setColor( Color.blue ); g.drawString("Solenoid",190,60); g.drawLine(220,62,255,70); g.drawString("Shift Valve",400,50); g.drawLine(425,55,425,68); g.drawString("Accumulator",250,230); g.drawLine(280,220,290,192); g.drawString("Servo",520,260); g.drawLine(515,255,490,255); g.drawString("Turn the Solenoid On/Off",30,370); g.drawLine(185,365,260,380); g.drawString("Increase/Decrease Accumulator Back Pressure",220,350); g.drawLine(330,352,370,380); g.setColor( Color.black ); } } /** * Window,menu,and button handling. If the window is closed clean up. * If New Graph is selected in the menu then open graph window. * If help is selected in the menu then open help window. * If exit is selected in the menu clean up and close window. */ public boolean handleEvent(Event event) { if ( event.id == Event.WINDOW_DESTROY ) { stop(); for( Enumeration e=graphs.elements(); e.hasMoreElements(); ) ((Graph)e.nextElement()).dispose(); graphs.removeAllElements(); dispose(); System.exit(0); return true; } if ( event.id == Event.ACTION_EVENT ) { if ( event.target == mi1_1 ) { Graph plot = new Graph(); plot.setTitle("Plot " + graphs.size() ); plot.pack(); plot.show(); plot.reshape(10,10,300,200); graphs.addElement( plot ); return true; } if ( event.target == mi3_1 ) // help { Help_Window helpp = new Help_Window(); helpp.setTitle(" Instructions " ); helpp.pack(); helpp.show(); helpp.reshape(10,10,300,500); return true; } if ( event.target == mi1_2 ) { stop(); for( Enumeration e=graphs.elements(); e.hasMoreElements(); ) ((Graph)e.nextElement()).dispose(); graphs.removeAllElements(); dispose(); System.exit(0); return true; } if ( event.target == reset ) { sol1.setLabel(" SS1 off "); ss1.state = false; for( Enumeration e=graphs.elements(); e.hasMoreElements(); ) ((Graph)e.nextElement()).dispose(); graphs.removeAllElements(); accum.init( 0.0, false, valve12, line_mod ); valve12.init( 0.0, 0.0, ss1 ); line_mod.init( 0.0 ); servo.init( 0.0, valve12 ); ss1.init( false, valve12 ); rktime = 0.0; next_time = 0.0; raw_back = 0.0; return true; } if ( event.target == sol1 ) { if ( ss1.state ) { sol1.setLabel(" SS1 off "); ss1.state = false; } else { ss1.state = true; sol1.setLabel(" SS1 on "); } return true; } if ( event.target == back_up ) { if ( raw_back < 100.0 ) raw_back += 2.5; return true; } if ( event.target == back_down ) { if ( raw_back > 2.5 ) raw_back -= 2.5; return true; } } return false; } /**************************************************************************** startStop() ****************************************************************************/ void startStop() { if (isRunning) { isRunning = false; mainThread.stop(); mainThread = null; } else { mainThread = new Thread(this); mainThread.start(); isRunning = true; } update(Display.getGraphics()); // update screen } } /** * This scales the plots that are selected under menu item New Graph */ class Plot_Object extends Object { public double value; public double base = 0.0; public double span = 1.0; Plot_Object() { value = 0.0; } public int plot_value() { return (int)( 1000.0 * ((value - base ) / span)); } public void set_range( double min, double max ) { base = min; span = max - min; } } /** * This sets up the plot selections under "File" menu selection. * The selected plot is then drawn using double buffered graphics. */ class Graph extends Frame { boolean first = true; boolean state = true; int index = 0; int[] buffer = new int[150]; boolean buff_full = false; String signal = " "; /* variables for double-buffered painting... */ Image offScreenImage = null; Graphics offScreenGraphics = null; Dimension offScreenSize = null; /* user interface objects */ Panel Display = new Panel(); MenuBar mb; // menu bar object Menu m1, m2, m3, mi1_1; // first sub menu objects MenuItem mi1_2, mi1_3; MenuItem mi3_1, mi3_2, mi3_3; /** * This sets up the plot selections in the "File" sub menu */ public Graph() { setLayout(new BorderLayout()); mb = new MenuBar(); // create the menu bar setMenuBar(mb); // add the menu bar to this window m1 = new Menu("File"); mb.add(m1); mi1_1 = new Menu(" Select Signal... "); m1.add(mi1_1); m1.addSeparator(); mi1_2 = new MenuItem(" Exit "); m1.add(mi1_2); for( Enumeration e = reg_mod.plot_vars.keys(); e.hasMoreElements(); ) { /* All available plots listed */ mi1_1.add( new MenuItem( (String)e.nextElement() )); } add("Center", Display); } /** * Update the screen */ public void redraw() { update(Display.getGraphics()); // update screen }; /** * Use double buffering to prevent flickering images. */ public final void update(Graphics g) { // implements no-flicker graphis using double buffering Dimension dim = size(); if((offScreenImage == null) || (dim.width != offScreenSize.width) || (dim.height != offScreenSize.height)) { offScreenImage = createImage(dim.width, dim.height); offScreenSize = dim; offScreenGraphics = offScreenImage.getGraphics(); } offScreenGraphics.clearRect(0, 0, offScreenSize.width, offScreenSize.height); paint(offScreenGraphics); g.drawImage(offScreenImage, 0, 0, null); } /** * Paint the window graphics. Label and draw the selected plot in the plot window. */ public void paint(Graphics g) { /* draw in black */ g.setColor( Color.black ); /* set font first time */ if ( first ) { Font f = new Font("Times Roman",Font.BOLD,12); g.setFont(f); first = false; } Dimension d = size(); int bottom = d.height - 80; int top = 10; double y_delta = ( d.height - 50 ) / 1000.0; double x = 10.0; double x_delta = (double)( d.width - 20 ) / (double)buffer.length; if ( signal.length() > 2 ) { /* get plot value placement in buffer */ buffer[index] = ((Plot_Object)(reg_mod.plot_vars.get(signal))).plot_value(); /* display signal name */ g.drawString("Signal: " + signal , 10, 10); /* check to see if the end of buffer reached. If not full continue to plot else reset to beginning */ if ( buff_full ) { int j, k; if ( index == (buffer.length-1) ) { j = 0; k = 1; } else if ( index == (buffer.length-2) ) { j = index+1; k = 0; } else { j = index + 1; k = index + 2; } for( int i=0; i<(buffer.length-1); i++ ) { g.drawLine( (int)x, bottom - (int)(buffer[j] * y_delta) , (int)(x + x_delta), bottom - (int)(buffer[k] * y_delta) ); x += x_delta; k++; j++; if ( k > buffer.length-1 ) { k = 0; j = buffer.length-1; } else if ( k == 1 ) { j = 0; } } } else { for( int i=0; i buffer.length-1 ) { buff_full = true; index = 0; } } else { index = 0; } } /** * Window,menu,and button handling. If the window is closed clean up. * If "Select Signal" is selected in the menu then open corresponding plot window. * If exit is selected in the menu clean up and close window. */ public boolean handleEvent(Event event) { if ( event.id == Event.WINDOW_DESTROY ) { state = false; return true; } if ( event.id == Event.ACTION_EVENT ) { if ( event.target == mi1_2 ) { state = false; return true; } if ( event.target instanceof MenuItem ) { for( Enumeration e = reg_mod.plot_vars.keys(); e.hasMoreElements(); ) { if ( ((String)event.arg).equals( (String)e.nextElement() ) ); { signal = (String)event.arg; } } return true; } } return false; } } /** * This creates the help window. */ class Help_Window extends Frame { boolean first = true; /* user interface objects */ Panel control = new Panel(); MenuBar mb; // menu bar object Menu m1; // first sub menu objects MenuItem mi1_1; Button close1 = new Button(" Close "); /** * The window gives a brief explanation of the simulation. */ public Help_Window() { setLayout(new BorderLayout()); control.setLayout( new FlowLayout( FlowLayout.CENTER ) ); mb = new MenuBar(); // create the menu bar setMenuBar(mb); // add the menu bar to this window m1 = new Menu("File"); mb.add(m1); mi1_1 = new MenuItem(" Exit "); m1.add(mi1_1); control.add( close1 ); String help_text = " Help \n\n" + " This is a simulation of the hydraulics inside\n" + " an automatic transmission used for a 1-2 shift.\n" + " The simulation models the hydraulic pressures\n" + " and component positions using differential \n" + " equations and a Runga-Kutta 4 integrator. \n\n" + " This program was done in Java for demonstration\n" + " purposes. The original models where written in \n" + " Fortran.\n\n" + " Starting Simulation\n\n" + " To start the simulation click on the button labeled\n" + " SS1 off, this will cause the shift valve to move to\n" + " the right. The movement of the shift valve allows \n" + " fluid to flow into the accumulator and servo. The \n" + " servo is the element which causes a shift to occur. \n" + " The objective is to smoothly apply the servo, which \n" + " is the reason for the accumulator. The accumulator \n" + " allows the pressure in the servo to slowly build \n" + " rather than suddenly jump up to max. pressure. \n" + " For controlling a shift we regulate the stroke of the\n" + " accumulator by adding pressure to the back side. \n" + " The buttons labeled Acc. Back + and - are used to \n" + " increase and decrease the accumulator back pressure.\n\n" + " Plotting\n\n" + " All the internal states ( pressures, positions, and \n" + " velocities ) can be plotted by going to the menu and \n" + " selecting File, then New Graph. This will create a new\n" + " plot window. In the menu on the plot window select \n" + " File, then Select Signal, from here you can choose \n" + " which signal you would like to plot. You can change \n" + " the signal you are plotting at any time by selecting a \n" + " new signal. You can also plot more signals by going \n" + " to the main window menu and selecting New Graph \n" + " again.\n"; add("Center", new TextArea( help_text ) ); add("South", control ); reg_mod.help_on = true; } /** * Help window,menu,and button handling. If the window is closed clean up. * If exit is selected in the menu clean up and close window. */ public boolean handleEvent(Event event) { if ( event.id == Event.WINDOW_DESTROY ) { dispose(); reg_mod.help_on = false; return true; } if ( event.id == Event.ACTION_EVENT ) { if ( event.target == mi1_1 ) { dispose(); reg_mod.help_on = false; return true; } if ( event.target == close1 ) { dispose(); reg_mod.help_on = false; return true; } } return false; } } /** * This handles the derivative/integration calculations for the accumulator resulting in the * spring position and velocity. This will give the resulting local pressure that is determined * by user input. */ class Accumulator extends Panel { final static double ACC_SPMOD_PRELOAD = 12.78; final static double ACC_SPMOD_K = 83.44; final static double ACC_SPMOD_TRVL = 0.1535; final static double ACC_A1 = 1.24659; final static double ACC_K = 23.66; final static double ACC_PRELOAD = 9.65; final static double ACC_EMASS = 0.000171; final static double ACC_TRVL = 1.45; final static double ACC_VOL = 0.4; final static double ACC_MAX_VOL = 2.5; public Plot_Object plot1 = new Plot_Object(); public Plot_Object plot2 = new Plot_Object(); protected boolean mod_spring = false; protected s12_valve valve12 = null; protected lm_valve line_mod = null; /* velocity array */ protected double dx[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; /* position array */ protected double x[] = { 0.0, 0.0 }; /** * 1-2 valve pressure effect on accumulator */ public double f1; /** * line pressure effect on accumaulator */ public double f2; /** * accumulator preload */ public double f3; /** * accumulator spring preload */ public double f4; /** * spring position */ public double pos; /** * spring velocity */ public double vel; /** * delta velocity */ public double delta_vel; /** * delta position */ public double delta_pos; private int length = 120, diam = 40, x1 = 240, y = 150; private int y2 = y+1, y3 = y+diam-1, xpos = 0; /**************************************************************************** Accumulator() Plot accumulator velocity and position ****************************************************************************/ protected Accumulator() { plot1.set_range( -20.0, 20.0 ); plot2.set_range( 0.0, 3.0 ); reg_mod.plot_vars.put("Acc Vel", plot1 ); reg_mod.plot_vars.put("Acc Pos", plot2 ); } /** * Set initial velocity, position, and pressure to zero */ public void init( double p, boolean has_msprg, s12_valve s12, lm_valve lm ) { for(int i=0; i<8; i++) dx[i] = 0.0; x[0] = 0.0; x[1] = p; valve12 = s12; line_mod = lm; pos = p; mod_spring = has_msprg; } /** * Calculate change in position and velocity * @param step the derivative step */ public void deriv( int step ) { f1 = valve12.feed * ACC_A1; f2 = line_mod.feed * ACC_A1; f3 = ACC_PRELOAD + ACC_K * pos; if (( mod_spring ) && ( pos <= ACC_SPMOD_TRVL )) f4 = ACC_SPMOD_PRELOAD - ACC_SPMOD_K * pos; else f4 = 0.0; valve12.acc_vol = pos * ACC_A1 + ACC_VOL; valve12.acc_flow = ACC_A1 * vel; delta_vel = ( f1 - f2 - f3 + f4 ) / ACC_EMASS; /* clip max. and min. travel */ if ( pos >= ACC_TRVL ) { pos = ACC_TRVL; if ( vel > 0.0 ) vel = 0.0; if ( delta_vel > 0.0 ) delta_vel = 0.0; if ( step == 1 ) { x[0] = vel; x[1] = ACC_TRVL; } } else if ( pos <= 0.0 ) { pos = 0.0; if ( vel < 0.0 ) vel = 0.0; if ( delta_vel < 0.0 ) delta_vel = 0.0; if ( step == 1 ) { x[0] = vel; x[1] = 0.0; } } delta_pos = vel; dx[2*step] = delta_vel; dx[2*step+1] = delta_pos; } /** * integrate the position and velocity increments * @param step the integral step */ public void intgrt( int step ) { if ( step == -1 ) { vel = x[0]; pos = x[1]; plot1.value = vel; plot2.value = pos; } else if ( step == 0 ) { vel = x[0] + ( dx[0] * reg_mod.DT2 ); pos = x[1] + ( dx[1] * reg_mod.DT2 ); } else if ( step == 1 ) { vel = x[0] + ( dx[2] * reg_mod.DT2 ); pos = x[1] + ( dx[3] * reg_mod.DT2 ); } else if ( step == 2 ) { vel = x[0] + ( dx[4] * reg_mod.DTHYD ); pos = x[1] + ( dx[5] * reg_mod.DTHYD ); } else if ( step == 3 ) { x[0] += ( dx[0] + 2.0*( dx[2] + dx[4] ) + dx[6] ) * reg_mod.DT6; x[1] += ( dx[1] + 2.0*( dx[3] + dx[5] ) + dx[7] ) * reg_mod.DT6; } } /** * Paint the window graphics. Draw the accumulator change in position and update * pressure and position values in the main window. */ public void paint(Graphics g) { xpos = (int)((1.0-(pos/ACC_TRVL)) * length); // back pressure g.setColor( reg_mod.pressColor( line_mod.feed ) ); g.fillRect( x1, y2, xpos, diam-1 ); g.fillRect( x1-10, y+diam-4, 10, 4 ); // feed pressure g.setColor( reg_mod.pressColor( valve12.feed ) ); g.fillRect( x1+xpos, y2, length-xpos+10, diam-1 ); g.fillRect( x1+length+10, y+diam-4, 24, 4 ); g.setColor( Color.lightGray ); g.fillRect( x1+xpos, y2, 9, diam-2 ); g.setColor( Color.black ); g.drawRect( x1+xpos, y2, 9, diam-2 ); g.drawLine( x1, y, x1+length+10, y); g.drawLine( x1-10, y+diam, x1+length+33, y+diam); g.drawLine( x1-10, y+diam-5, x1, y+diam-5 ); g.drawLine( x1+length+10, y+diam-5, x1+length+33, y+diam-5); g.drawLine( x1, y, x1, y+diam-5); g.drawLine( x1+length+10, y, x1+length+10, y+diam-5); reg_mod.draw_Spring( 0, g, x1, x1+xpos, y2, y3 ); g.drawString("BP: " + reg_mod.printPress( line_mod.feed ), x1,y-25); g.drawString("FP: " + reg_mod.printPress( valve12.feed ), x1,y-15); g.drawString("Pos: " + reg_mod.printPress( pos ), x1,y-5); } } class lm_valve extends Panel { protected double dx[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; protected double x[] = { 0.0, 0.0 }; public double feed; public double f1, f2, f3, f4, pos, vel, vol, q_feed, q_back; public double delta_vel, delta_pos; /**************************************************************************** lm_valve() ****************************************************************************/ protected lm_valve() { } /**************************************************************************** init() ****************************************************************************/ public void init( double press ) { for(int i=0; i<8; i++) dx[i] = 0.0; x[0] = 0.0; x[1] = 0.0; feed = press; } /**************************************************************************** deriv( int step ) ****************************************************************************/ public void deriv( int step ) { } /**************************************************************************** paint(Graphics g) ****************************************************************************/ public void paint(Graphics g) { } } /** * This handles the derivative/integration calculations for the 1-2 valve resulting in the * valve position and velocity. This will affect the pressure feed to the system. */ class s12_valve extends Panel { final static double S12VLV_A1 = 0.2386; final static double S12VLV_K = 4.23; final static double S12VLV_PRELOAD = 4.0; final static double S12VLV_DIAM = 0.5512; final static double S12VLV_TRVL = 0.26; final static double S12VLV_OVLP1 = 0.125; final static double S12VLV_OVLP2 = 0.135; final static double S12VLV_VOL = 0.5; final static double S12VLV_EMASS = 0.000013; protected double dx[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; protected double x[] = { 0.0, 0.0, 0.0, 0.0, 0.0 }; protected double c1, c2, c5, c9, c11; protected solenoid ss1 = null; public Plot_Object plot3 = new Plot_Object(); public Plot_Object plot4 = new Plot_Object(); public Plot_Object plot5 = new Plot_Object(); public Plot_Object plot6 = new Plot_Object(); public Plot_Object plot7 = new Plot_Object(); public double feed; /** * release pressure */ public double rel; /** * intermediate pressure */ public double interm; /** * delta line pressure feed */ public double delta_feed; /** * delta release pressure */ public double delta_rel; /** * delta intermediate pressure */ public double delta_interm; /** * initial velocity holder */ public double f1; /** * secondary velocity holder */ public double f2; /** * valve position */ public double pos; /** * valve velocity */ public double vel; /** * valve volume */ public double vol; /** * pressure feed flow */ public double q_feed; /** * pressure exhaust flow */ public double q_exh; /** * pressure release flow */ public double q_release; /** * pressure source flow */ public double q_source; /** * flow from solenoid */ public double ss_draw; /** * change in valve velocity */ public double delta_vel; /** * change in valve position */ public double delta_pos; /** * feed position */ public double x_feed; /** * exhaust position */ public double x_exh; /** * exhaust area */ public double area; /** * pressure constant 1 */ public double beta1; /** * pressure constant 2 */ public double beta2; /** * pressure constant 3 */ public double beta3; /** * servo apply volume */ public double sap_vol; /** * servo release volume */ public double srel_vol; /** * servo apply flow */ public double sap_flow; /** * servo release flow */ public double srel_flow; /** * servo accumulator volume */ public double acc_vol; /** * accumulator flow */ public double acc_flow; private int travel = 14, length = 91, diam = 20, x0 = 360, y = 74; private int xpos = 0, y1 = y - 5, y2 = y - 1, y3 = y + diam + 1, y4 = y + diam + 5; private double area2_press = 0.0; /**************************************************************************** s12_valve() This valve is used to regulate pressure flow for a 1-2 shift ****************************************************************************/ protected s12_valve() { /* constants */ c1 = 2.0 / reg_mod.RHO; c2 = Math.sqrt( c1 ); c5 = 1.0 / reg_mod.BETAL; c9 = Math.PI * S12VLV_DIAM; c11 = c2 * reg_mod.CEEDEE; plot3.set_range( -20.0, 20.0 ); plot4.set_range( 0.0, 0.5 ); plot5.set_range( 0.0, 150.0 ); plot6.set_range( 0.0, 150.0 ); plot7.set_range( 0.0, 150.0 ); /* plot servo and 1-2 valve values */ reg_mod.plot_vars.put("vlv12 Vel", plot3 ); reg_mod.plot_vars.put("vlv12 Pos", plot4 ); reg_mod.plot_vars.put("Servo App", plot5 ); reg_mod.plot_vars.put("Servo Rel", plot6 ); reg_mod.plot_vars.put("vlv12 Src", plot7 ); } /** * Set initial velocity, position, pressures and area for 1-2 valve */ public void init( double press, double vpos, solenoid ss ) { for(int i=0; i<20; i++) dx[i] = 0.0; x[0] = 0.0; x[1] = 0.0; x[2] = 0.0; x[3] = 0.0; x[4] = 0.0; feed = press; pos = vpos; interm = 0.0; rel = 0.0; ss1 = ss; area2_press = 0.0; } /** * Calculate changes in position, velocity, area, flow * @param step the derivative step */ public void deriv( int step ) { beta1 = 1.0 / ( c5 + ( reg_mod.AIRMIX / ( 1.4 * ( feed + 14.7 ) ) ) ); beta2 = 1.0 / ( c5 + ( reg_mod.AIRMIX / ( 1.4 * ( rel + 14.7 ) ) ) ); beta3 = 1.0 / ( c5 + ( reg_mod.AIRMIX / ( 1.4 * ( interm + 14.7 ) ) ) ); f1 = ss1.feed * S12VLV_A1; f2 = S12VLV_PRELOAD + S12VLV_K * pos; /* feed area and flow */ if ( pos > S12VLV_OVLP2 ) x_feed = pos - S12VLV_OVLP2; else x_feed = 0.0; area = c9 * x_feed; if ( area > reg_mod.AREAMAX ) area = reg_mod.AREAMAX; q_source = c11 * ( 0.1 * area ) * reg_mod.sqrtt( 120.0 - interm ); q_feed = c11 * area * reg_mod.sqrtt( interm - feed ); /* allow leakage for release exhaust */ if ( area < 0.02 ) area = 0.02; q_release = c11 * ( 0.25 * area ) * reg_mod.sqrtt( rel ); /* exhaust area and flow */ if ( pos < S12VLV_OVLP1 ) x_exh = S12VLV_OVLP1 - pos; else x_exh = 0.0; area = c9 * x_exh; if ( area > reg_mod.AREAMAX ) area = reg_mod.AREAMAX; q_exh = c11 * area * reg_mod.sqrtt( feed ); /* flow from ss1 */ ss_draw = vel * S12VLV_A1; delta_feed = (beta1 / (S12VLV_VOL + acc_vol + sap_vol) ) * ( q_feed - q_exh - sap_flow - acc_flow ); delta_rel = (beta2 / (0.001 + srel_vol) ) * ( srel_flow - q_release ); delta_interm = (beta3 / 0.1 ) * ( q_source - q_feed ); delta_vel = (f1 - f2) / S12VLV_EMASS; delta_pos = vel; /* clip max. and min. travel */ if ( pos >= S12VLV_TRVL ) { pos = S12VLV_TRVL; if ( vel > 0.0 ) vel = 0.0; if ( delta_vel > 0.0 ) delta_vel = 0.0; if ( step == 1 ) { x[0] = vel; x[1] = S12VLV_TRVL; } } else if ( pos <= 0.0 ) { pos = 0.0; if ( vel < 0.0 ) vel = 0.0; if ( delta_vel < 0.0 ) delta_vel = 0.0; if ( step == 1 ) { x[0] = vel; x[1] = 0.0; } } delta_pos = vel; dx[5*step] = delta_vel; dx[5*step+1] = delta_pos; dx[5*step+2] = delta_feed; dx[5*step+3] = delta_rel; dx[5*step+4] = delta_interm; /* for graphics */ if (( pos > 0.07 ) && ( pos < 0.135 )) area2_press = 120.0; else if ( pos > 0.135 ) area2_press = feed; } /** * integrate the position and velocity increments and calculate * feed,release,and intermediate values. * @param step the integral step */ public void intgrt( int step ) { if ( step == -1 ) { vel = x[0]; pos = x[1]; feed = x[2]; rel = x[3]; interm = x[4]; plot3.value = vel; plot4.value = pos; plot5.value = feed; plot6.value = rel; plot7.value = interm; } else if ( step == 0 ) { vel = x[0] + ( dx[0] * reg_mod.DT2 ); pos = x[1] + ( dx[1] * reg_mod.DT2 ); feed = x[2] + ( dx[2] * reg_mod.DT2 ); rel = x[3] + ( dx[3] * reg_mod.DT2 ); interm = x[4] + ( dx[4] * reg_mod.DT2 ); } else if ( step == 1 ) { vel = x[0] + ( dx[5] * reg_mod.DT2 ); pos = x[1] + ( dx[6] * reg_mod.DT2 ); feed = x[2] + ( dx[7] * reg_mod.DT2 ); rel = x[3] + ( dx[8] * reg_mod.DT2 ); interm = x[4] + ( dx[9] * reg_mod.DT2 ); } else if ( step == 2 ) { vel = x[0] + ( dx[10] * reg_mod.DTHYD ); pos = x[1] + ( dx[11] * reg_mod.DTHYD ); feed = x[2] + ( dx[12] * reg_mod.DTHYD ); rel = x[3] + ( dx[13] * reg_mod.DTHYD ); interm = x[4] + ( dx[14] * reg_mod.DTHYD ); } else if ( step == 3 ) { x[0] += ( dx[0] + 2.0*( dx[5] + dx[10] ) + dx[15] ) * reg_mod.DT6; x[1] += ( dx[1] + 2.0*( dx[6] + dx[11] ) + dx[16] ) * reg_mod.DT6; x[2] += ( dx[2] + 2.0*( dx[7] + dx[12] ) + dx[17] ) * reg_mod.DT6; x[3] += ( dx[3] + 2.0*( dx[8] + dx[13] ) + dx[18] ) * reg_mod.DT6; x[4] += ( dx[4] + 2.0*( dx[9] + dx[14] ) + dx[19] ) * reg_mod.DT6; } } /** * Paint the window graphics. Display the pressure changes(red color gets * darker in areas of higher pressure) and the valve movement in the main window. */ public void paint(Graphics g) { xpos = x0 + (int)( (pos/0.26) * travel ); // area 1 g.setColor( reg_mod.pressColor( ss1.feed ) ); g.fillRect( x0+1,y,(xpos+4-x0), diam+1); // line feed area g.setColor( Color.red ); g.fillRect( x0+27,y-15,4,15); // area 2 g.setColor( reg_mod.pressColor( area2_press ) ); g.fillRect( xpos+11, y, 14, diam+1); // output feed area g.setColor( reg_mod.pressColor( feed ) ); g.fillRect( x0+34, y+diam, 4, 131); // area 3 exhausts // output release area g.setColor( reg_mod.pressColor( rel ) ); g.fillRect( x0+69, y+diam, 4, 111); g.fillRect( x0+69, y+126, 50, 4); g.fillRect( 479, y+126, 4, 25); // draw valve g.setColor( Color.lightGray ); g.fillRect( xpos, y+7, 4, 6 ); g.fillRect( xpos+4, y, 7, diam ); g.fillRect( xpos+11, y+7, 14, 6 ); g.fillRect( xpos+25, y, 7, diam ); g.fillRect( xpos+32, y+7, 14, 6 ); g.fillRect( xpos+46, y, 7, diam ); g.fillRect( xpos+53, y+7, 14, 6 ); g.fillRect( xpos+67, y, 14, diam ); // draw valve outline g.setColor( Color.black ); g.drawRect( xpos, y+7, 4, 6 ); g.drawRect( xpos+4, y, 7, diam ); g.drawRect( xpos+11, y+7, 14, 6 ); g.drawRect( xpos+25, y, 7, diam ); g.drawRect( xpos+32, y+7, 14, 6 ); g.drawRect( xpos+46, y, 7, diam ); g.drawRect( xpos+53, y+7, 14, 6 ); g.drawRect( xpos+67, y, 14, diam ); // valve case top g.drawLine(x0,y2,x0+26,y2); g.drawLine(x0+26,y2,x0+26,y-15); g.drawLine(x0+31,y2,x0+31,y-15); g.drawLine(x0+31,y2,x0+40,y2); g.drawLine(x0+40,y2,x0+40,y1); g.drawLine(x0+45,y2,x0+45,y1); g.drawLine(x0+45,y2,x0+75,y2); g.drawLine(x0+75,y2,x0+75,y1); g.drawLine(x0+80,y2,x0+80,y1); g.drawLine(x0+80,y2,x0+109,y2); // case bottom g.drawLine(x0,y3,x0+33,y3); g.drawLine(x0+33,y3,x0+33,y+111); g.drawLine(x0+38,y3,x0+38,y+150); g.drawLine(x0+38,y3,x0+68,y3); g.drawLine(x0+68,y3,x0+68,y+130); g.drawLine(x0+73,y3,x0+73,y+125); g.drawLine(x0+73,y3,x0+109,y3); g.drawLine(x0,y2,x0,y3-5); g.drawLine(x0+109,y2,x0+109,y3); reg_mod.draw_Spring( 0, g, xpos+81, x0+109, y, y+diam ); // continue feed line g.drawLine(x0+33,y+116,x0+33,y+150); // continue rel line g.drawLine(x0+68,y+130,478,y+130); g.drawLine(x0+73,y+125,483,y+125); g.drawLine(478,y+130,478,224); g.drawLine(483,y+125,483,224); g.drawString("Pos: " + reg_mod.printPress( pos ), x0+115,y+12); g.drawString("Pfeed: " + reg_mod.printPress( feed), x0+115,y+22); g.drawString("Prel: " + reg_mod.printPress( rel ), x0+115,y+32); } } /** * Applying pressure to the servo tightens the band clutch for the 1-2 shift */ class band_clutch extends Panel { final static double SERVO_A1 = 6.67; final static double SERVO_A2 = 6.55; final static double SERVO_VOL_INIT = 1.0; final static double SERVO_K = 400.0; final static double SERVO_PRELOAD = 86.0; final static double SERVO_EMASS = 0.00087; final static double SERVO_TRVL = 0.26; final static double SERVO_MAX_VOL = 2.8; /* velocity array */ protected double dx[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; /* position array */ protected double x[] = { 0.0, 0.0 }; public Plot_Object plot8 = new Plot_Object(); public Plot_Object plot9 = new Plot_Object(); /** * servo apply feed pressure */ public double f1; /** * servo apply release pressure */ public double f2; /** * servo preload */ public double f3; /** * reserved */ public double f4; /** * servo position */ public double pos; /** * servo velocity */ public double vel; /** * servo velocity delta */ public double delta_vel; /** * servo position delta */ public double delta_pos; protected s12_valve valve12 = null; private int length = 80, diam = 60, x0 = 393, y = 224; private int y2 = y + 1, y3 = y+diam-1, xpos = 0, x2 = x0+length+10; /**************************************************************************** band_clutch() The band clutch is activated for a 1-2 shift ****************************************************************************/ protected band_clutch() { plot8.set_range( -20.0, 20.0 ); plot9.set_range( 0.0, 0.5 ); /* plot servo position, velocity */ reg_mod.plot_vars.put("Servo Vel", plot8 ); reg_mod.plot_vars.put("Servo Pos", plot9 ); } /** * Set initial velocity and position for servo */ public void init( double vpos, s12_valve s12 ) { for(int i=0; i<8; i++) dx[i] = 0.0; x[0] = 0.0; x[1] = vpos; pos = vpos; valve12 = s12; } /** * Calculate changes in position and velocity in servo * @param step the derivative step */ public void deriv( int step ) { f1 = valve12.feed * SERVO_A1; f2 = valve12.rel * SERVO_A2; f3 = SERVO_PRELOAD + SERVO_K * pos; /* servo apply volume */ valve12.sap_vol = SERVO_A1 * pos + SERVO_VOL_INIT; valve12.srel_vol = SERVO_MAX_VOL - SERVO_A2 * pos; valve12.sap_flow = SERVO_A1 * vel; valve12.srel_flow = SERVO_A2 * vel; delta_vel = ( f1 - f2 - f3 ) / SERVO_EMASS; // clip max. and min. travel if ( pos >= SERVO_TRVL ) { pos = SERVO_TRVL; if ( vel > 0.0 ) vel = 0.0; if ( delta_vel > 0.0 ) delta_vel = 0.0; if ( step == 1 ) { x[0] = vel; x[1] = SERVO_TRVL; } } else if ( pos <= 0.0 ) { pos = 0.0; if ( vel < 0.0 ) vel = 0.0; if ( delta_vel < 0.0 ) delta_vel = 0.0; if ( step == 1 ) { x[0] = vel; x[1] = 0.0; } } delta_pos = vel; dx[2*step] = delta_vel; dx[2*step+1] = delta_pos; } /** * integrate the position and velocity increments for the servo * in order to apply the band clutch * @param step the integral step */ public void intgrt( int step ) { if ( step == -1 ) { vel = x[0]; pos = x[1]; plot8.value = vel; plot9.value = pos; } else if ( step == 0 ) { vel = x[0] + ( dx[0] * reg_mod.DT2 ); pos = x[1] + ( dx[1] * reg_mod.DT2 ); } else if ( step == 1 ) { vel = x[0] + ( dx[2] * reg_mod.DT2 ); pos = x[1] + ( dx[3] * reg_mod.DT2 ); } else if ( step == 2 ) { vel = x[0] + ( dx[4] * reg_mod.DTHYD ); pos = x[1] + ( dx[5] * reg_mod.DTHYD ); } else if ( step == 3 ) { x[0] += ( dx[0] + 2.0*( dx[2] + dx[4] ) + dx[6] ) * reg_mod.DT6; x[1] += ( dx[1] + 2.0*( dx[3] + dx[5] ) + dx[7] ) * reg_mod.DT6; } } /** * Paint the window graphics. Display the pressure changes(red color gets * darker in areas of higher pressure) and the servo movement in the main window. */ public void paint(Graphics g) { xpos = (int)( (pos/0.26) * length); // apply pressure g.setColor( reg_mod.pressColor( valve12.feed ) ); g.fillRect( x0, y2, xpos, diam-1 ); // feed pressure g.setColor( reg_mod.pressColor( valve12.rel ) ); g.fillRect( x0+xpos, y2, length-xpos+10, diam-1 ); g.setColor( Color.lightGray ); g.fillRect( x0+xpos, y2, 10, diam-2 ); g.setColor( Color.black ); g.drawRect( x0+xpos, y2, 10, diam-2 ); g.drawLine( x0+5, y, x0+length+5, y); g.drawLine( x0, y+diam, x2, y+diam); g.drawLine( x0, y, x0, y+diam); g.drawLine( x0+length+10, y, x2, y+diam); reg_mod.draw_Spring( 1, g, x0+xpos+10, x2, y2, y3 ); g.setColor( Color.lightGray ); g.fillRect( x0+xpos+10, y + diam/2 - 5, 80, 10 ); g.setColor( Color.black ); g.drawRect( x0+xpos+10, y + diam/2 - 5, 80, 10 ); reg_mod.draw_Spring( -1, g, x0+xpos+10, x2, y2, y3 ); g.drawString("Pos: " + reg_mod.printPress( pos ), x0,y3+15); } } /** * The solenoid regulates the pressure needed to open and close the 1-2 valve */ class solenoid extends Panel { final static double SS1_ORF1 = 0.0659; final static double SS1_ORF2 = 0.0758; final static double SS1_VOL = 1.50; /* velocity array */ protected double dx[] = { 0.0, 0.0, 0.0, 0.0 }; /* position array */ protected double x[] = { 0.0 }; public Plot_Object plot10 = new Plot_Object(); /* constants */ protected double c1, c2, c3, c4, c5, beta1; /** * solenoid feed pressure */ public double feed; /** * source pressure */ public double source; /** * solenoid feed flow */ public double q_feed; /** * solenoid exhaust flow */ public double q_exh; /** * solenoid delta feed pressure */ public double delta_feed; protected s12_valve valve12 = null; public boolean state = false; private int x0 = 260, y = 50; /**************************************************************************** solenoid() When the solenoid is off(closed) there is no pressure feed. The degree that it is open affects the pressure feed to the system ****************************************************************************/ protected solenoid() { c1 = 2.0 / reg_mod.RHO; c2 = Math.sqrt( c1 ); c3 = 1.0 / reg_mod.BETAL; c4 = c2 * reg_mod.CEEDEE * ( Math.PI / 4.0 ) * Math.pow( SS1_ORF1, 2.0 ); c5 = c2 * reg_mod.CEEDEE * ( Math.PI / 4.0 ) * Math.pow( SS1_ORF2, 2.0 ); plot10.set_range( 0.0, 120.0 ); reg_mod.plot_vars.put("SS1 Feed", plot10 ); } /** * Set initial velocity and position for the solenoid */ public void init( boolean on_off, s12_valve s12 ) { for(int i=0; i<4; i++) dx[i] = 0.0; x[0] = 0.0; feed = 0.0; state = on_off; valve12 = s12; } /** * Calculate changes in position and velocity in solenoid * @param step the derivative step */ public void deriv( int step ) { /* constant source of 60psi */ source = 60.0; beta1 = 1.0 / ( c3 + ( reg_mod.AIRMIX / ( 1.4 * ( feed + 14.7 ) ) ) ); if ( state ) { q_feed = c4 * reg_mod.sqrtt( source - feed ); q_exh = 0.0; } else { q_feed = 0.0; q_exh = c5 * reg_mod.sqrtt( feed ); } delta_feed = (beta1/SS1_VOL) * ( q_feed - q_exh - valve12.ss_draw ); dx[step] = delta_feed; } /** * integrate the position and velocity increments for the solenoid * in order to apply pressure and flow to the system * @param step the integral step */ public void intgrt( int step ) { if ( step == -1 ) { feed = x[0]; plot10.value = feed; } else if ( step == 0 ) { feed = x[0] + ( dx[0] * reg_mod.DT2 ); } else if ( step == 1 ) { feed = x[0] + ( dx[1] * reg_mod.DT2 ); } else if ( step == 2 ) { feed = x[0] + ( dx[2] * reg_mod.DTHYD ); } else if ( step == 3 ) { x[0] += ( dx[0] + 2.0*( dx[1] + dx[2] ) + dx[3] ) * reg_mod.DT6; } } /** * Paint the window graphics. Display the pressure changes(red color gets * darker in areas of higher pressure) as the solenoid changes pressure * and flow in the main window. */ public void paint(Graphics g) { g.setColor( Color.black ); g.drawRect( x0, y, 30, 30 ); g.drawRect( x0+7, y+30, 16, 3 ); g.drawRect( x0+5, y+33, 20, 5 ); g.drawRect( x0+11, y+38, 8, 9 ); g.drawRect( x0+9, y+47, 12, 5 ); g.drawRect( x0+12, y+52, 6, 4 ); g.setColor( reg_mod.pressColor( feed ) ); g.fillRect( x0+20, y+41, 81, 4 ); g.setColor( Color.black ); g.drawLine( x0+19, y+40, x0+100, y+40 ); g.drawLine( x0+19, y+45, x0+100, y+45 ); g.drawString("SS1",x0+5,y+15); g.drawString("State: " + state,x0,y-15); g.drawString("Feed: " + reg_mod.printPress( feed ), x0,y-5); } }