University of Rochester / Ultrasound Research Laboratory
2D Array Library

 
Class hierarchy   Compound list   File list   Header files   Compound Members   File Members   Examples  

PE3

This is an example application which makes extensive use of the 2D array library. The purpose of this example is to perform a B-scan. This example also relies heavily on the structures contained in the TEST_HDR_TYPE.

/*
  $Id: Acq.h,v 1.1 1999-03-05 16:34:52-05 ljb Exp ljb $
  $Revision: 1.1 $

  $Log: Acq.h,v $
  Revision 1.1  1999-03-05 16:34:52-05  ljb
  Initial revision

  Revision 1.2  1999/03/02 14:54:12  LJB
  After directory restructuring.

  Revision 1.1  1998/06/29 15:11:06  LJB
  Initial revision

*/

#ifndef ACQ_H
#define ACQ_H

#include "tdefs.h"

/* supported scanning methods */
#define LINEAR_IMAGE          0
#define SECTOR_IMAGE          1

/* maximum number of tx and rx focal zones available */
#define MAX_NMBR_ZONES 60

/* maximum number of tgc breakpoints */
#define MAX_NMBR_BRKPTS 10

/*--------------------------------
  TEST_HDR_TYPE 
--------------------------------*/

/*
  Experiment Focus Setup Information
     - defines zone properties
     - assign zones to be used for test 
*/
typedef struct {
  float focus_increment;             // rx delays length within a zone
  float elevation;
  float azimuth;
  float focus_depth[MAX_NMBR_ZONES];   // depth from center of aperature (mm)
  float focus_start[MAX_NMBR_ZONES];   // start of zone band (mm)
  float focus_stop[MAX_NMBR_ZONES];    // end of zone band (mm)
  float tx_fnum[MAX_NMBR_ZONES];     // transmit F#, one per zone
  float rx_fnum[MAX_NMBR_ZONES];     // receive F#, one per zone
  WORD zone_list[MAX_NMBR_ZONES];     // list of zones for experiment
  WORD nmbr_zones;
  WORD dummy;
} FOCUS_CTL_TYPE;                 //1336 bytes

typedef struct {
  int nAscans, nZones, F_sp, Xpitch, Ypitch;
  int temp;                       //temperature in .01C units
  int dummy[26];
} BRIEF;                          //128 byte header for liu's benefit

typedef struct {
  BYTE gain; // 8-bit gain at beak point
  WORD brk_pt; // break point depth (mm)
  BYTE dummy;
} TGC_TYPE;

typedef struct {
  WORD image_type;              //0 = linear, 1 = sector (phased array)
  union {
    float included_angle;       // sector image included angle (radians)
    float lateral_width;        // linear image lateral width (mm)
  } u;

  WORD ascans_per_image;        // number of A-scans per image
  WORD image_start;             // distance (mm) from center element to begin of ROI
  WORD image_stop;              // distance (mm) from center element to end of ROI
        /* NOTE: image_start/stop depend on image_type:
           linear - front and back border of box
           sector - inner and outer arcs of annulus
        */
  WPAIR tx_center;                   // line number for center of tx scan (0-79)
  WPAIR rx_center;                   // line number for center of rx scan (0-79)
  enum methods { array, motors} scan_method;
  WORD dwell_count;
  WORD nmbr_tgc;                                 // how may break points in test
  TGC_TYPE tgc[MAX_NMBR_BRKPTS];            // specifies max rx gain breakpoints
  char dummy[4];
} SCAN_CTL_TYPE;

typedef struct  {
  //MOTOR Control parameters
  WORD        stepper_motor_posn; // relates to moving sample
  WORD        stepper_motor_incr;
  WORD        stepper_motor_iter;
  WORD        dummy;
} MOTOR_CTL_TYPE ;

/*  2D-array system parameters */

#define MAXDIM  80
#define PITCH   0.6    //mm
#define FREQ    3.0    //MHz
#define BANDWIDTH 1.9  //MHz 60%
#define SPEED   1.501  //mm/microsec
#define RECT    101
#define CIRCLE  102
#define COSINE  103

#define MAX_NMBR_TX_CHANNELS 128  // allows F# = 3 from 0-90 mm
#define MAX_NMBR_RX_CHANNELS 16   // HW limit
#define MASTER_CLOCK 40           // (MHz)
#define RX_CLOCK_FACTOR  2
#define GAIN_CLOCK_FACTOR 8

typedef struct {
  float Xpitch;    // (mm)
  float Ypitch;
  float speed;
  float freq;
  float bw;
  float amp;
  WORD nmbr_array_elements;
  WORD tx_clock;                        // (MHz)
  WORD rx_clock_factor;
  WORD gain_clock_factor;
  char TxWaveFile[60];
  char AberCorrFile[60];          //;
  char ImpResFile[60];
  char RxImpResFile[60];
} SYSTEM_TYPE;                    //272 bytes

/*
  Overall Experiment Data Header
     - this information is defined prior to data acquisition
     - defines all aspects of data acquisition, focusing, &
       A-scan generation, EXCEPT those items that are controlled
       by user-supplied functions (e.g. apodization, RF demodulation) 
*/
#define COMMENTS 80              //length of experiment text comments buffer



typedef struct {

  BRIEF brief;                  // 128 bytes
  MOTOR_CTL_TYPE motor_info;    // 8  pointer to info for scatter experiment

  FOCUS_CTL_TYPE focus_ctl;     // 1336 focusing information

  SCAN_CTL_TYPE scan_ctl;       // 96  image boundaries/paramters

  SYSTEM_TYPE system;           // 272 2d-array paramters
  char comments[COMMENTS];      // 80 user comments
  char acq_date[16];            // 16 data acquisition date (mm/dd/yy)
  char process_date[16];        // 16 rf-to-A-scan processing date
  char scan_conv_date[16];      // 16 scan conversion date
  char AscanFile[80];           // Output File Name.
} TEST_HDR_TYPE;                // should be 2048 bytes

typedef TEST_HDR_TYPE *test_hdr; 

//
// should below member types be switched from INT16 to WORD ???
//

#include "rrh.h"
#include "afh.h"
#include "adh.h"


/*----------------------------
   Miscellaneous Structures
----------------------------*/


typedef struct {

  WPAIR tx_size;  

  WPAIR rx_size;  

  WPAIR tx_center; 

  WPAIR rx_center;
 
  WPAIR tx_incr;  

  WPAIR rx_incr;  
} ZONE_TYPE;
typedef ZONE_TYPE *zone_ptr;
  

// structure to a first order line equation
typedef struct {
  float slope;
  float offset;
} LINE;
       
typedef LINE* line_type; // pointer to a LINE struct

#endif



/*
  $Id: pe3.cpp 1.4 1998/07/09 16:17:13 LJB Exp LJB $
  $Revision: 1.4 $

  $Log: pe3.cpp $
  Revision 1.4  1998/07/09 16:17:13  LJB
  Added the record_index after the experiment header.
  The record_index points to the beginning of each raw data block.

  Revision 1.3  1998/06/29 13:39:27  LJB
  Working version left at UofR 6/26/98

  Revision 1.2  1998/05/13 14:51:47  LJB
  This should be a working version which does one Tx/Rx zone combination.

  Revision 1.1  1998/05/13 14:49:41  LJB
  Initial revision

  the third PE Experiment
  breaks the data collection into convenient pieces
 */



#define LJBDEV

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>  
#include <ctype.h>
#include <io.h>
#include <conio.h>
#include <new.h>
#include <assert.h>
#include <fstream.h>
#include <iomanip.h>
#include <string.h>
#include <complex>
#include <process.h>  
#include "2dcntrl.h"
#include "txaper.h"
#include "rxaper.h"
#include "sysgain.h"
#include "uas.h"
#include "uasaddr.h"
#include "array.h"
#include "sigpro.h"
#include "wpair.h"
#include "data.h"
#include "ascan.h"

/* Define hardware constants */
#if defined(LJBDEV)
  #define FILENAME "\\temp\\stepper.dat"  //File for moving motors
  #define TEMPFILE "\\temp\\temp.txt"     //File for reading temperature
#else  
  #define FILENAME "\\\\uas0\\uas0c\\temp\\stepper.dat"  //File for moving motors
  #define TEMPFILE "\\\\uas0\\uas0c\\temp\\temp.txt"     //File for reading temperature
  #define MOVING
// #define INVERSE_MOVING
#endif

// Objects needed for running the 2D-array
TTxAper *tx;
TRxAper *rx;
TwoDCntrlClass *pci = 0;
TwoDCntrlClass *initUAS(void);
SystemGain *sg;
SystemProps *ap;
TUas *uas;
TAscan *ascan;
ZoneData *fdata;

// Local Prototypes
void MoveScanner( float );
void CollectData( TTxAper *, TRxAper *, TUas *);      
WORD  load_defaults( TEST_HDR_TYPE *th);
WORD  init_header(TEST_HDR_TYPE *th, char *cfg_file);

int main( int argc, char *argv[]){
  int i,j;
  WPAIR txcenter, rxcenter;
  WORD num_tgc_breaks;
  WORD status,qq;
  FILE *fp;
  FILE *fp2=0, *fp4=0;
  FILE *fp5=0;
  int ia, nascans;
  int iz, nzones;

  int irec=0, nrec;
  long *record_index;

  char buf[80];
  TGC_TYPE tgc[MAX_NMBR_BRKPTS];

  float threshold=1.0;
  float tx_fn, rx_fn, speed;
  float ft1, ft2, temperature, ft4;

  int avg;
  int npts;

  float elev,r0,r1,r2;
  float azim;
  float f0;
  float bw;
  float phase;
  float amp;

  INT32 *data;

  if( argc < 3) {
    printf("Usage: pe3 <CFG_file> <OUT_file> [Raw-File] [Aberration_delay_file]\n");
    return(1);
  } 

  int q1 = sizeof(TEST_HDR_TYPE);
  int q2 = sizeof(MOTOR_CTL_TYPE);
  int q3 = sizeof(FOCUS_CTL_TYPE);
  int q4 = sizeof(SCAN_CTL_TYPE);
  int q5 = sizeof(SYSTEM_TYPE);
  int q6 = sizeof(RAW_RECORD_HEADER_TYPE);
  int q7 = sizeof(ASCAN_DATA_HEADER);
  int q8 = sizeof(ASCAN_FILE_HEADER);

  TEST_HDR_TYPE *th;
  th   = new TEST_HDR_TYPE;     assert(th);
 
  // Initializing the header using a CFG file
  fprintf(stdout,"Initializing Header using the CFG file %s...\n",argv[1]);
  status = init_header(th, argv[1]); 
  if( status) return status;                                   

  // Check to see if output file exists
  if( _access( argv[2], 0) == 0) {
    fprintf(stdout,
      "%s already exists.  Do you want to overwrite it? [y|N] ",
      argv[2]); 
    if( toupper(_getche()) != 'Y') {
      fprintf(stdout,
        "Try running this program again with a unique a32_file name\n");
      return ERR_EXIST;
    }
  }

  // open new a32 data file
  fp = fopen(argv[2], "wb");
  if( fp == NULL) return ERR_BMODE_FOPEN;

  ascan = new TAscan( th);
  ascan->WriteAscanFileHeader(fp);

  nascans = th->scan_ctl.ascans_per_image; 
  nzones  = th->focus_ctl.nmbr_zones;
  nrec = nzones*nascans;
  record_index = new long[nrec]; assert( record_index != 0);

    //Read the temperature
    fp4 = fopen(TEMPFILE,"rt");
    if (fp4 != 0){
      fscanf( fp4,"%f %f %f %f", &ft1, &ft2, &temperature, &ft4);
      fclose(fp4);
    }
	  else {
		  printf("Temp file not found, please enter t1 t2 t3 t4\n");
		  scanf("%f %f %f %f", &ft1, &ft2, &temperature, &ft4);
	  }

  fp2=0;
  if (argc >= 4){
    fp2 = fopen(argv[3],"wb");
    assert( fp2 != 0);
    //update the brief header
    th->brief.nAscans = th->scan_ctl.ascans_per_image;
    th->brief.nZones = th->focus_ctl.nmbr_zones;
    th->brief.Xpitch = (int)(0.5+th->system.Xpitch * 1000.);
    th->brief.Ypitch = (int)(0.5+th->system.Ypitch * 1000.);
    th->brief.F_sp = th->system.tx_clock / th->system.rx_clock_factor;
    th->brief.temp = (int)(100.*temperature);
    fwrite( th, sizeof(TEST_HDR_TYPE), 1, fp2);
    fwrite( record_index, sizeof(long), nrec, fp2);     //reserve the space
  }

  if (argc == 5){
    fp5 = fopen(argv[4],"rb");
    assert( fp5 != 0);
  }

  try{

    // Initialize Objects and Classes
    pci = initUAS();
    uas = new TUas();

    ap = new SystemProps();
#if defined(COMP)
    ap->SetImpResp(th->system.ImpResFile);
#endif
#if defined(ONE_WAY)
    ap->SetImpResp(th->system.ImpResFile);
    ap->SetRxImpResp(th->system.RxImpResFile);
#endif

    data = new INT32[2048];   assert( data !=0);

    avg            = th->scan_ctl.dwell_count;
    txcenter       = th->scan_ctl.tx_center;
    rxcenter       = th->scan_ctl.rx_center;
    num_tgc_breaks = th->scan_ctl.nmbr_tgc;
    for(j=0; j< num_tgc_breaks; j++) 
      tgc[j]       = th->scan_ctl.tgc[j];
    elev           = th->focus_ctl.elevation;
    azim           = th->focus_ctl.azimuth;
    f0             = th->system.freq; 
    bw             = th->system.bw; 
    phase          = 0.0; 
    amp            = th->system.amp;
    speed          = th->system.speed;

    //Setup the SystemGain
    sg = new SystemGain();
    sg->SetGainType(UGW);                                   //all channels setup
    float tgc_last_time = 2.0 * (float)tgc[num_tgc_breaks-1].brk_pt / speed; 
    sg->SetTimeWindow(0.0, tgc_last_time, 0.0);
    sg->InitBreakPoints();
    sg->SetTgcCurve( tgc, num_tgc_breaks);
    sg->LoadTgcWaves();



    float image_width = th->scan_ctl.u.lateral_width;
    float pos_inc = image_width / (float)(nascans -1);
    float Position_0= -image_width/2.;
    float Position_mm;

    for( ia = 0; ia < nascans; ia++){ 
      Position_mm = Position_0 + (float)ia * pos_inc;
      MoveScanner( Position_mm);

      for( iz =0; iz < nzones; iz++){

        // Unload zone dependent info from the experiment header to locals
        r0             = th->focus_ctl.focus_start[iz];
        r1             = th->focus_ctl.focus_depth[iz];
        r2             = th->focus_ctl.focus_stop[iz];
        tx_fn          = th->focus_ctl.tx_fnum[iz];
        rx_fn          = th->focus_ctl.rx_fnum[iz];

        //Setup the TxAperture
        tx  = new TTxAper(); 
        qq = (WORD)tx->CalcAperSize( r1, tx_fn);
        WPAIR txSize = WPAIR( qq,qq);
        int tx_area = qq*qq;
        tx->SetupAper( CTW, txSize);
        tx->SetWaveSize( txSize);
        tx->SetCenterEl(txcenter);
#if defined(COS_APOD)
        tx->CalcApodization( COSINE);
#endif
#if defined(RECT_APOD)
		tx->CalcApodization( RECT);
#endif
        tx->range0 = r0;
        tx->range1 = r1;
        tx->CalcDelays( r1, elev, azim);
        if( fp5 != 0) tx->FillAberrationDelays( fp5);
        tx->SetWaveforms( f0, bw, phase, amp);

/*  LJB 09/25/98 Just to have a look at the Tx waveforms
		FILE *fp6;
		fp6 = fopen("txtest.raw","wb");
		tx->WriteRawAperture( fp6);
		fclose(fp6);
*/


        //Setup the RxAperture this is pe3 
        rx = new TRxAper();
        qq = (WORD)rx->CalcAperSize( r2, rx_fn);
        WPAIR rxSize = WPAIR(qq,qq);
        rx->SetupAper( CGW, rxSize);
        rx->SetWaveSize( rxSize);
        rx->SetCenterEl(rxcenter);
        rx->SetAvgCount(avg);
        float t_start = 2. * r0 /speed;
        float t_stop = 2. * r2 / speed;
        if(fp5!=0) rx->FillAberrationDelays( fp5);
        rx->range0 = r0;
        rx->range1 = r2;
        rx->SetUpWaveforms( t_start, t_stop);
        rx->SetTimeCenter( tx->delay_center);
#if defined(COS_APOD)
        rx->CalcApodization( COSINE);
#endif
#if defined(RECT_APOD)
		rx->CalcApodization( RECT);
#endif

  
        // Perform element compensation on TxWaveforms
#if defined(COMP)
        tx->Compensate( ap);
#endif
#if defined(ONE_WAY)
		tx->Compensate( ap);
#endif
        // Collect data
        CollectData( tx, rx, uas);

        // Post-Process data
#if defined(COMP)
        rx->Compensate( ap);
#endif
#if defined(ONE_WAY)
		rx->RxCompensate( ap );
#endif
        // Time shift waveforms
//        rx->ShiftWaveforms();

        if (fp2 != 0) {
          record_index[irec++] = ftell(fp2);                   //fill the index
          rx->WriteRawAperture( ia, iz, temperature, tx, fp2);
        }

        rx->Focus( tx->GetCenterFreq(), tx_area );
        npts = rx->GetNumFocusedPoints();    assert( npts <= 2048);
        rx->GetFocusedData( data);
        ascan->SetZoneData( iz, npts, data);
        delete tx; delete rx;
      }     //end of zone loop
      ascan->zoneavg(th);
      ascan->WriteAscan32(ia,fp);
    }     //end of ascan loop
  }
  catch(PCIClassErr err){
    printf(err.msg);
    exit(1);
  }

  fclose(fp);
  if (fp2 != 0){
    fseek( fp2, 0L, SEEK_SET);                      //rewind
    fwrite( th, sizeof(TEST_HDR_TYPE), 1, fp2);     //re-write the experiment header
    fwrite( record_index, sizeof(long), nrec, fp2); //write index for real
    fclose(fp2);
  }
  if (fp5 != 0) fclose(fp5);
  delete[] record_index;
  delete[] data;
  delete th; 
//  delete ascan; 
  delete uas; 
  delete ap;  
  delete sg; 
  return(0);

}

#include <dos.h>
void CollectData( TTxAper *tx, TRxAper *rx, TUas *uas){
  MuxTwoDType mt;
  WPAIR c0,c1;
  int itx, irx, ic, count;

  WPAIR TxSubs = tx->GetNumSubs();
  WPAIR RxSubs = rx->GetNumSubs();
  int n_TxSubs = area(TxSubs);
  int n_RxSubs = area(RxSubs);

  WPAIR tx_center = tx->GetCenterEl();
  WPAIR rx_center = rx->GetCenterEl();
  WPAIR tx_size = tx->GetAperSize();
  WPAIR rx_size = rx->GetAperSize();
  WPAIR l_tx_corner = tx_center - tx_size/2;
  WPAIR l_rx_corner = rx_center - rx_size/2;
  WPAIR p_tx_c0, p_tx_c1;
  WPAIR p_rx_c0, p_rx_c1;

//  printf("Collecting data for %d TxSubs and %d RxSubs\n", n_TxSubs, n_RxSubs);
//  printf("tx_center = %3d:%3d\n",X(tx_center),Y(tx_center));
//  printf("rx_center = %3d:%3d\n",X(rx_center),Y(rx_center));
  rx->ClearWaveforms();

  count = rx->GetAvgCounts();
  for(itx = 0; itx<n_TxSubs; itx++){
    printf("\nTxSub %3d of %3d\n",itx, n_TxSubs);
    c0 = tx->GetCorner0(itx);
    c1 = tx->GetCorner1(itx);

    p_tx_c0 = l_tx_corner+c0;
    p_tx_c1 = l_tx_corner+c1;

    TBool TxFlag = tx->LoadMT( &mt, p_tx_c0, p_tx_c1);
    if( TxFlag == bTRUE){
      tx->LoadBuffer( p_tx_c0, p_tx_c1, c0, c1);
      for(irx = 0; irx < n_RxSubs; irx++){
        c0 = rx->GetCorner0(irx);
        c1 = rx->GetCorner1(irx);

        p_rx_c0 = l_rx_corner+c0;
        p_rx_c1 = l_rx_corner+c1;

/* sanity check dp 0811 09feb99
      printf("RxSub %3d of %3d\n",irx, n_RxSubs);
      printf(" c0: logical = (%3d,%3d)  physical = (%3d,%3d)\n",   
        X(c0), Y(c0), X(p_rx_c0), Y(p_rx_c0));
      printf(" c1: logical = (%3d,%3d)  physical = (%3d,%3d)\n", 
        X(c1), Y(c1), X(p_rx_c1), Y(p_rx_c1));
 */
        TBool RxFlag = rx->LoadMT( &mt, p_rx_c0, p_rx_c1);

        if (RxFlag == bTRUE){ 

          //Load the Multiplexer
#if defined(HW_AVAIL)
          if(pci) pci->MuxConfig(mt); 
#endif
          for (ic =0 ; ic < count; ic++){
            uas->fire();          // Fire the pulser
            uas->FineDelay(200);
            rx->UnLoadBuffer( ic, p_rx_c0, p_rx_c1, c0, c1 );
          }
        } // endif RxFlag
      }  //Next RxSubAperture
    } //endif TxFlag
  }  //Next TxSubAperture
  rx->RemoveBias();
}  //End of the Collection routine

void MoveScanner( float Position){
    FILE *fp3=0;
#if defined(MOVING)
    //Do something here to move the array
      int BoardID=1, Axis=1, relative=0;

    fp3=fopen(FILENAME,"wt");
    fprintf(fp3,"%d \tBoardID\n",BoardID);
    fprintf(fp3,"%d \tAxis\n",Axis);

    fprintf(fp3,"%f \tPosition_mm\n",Position);
    fprintf(fp3,"%d \trelative\n",relative);
    fclose(fp3);

    // wait while file is still there
    while (access(FILENAME,0)==0)
    {
    if (kbhit())
      break;
    Sleep(10);  // wait 1/100 sec
    } 
    // Move should be done

#if defined(INVERSE_MOVING)
    BoardID=2;

    fp3=fopen(FILENAME,"wt");
    fprintf(fp3,"%d \tBoardID\n",BoardID);
    fprintf(fp3,"%d \tAxis\n",Axis);

    fprintf(fp3,"%f \tPosition_mm\n",-Position_mm);  // move to inverse direction
    fprintf(fp3,"%d \trelative\n",relative);
    fclose(fp3);

    // wait while file is still there
    while (access(FILENAME,0)==0)
    {
    if (kbhit())
      break;
    Sleep(10);  // wait 1/100 sec
    } 
    // Move should be done

#endif // defined(INVERSE_MOVING)
#endif //defined(MOVING)
}

Software written by
Larry Busse of LJB Development
and Bill Glenn, Al Murphy and John Losche of TETRAD Corporation
Documentation generated 3/11/1999