Author Topic: Home Brew Analog Computer System  (Read 45958 times)

0 Members and 1 Guest are viewing this topic.

Offline AlfBaz

  • Super Contributor
  • ***
  • Posts: 1714
  • Country: au
Re: Home Brew Analog Computer System
« Reply #150 on: July 22, 2013, 12:12:41 PM »
Hi GK great thread, I also follow your work with great interest.

On the subject of front panels, have you considered laser cutting services? I was just looking and found quite a few that were reasonable, especially if you can get away with plastic. If shielding is an issue it may still be more viable to simply line the inside of a plastic panel with foil. Given that they can not only cut holes of whatever shape but may also be able to do 2 tone legend engraving

Just a thought

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #151 on: July 23, 2013, 12:13:34 AM »
Just seen this post on tekscopes about capacitor probems etc.

http://www.maximintegrated.com/app-notes/index.mvp/id/5663


Dunno if anyone is going to get stroppy over copyright on these old texts, but here is a bit on capacitor leakage and dielectric absorption from Computer Handbook Huskey & Korn, and Electronic Analog and Hybrid Computers, Korn & Korn. Numerous other ancient texts cover the same ground too.

I'm sorry to say it but Bob Pease was a little late to the party on this one.

« Last Edit: July 23, 2013, 12:15:15 AM by GK »

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #152 on: July 23, 2013, 12:21:06 AM »
Hi GK great thread, I also follow your work with great interest.

On the subject of front panels, have you considered laser cutting services? I was just looking and found quite a few that were reasonable, especially if you can get away with plastic. If shielding is an issue it may still be more viable to simply line the inside of a plastic panel with foil. Given that they can not only cut holes of whatever shape but may also be able to do 2 tone legend engraving

Just a thought


Thanks, but I'm not sure that plastic would be strong enough; especially so to support the weight of each "modular" chassis. Another thing is that the entire composite rack system front panel serves as a ground plane for my signal ground.

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #153 on: July 23, 2013, 01:16:09 AM »
Well, finally, here is the Lorenz Attractor in 3-D projection with variable angles of rotation (the 3-D projection unit in action). I have to say that I am quite happy with the way the synthesized sine/cosine potentiometers worked out with the 8-bit digital pots and the sine/cosine look up table. The 1 degree step resolution and 8-bit accuracy gives a fluid variation in display that is, for all sakes and purposes, totally analog as far as I as the operator can discern. In all honesty the Lorenz Attractor probably isn't the best 3-D "object" to demonstrate the operation of the projection unit, as it is a bit complex and an interpretation of the display isn't intuitively obvious as it is with simpler shapes and objects, such as the assorted springs I posted screen photos of a few posts previously.   



Here is a simplified schematic of  the initial, prototype projection unit. It is based on the basic 3-D projection principle outlined in chapter 9 (Multi-Dimensional Displays) of Analog Computing At Ultra High Speed, D M.MacKay, M E. Fischer.




I have made a significant improvement to the above described 3D projection unit. The unit as shown above is only capable of rotating the projection on both the X and Y axes over the range of 0 to 90 degrees. This is quite adequate an adjustable range for graphs and shapes in isometric projection, which are typically shown at a "perspective" of 45 degrees. However I figured that it would be a lot cooler if the projection unit could in fact spin the projected display on either axis the full 360 degrees.

The reason the design detailed above is limited to 0-to-90 degree range is that the digital pots connected as potential dividers (to implement the necessary sine and cosine multiplications) can only effectively multiply in two quadrants (the positive ones) as the range of multiplication of the applied input signal is limited to the range of 0 to 1. Now while 2 quadrants of operation for either a sine or cosine function on its own represents a 180 degree range of rotation, the range is in fact limited 90 degrees when a sine/cosine complement is generated as only a 90 degrees of variation is achievable before one function hits its limit at the point of transition into an off-limits negative quadrant.

However I figured out a simple way to achieve the full 4-quadrant range of operation with each digital pot, thus eliminating the above described restriction and permitting a full 360 degree range of variable rotation on each axis. It's quite simple really. I just followed each of the 8 digital pots implementing the sine and cosine multiplication functions with an individual "amplifier" having a gain of either 1 or -1, depending on the state of a logic control input. The range of multiplication is thus extended from 1 to 0, to 1 to -1, simply by asserting the logic control line to switch the amplifier from a gain of 1 to -1 whenever operation in the negative quadrants are required.

Here is a video of the resultant prototype in action. At the moment the angles of rotation are not manually variable/settable as they were previously as I haven't gotten that far with the code yet. I just wrote a test subroutine to linearly and continuously rotate the projected display on each axis the full 0-to-360 degrees at a fixed and steady rate (one axis rotating twice as fast at the other). Once again the "object" being displayed is the Rössler Attractor: 




Cool, huh?  ;D

 

 




« Last Edit: July 23, 2013, 01:22:20 AM by GK »

Offline Odysseus

  • Regular Contributor
  • *
  • Posts: 107
  • Country: us
Re: Home Brew Analog Computer System
« Reply #154 on: July 23, 2013, 08:02:24 AM »
Damn right it's cool.

Give us a heads up when you try attacking the N-body problem.  :-+
« Last Edit: July 23, 2013, 08:04:30 AM by Odysseus »

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #155 on: July 24, 2013, 07:12:18 PM »
N-body problem.  :-+



I looked it up and the some of the equations looked quite scary!
 

Offline Odysseus

  • Regular Contributor
  • *
  • Posts: 107
  • Country: us
Re: Home Brew Analog Computer System
« Reply #156 on: July 25, 2013, 12:06:38 PM »
Could you simulate a single moving mass orbiting a fixed gravitational center?  Just F=ma and F=m1*m2/r^2.  In vector form for more dimensions than one.

Then try a two body system where you have two moving masses pulling on each other.

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #157 on: August 04, 2013, 01:08:34 AM »
  Such a problem may probably best be broken down into something simple and then built upon. Really don't have much time to devote to that now though! Thoroughly stuck into the computers hardware construction right now.


--------------------------------------------------------------------------------------------------------------------


BTW, could anyone suggest to me a more elegant way of converting a long integer (value ranging 0 to 360) into three seperate decimals (0 to 9) (hundreds [xh], tens [xt] and units [xu])? It should probably be obvious but it is getting close to 1am now.

I've added digital readouts (7-segment LED) for the variable angles of rotation to my 3-D projection unit. The code and hardware is done and operational, but I am now tidying it up the firmware and annotating.

Here is how I am currently doing it:

   
xh = abs(angle_of_rotation_X_axis / 100);
xt = angle_of_rotation_X_axis - (xh * 100);
xu = xt - 10 * (abs(xt / 10));
xt = abs(xt / 10);
   

Offline baljemmett

  • Supporter
  • ****
  • Posts: 665
  • Country: gb
Re: Home Brew Analog Computer System
« Reply #158 on: August 04, 2013, 03:54:22 AM »
BTW, could anyone suggest to me a more elegant way of converting a long integer (value ranging 0 to 360) into three seperate decimals (0 to 9) (hundreds [xh], tens [xt] and units [xu])? It should probably be obvious but it is getting close to 1am now.

One approach is to convert to BCD, then mask off nibbles - if you happen to have a library function for that, or an app note with efficient code for your uC (I presume this is in the 'pretend pot' firmware?), that might be reasonably elegant.

Another way to avoid the hit of the division and multiplication is to loop over it:

Code: [Select]
unsigned int input = 276;
char hundreds = 0, tens = 0, units = 0;

while (input >= 100)
{
    hundreds++;
    input -= 100;
}

while (input >= 10)
{
    tens++;
    input -= 10;
}

units = input;

/* should now have hundreds = 2, tens = 7, units = 6 */

Crude, but it's been effective for me in the past - faster than doing division with the library functions, at any rate.

Offline Chalky

  • Regular Contributor
  • *
  • Posts: 86
  • Country: nz
Re: Home Brew Analog Computer System
« Reply #159 on: August 04, 2013, 07:16:20 AM »
BTW, could anyone suggest to me a more elegant way of converting a long integer (value ranging 0 to 360) into three seperate decimals (0 to 9) (hundreds [xh], tens [xt] and units [xu])? It should probably be obvious but it is getting close to 1am now.
Hi there, I don't know your language, am assuming some sort of embedded C, but if you have a MOD operator or function available then you could so an equivalent of this VB.NET code (works with either positive or negative angle, just returns absolute digit):
Sub Main()
        Dim angle_of_rotation_X_axis As Long = -359
        Dim xh As Short = GetDigit(angle_of_rotation_X_axis, 100)
        Dim xt As Short = GetDigit(angle_of_rotation_X_axis, 10)
        Dim xu As Short = GetDigit(angle_of_rotation_X_axis, 1)
    End Sub

    Function GetDigit(value As Long, unit As Integer) As Short
        Return CShort(Int((Abs(value) Mod unit * 10) / unit))
    End Function
Cheers.

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #160 on: August 05, 2013, 08:01:45 PM »
OK, thanks for the replies. The language is C; code for a PIC uC using "Custom computer services" (CCS) PIC-C compiler.
Yes, it for my "pretend pot" firmware of the 3-D projection unit. I've written a lot of PIC C firmware but I am far from a professional code writer. Here is the complete program. It's functional and I think relatively tidy, but those who program for a living may very well see things that could be done better.
Also attached is the complete schematic of the final unit.

Quote

//   3-D PROJECTION UNIT
//   DATE         AUGUST/2013
//   AUTHOR      Glen Kleinschmidt
// VERSION      1.0
// DEVICE      PIC16F874


// ROM used: 1533 (37%)
// Largest free fragment is 2048
// RAM used: 24 (13%) at main() level
// 131 (69%) worst case


#include <16f874.h>
#device  ADC=10
#use delay(clock=4000000)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
#use standard_io(D)
#FUSES HS,NOWDT,PUT,NOPROTECT,NOLVP,NOCPD,NOWRT,BROWNOUT


long int       angle_of_rotation_X_axis;
long int       angle_of_rotation_Y_axis;

int            address;
int            data;
int            shift;

int            xh;
int            xt;
int            xu;

int            yh;
int            yt;
int            yu;

int            sine_X;
int            cosine_X;

int            sine_Y;
int            cosine_Y;

short int      polarity_sine_X;
short int      polarity_cosine_X;

short int      polarity_sine_Y;
short int      polarity_cosine_Y;


read_angle_of_rotation_potentiometers(void)
{
   SET_ADC_CHANNEL(0);                                      // Set ADC MUX to channel 0 (pin RA0)
   delay_us(100);                                           // Wait for ADC-input MUX to settle
   angle_of_rotation_X_axis = (READ_ADC() / 2.8);           // Read X-rotation potentiometer(s) position and scale

   SET_ADC_CHANNEL(1);                                      // Set ADC MUX to channel 1 (pin RA1)
   delay_us(100);                                           // Wait for ADC-input MUX to settle
   angle_of_rotation_Y_axis = (READ_ADC() / 2.8);           // Read Y-rotation potentiometer(s) position and scale

   if (angle_of_rotation_X_axis > 360)                      // Limit X value (0-to-360 degrees)
   angle_of_rotation_X_axis = 360;                          //

   if (angle_of_rotation_Y_axis > 360)                      // Limit Y value (0-to-360 degrees)
   angle_of_rotation_Y_axis = 360;                          //
}


seven_segment_display_decode(void)
{
   int   sevenseg[10] = {2,158,36,12,152,72,192,30,0,24};   // Look-up table for 7-segment LED display decode

   xh = abs(angle_of_rotation_X_axis / 100);                // Decode decimal values (hundreds, tens & units)
   xt = angle_of_rotation_X_axis - (xh * 100);              // for X-axis angle-of-rotation digital display
   xu = xt - 10 * (abs(xt / 10));                           //
   xt = abs(xt / 10);                                       //

   yh = abs(angle_of_rotation_Y_axis / 100);                // Decode decimal values (hundreds, tens & units)
   yt = angle_of_rotation_Y_axis - (yh * 100);              // for Y-axis angle-of-rotation digital display
   yu = yt - 10 * (abs(yt / 10));                           //
   yt = abs(yt / 10);                                       //

   xh = sevenseg[xh];                                       // 3-digit 7-segment decode for X-axis angle-of-rotation display
   xt = sevenseg[xt];                                       //
   xu = sevenseg[xu];                                       //

   yh = sevenseg[yh];                                       // 3-digit 7-segment decode for Y-axis angle-of-rotation display
   yt = sevenseg[yt];                                       //
   yu = sevenseg[yu];                                       //

   output_low(pin_D4);                                      // Digital display digit latch lines low
   output_low(pin_D5);                                      //
   output_low(pin_D6);                                      //
   output_low(pin_D7);                                      //
   output_low(pin_B0);                                      //

   output_b(yu);                                            // Set "units" digit latch for Y-axis angle-of-rotation
   output_high(pin_B0);                                     //
   output_low(pin_B0);                                      //

   output_b(yt);                                            // Set "tens" digit latch for Y-axis angle-of-rotation
   output_high(pin_D7);                                     //
   output_low(pin_D7);                                      //

   output_b(yh);                                            // Set "hundreds" digit latch for Y-axis angle-of-rotation
   output_high(pin_D6);                                     //
   output_low(pin_D6);                                      //

   output_b(xu);                                            // Set "units" digit latch for X-axis angle-of-rotation
   output_high(pin_D5);                                     //
   output_low(pin_D5);                                      //

   output_b(xt);                                            // Set "tens" digit latch for X-axis angle-of-rotation
   output_high(pin_D4);                                     //
   output_low(pin_D4);                                      //

   output_b(xh);                                            // Put "hundreds" digit on 7-segment data bus
}


sincostable(void)
{
   int   sincos[91] = {0,  4,  8,  13, 17, 22, 26, 31, 35, 39,    // Look-up table for sine and cosine trig. function
                       44, 48, 53, 57, 61, 65, 70, 74, 78, 83,
                       87, 91, 95, 99, 103,107,111,115,119,123,
                       127,131,135,138,142,146,149,153,156,160,
                       163,167,170,173,177,180,183,186,189,192,
                       195,198,200,203,206,208,211,213,216,218,
                       220,223,225,227,229,231,232,234,236,238,
                       239,241,242,243,245,246,247,248,249,250,
                       251,251,252,253,253,254,254,254,254,254,
                       255};

   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   if (angle_of_rotation_X_axis <= 360)                     // Read sine(x) table value for 271-to-360 degree segment
   {                                                        // Inverting for this segment (0 = true)
      sine_X = sincos[360 - angle_of_rotation_X_axis];      //
      polarity_sine_X = 0;                                  //
   }                                                        //

   if (angle_of_rotation_X_axis <= 270)                     // Read sine(x) table value for 181-to-270 degree segment
   {                                                        // Inverting for this segment (0 = true)
      sine_X = sincos[angle_of_rotation_X_axis - 180];      //
      polarity_sine_X = 0;                                  //
   }                                                        //

   if (angle_of_rotation_X_axis <= 180)                     // Read sine(x) table value for 91-to-180 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      sine_X = sincos[180 - angle_of_rotation_X_axis];      //
      polarity_sine_X = 1;                                  //
   }                                                        //

   if (angle_of_rotation_X_axis <= 90)                      // Read sine(x) table value for 0-to-90 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      sine_X = sincos[angle_of_rotation_X_axis];            //
      polarity_sine_X = 1;                                  //
   }                                                        //

   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   if (angle_of_rotation_X_axis <= 360)                     // Read cosine(x) table value for 271-to-360 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      cosine_X = sincos[angle_of_rotation_X_axis - 270];    //
      polarity_cosine_X = 1;                                //
   }                                                        //

   if (angle_of_rotation_X_axis <= 270)                     // Read cosine(x) table value for 181-to-270 degree segment
   {                                                        // Inverting for this segment (0 = true)
      cosine_X = sincos[270 - angle_of_rotation_X_axis];    //
      polarity_cosine_X = 0;                                //
   }                                                        //

   if (angle_of_rotation_X_axis <= 180)                     // Read cosine(x) table value for 91-to-180 degree segment
   {                                                        // Inverting for this segment (0 = true)
      cosine_X = sincos[angle_of_rotation_X_axis - 90];     //
      polarity_cosine_X = 0;                                //
   }                                                        //

   if (angle_of_rotation_X_axis <= 90)                      // Read cosine(x) table value for 0-to-90 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      cosine_X = sincos[90 - angle_of_rotation_X_axis];     //
      polarity_cosine_X = 1;                                //
   }                                                        //

   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   if (angle_of_rotation_Y_axis <= 360)                     // Read sine(y) table value for 271-to-360 degree segment
   {                                                        // Inverting for this segment (0 = true)
      sine_Y = sincos[360 - angle_of_rotation_Y_axis];      //
      polarity_sine_Y = 0;                                  //
   }                                                        //

   if (angle_of_rotation_Y_axis <= 270)                     // Read sine(y) table value for 181-to-270 degree segment
   {                                                        // Inverting for this segment (0 = true)
      sine_Y = sincos[angle_of_rotation_Y_axis - 180];      //
      polarity_sine_Y = 0;                                  //
   }                                                        //

   if (angle_of_rotation_Y_axis <= 180)                     // Read sine(y) table value for 91-to-180 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      sine_Y = sincos[180 - angle_of_rotation_Y_axis];      //
      polarity_sine_Y = 1;                                  //
   }                                                        //

   if (angle_of_rotation_Y_axis <= 90)                      // Read sine(y) table value for 0-to-90 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      sine_Y = sincos[angle_of_rotation_Y_axis];            //
      polarity_sine_Y = 1;                                  //
   }                                                        //

   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   if (angle_of_rotation_Y_axis <= 360)                     // Read cosine(y) table value for 271-to-360 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      cosine_Y = sincos[angle_of_rotation_Y_axis - 270];    //
      polarity_cosine_Y = 1;                                //
   }                                                        //

   if (angle_of_rotation_Y_axis <= 270)                     // Read cosine(y) table value for 181-to-270 degree segment
   {                                                        // Inverting for this segment (0 = true)
      cosine_Y = sincos[270 - angle_of_rotation_Y_axis];    //
      polarity_cosine_Y = 0;                                //
   }                                                        //

   if (angle_of_rotation_Y_axis <= 180)                     // Read cosine(y) table value for 91-to-180 degree segment
   {                                                        // Inverting for this segment (0 = true)
      cosine_Y = sincos[angle_of_rotation_Y_axis - 90];     //
      polarity_cosine_Y = 0;                                //
   }                                                        //

   if (angle_of_rotation_Y_axis <= 90)                      // Read cosine(y) table value for 0-to-90 degree segment
   {                                                        // Non-inverting for this segment (1 = false)
      cosine_Y = sincos[90 - angle_of_rotation_Y_axis];     //
      polarity_cosine_Y = 1;                                //
   }                                                        //

   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}


RDACclock(void)                           // Strobe digipot clock line
{
   delay_us(100);
   output_high(pin_C1);
   delay_us(100);
   output_low(pin_C1);
   delay_us(100);
}


RDACaddress(void)                         // Shift the 3 address bits to digipot data line
{
   for (shift=0; shift<3; shift++)
   {
      output_bit(pin_C2, bit_test(address, 2 - shift));
      RDACclock();
   }
}


RDACdata(void)                            // Shift the 8 data bits to the digipot data line
{
   for (shift=0; shift<8; shift++)
   {
      output_bit(pin_C2, bit_test(data, 7 - shift));
      RDACclock();
   }
}


set_digital_potentiometers(void)
{
   output_low(pin_C0);                    // !CS low to initiate data transfer
   address = 0;                           // Set address for RDAC1
   RDACaddress();                         // Send the 3 address bits
   data = cosine_Y;                       // Set data value to cosine_Y
   RDACdata();                            // Send the 8 data bits
   RDACaddress();                         // Send the next daisy-chained 3 address bits
   data = cosine_X;                       // Set data value to cosine_X
   RDACdata();                            // Send the next daisy-chained 8 data bits
   output_high(pin_C0);                   // !CS high to complete data transfer

   delay_us(200);

   output_low(pin_C0);                    // !CS low to initiate data transfer
   address = 1;                           // Set address for RDAC2
   RDACaddress();                         // Send the 3 address bits
   data = sine_Y;                         // Set data value to sine_Y
   RDACdata();                            // Send the 8 data bits
   RDACaddress();                         // Send the next daisy-chained 3 address bits
   data = sine_X;                         // Set data value to sine_X
   RDACdata();                            // Send the next daisy-chained 8 data bits
   output_high(pin_C0);                   // !CS high to complete data transfer

   delay_us(200);

   output_low(pin_C0);                    // !CS low to initiate data transfer
   address = 2;                           // Set address for RDAC3
   RDACaddress();                         // Send the 3 address bits
   data = sine_Y;                         // Set data value to sine_Y
   RDACdata();                            // Send the 8 data bits
   RDACaddress();                         // Send the next daisy-chained 3 address bits
   data = sine_X;                         // Set data value to sine_X
   RDACdata();                            // Send the next daisy-chained 8 data bits
   output_high(pin_C0);                   // !CS high to complete data transfer

   delay_us(200);

   output_low(pin_C0);                    // !CS low to initiate data transfer
   address = 3;                           // Set address for RDAC4
   RDACaddress();                         // Send the 3 address bits
   data = cosine_Y;                       // Set data value to cosine_Y
   RDACdata();                            // Send the 8 data bits
   RDACaddress();                         // Send the next daisy-chained 3 address bits
   data = cosine_X;                       // Set data value to cosine_X
   RDACdata();                            // Send the next daisy-chained 8 data bits
   output_high(pin_C0);                   // !CS high to complete data transfer
}


set_sinecos_polarity(void)
{
   output_bit(pin_D1, bit_test(polarity_sine_X,   0));   // Connect polarity status to sine(x) amplifiers
   output_bit(pin_D2, bit_test(polarity_cosine_X, 0));   // Connect polarity status to cosine(x) amplifiers
   output_bit(pin_C3, bit_test(polarity_sine_Y,   0));   // Connect polarity status to sine(y) amplifier
   output_bit(pin_D0, bit_test(polarity_cosine_Y, 0));   // Connect polarity status to cosine(y) amplifier
}


MAIN()
{
   SETUP_ADC_PORTS(RA0_RA1_ANALOG_RA3_RA2_REF);    // Define ADC inputs: RA0 & RA1=inputs, RA2= -Vref, RA3= +Vref)
   SETUP_ADC(ADC_CLOCK_DIV_32);                    // Connect ADC internal clock

   loop:

      read_angle_of_rotation_potentiometers();     // This routine reads the X & Y angle-of-rotation potentiometers
      seven_segment_display_decode();              // This routine sets the digital display of the angles of rotation
      sincostable();                               // This routine sets the sine and cosine values for the digipots
      set_digital_potentiometers();                // This routine programs the digipots (daisy-chained serial)
      set_sinecos_polarity();                      // This routing sets the switchable inverting/non inverting
                                                   // amplifiers as required for 4-quadrant sine/cosine multiplication

   goto loop;                                      // Play it again Sam!
}

Here is the completed unit:


« Last Edit: August 05, 2013, 08:07:45 PM by GK »

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #161 on: August 05, 2013, 08:11:05 PM »
Here is a video of the unit in action, with a full 360 degrees of variable rotation of both X and Y axes. Once again I am using my Rössler Attractor signal generator as the source. I'm currently laying out a PCB for that one will post up the circuit details when done.


Online mamalala

  • Supporter
  • ****
  • Posts: 724
  • Country: de
Re: Home Brew Analog Computer System
« Reply #162 on: August 06, 2013, 01:52:15 AM »
Hi Glen,

there are a few things you can do to improve the code wrt. the table-lookup, avoiding a lot of calculations and stuff. It is a tradeoff between ROM/FLASH usage for the table on one side, and codesize & execution speed on the other side. But since you are using the table a lot with lots of code calculating it, i guess the overall ROM/FLASH used will be less, plus a faster processing speed.

First, make the lookup-table 256 entries large. The native data size of the PIC is 8 bits, using that as table size allows for some really fast methods for reversing the lookup direction and inverting the value.

Then, the PIC has a 10-bit ADC. Use that! This will make things even simpler. To store the result, the PIC uses two registers, ADRESL and ADRESH. Configure the ADC to give you a right-justified result. (register ADCON1 bit ADFM set to 1). This will result in the lower 8 bits of the readout to be stored in ADRESL, and the upper 2 bits into the lower 2 bits of ADRESH.

The effect of this is that in ADRESH you get only the value 0, 1, 2 or 3 over the full range. Now, 4 values, 4 quadrants, a table with 256 entries and a ADRESL of 8 bits... I guess you can already start to see where this goes.

Now about how to access it using simple methods and the ADRESH bits of the result. The lookup table contains the first 90° of a sinewave here. If you invert the index value, you read that table backwards. That way you now have 180°. To decide wether to read forwards or backwwards, you use bit 0 of ADRESH. If it is set, you simply invert the index into the table.

In code this would look something like this:

Code: [Select]
if (ADRESH & 0x01)
{
    result = sintab[~ADRESL];
}
else
{
    result = sintab[ADRESL];
}

Now for the inverting of the read value of the lookup. You use bit 1 of ADRESL to do that. If it set to 1, you simply invert the value you just read from the lookup-table. Again, in code this looks like:

Code: [Select]
if (ADRESH & 0x02)
{
    result = ~result;
}

OK, this was just for sine lookup from the table. The bits of ADRESH for those 4 quadrants in sequence look like this:

Code: [Select]
00000000 - first sine quadrant
00000001 - second sine quadrant
00000010 - third sine quadrant
00000011 - fourth sine quadrant

Which is, of course, also the same sequence you get in ADRESH in 10 bit ADC mode when going from 0 to maximum.

If you want to read a cosine instead, you simply add 1 to ADRESH. The resulting sequence of ADRESH will then be:

Code: [Select]
00000001
00000010
00000011
00000100

This is OK because only the lowest two bits are evaluated anyways. Now, if you want to have the full sine or cosine inverted, you simply add another 2 to ADRESH. Doing all the above allows you to write a single routine that does this. With a little more bit-magic the polarity bits that you use to control the actual output can also be set. You can also combine those bits into a single byte instead of spreading it over four int's. There is the nifty thing of #define, which allows you to define things with a name.

Attached is a textfile with some ad-hoc example code of all that with lots of comments. Of course not tested for bugs, just to show you the overall process. Hope that helps. If you have any questions, let me know.

Greetings,

Chris

Online mamalala

  • Supporter
  • ****
  • Posts: 724
  • Country: de
Re: Home Brew Analog Computer System
« Reply #163 on: August 06, 2013, 02:56:11 AM »
What i forgot to mention. In my example i do invert the readout value _and_ set the negative-polarity bit. I just assumed that when you toggle the output pin that the DAC output is inverted after the OpAmps, that is 5V input becomes 0V and 0V input becomes -5V output when negative, while for the positive half 5V in becomes 5V out, and 0V in becomes 0V out (just as an example). If that is not the case, simple comment out the "result = ~result" line there.

Also, note that due to the way the lookuptable is read, the first and last value in it are duplicated at each start/end of a quadrant. That is, for example, the zero-crossing at 180° will become 0 at an ADC value of 511 (end of second quadrant) but also 0 at a ADC value of 512 (start of third quadrant). There are two ways to eliminate that error. One is to create the table so there is no 0° and 90°. So the sequence instead of, for example, 8-4-0 0-4-8 becomes 10-6-2 2-6-10. Another way is to limit the maximum value in the table, and then add a fixed value if you go negative. So if the sequence from the table would be 8-4-0 0-4-8 you simply add 4 if negative, and get 8-4-0 4-8-12 instead. Of course this means that the maximum value can not be 255 but must be 251 instead, to avoid an overflow when adding 4.

Personally i would prefer the first method. This ensures that the generated quadrants are symetrical. And at 8 bits for one quadrant you have a resolution of roundabout 0.35°, so the small "error" of not having complete 0° or 90° is just roundabout +/- 0.175°.

Greetings,

Chris

Offline woodchips

  • Regular Contributor
  • *
  • Posts: 188
  • Country: gb
Re: Home Brew Analog Computer System
« Reply #164 on: August 06, 2013, 04:42:32 AM »
Just got a copy of the Korn Electronic and Hybrid Analogue Computers book. I like it. Dates from 1963 so right at the very end of both designing with valves and analogue computers, a few years later both were history. And all those ECC83s that were junked!

What is really nice is that the book can be read as a guide to design, there is lots of useful and interesting information. If you like the MIT Rad Lab books then you will like this. So many, most, text books are, quite frankly, boring and a chore to read, but every now and then a real gem pops up. Others are ones by Scroggie, Cathode Ray of Wireless World, Steinmetz from the early 1900s.

Thanks for the suggestion.


Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #165 on: August 06, 2013, 12:37:52 PM »
What i forgot to mention. In my example i do invert the readout value _and_ set the negative-polarity bit. I just assumed that when you toggle the output pin that the DAC output is inverted after the OpAmps, that is 5V input becomes 0V and 0V input becomes -5V output when negative, while for the positive half 5V in becomes 5V out, and 0V in becomes 0V out (just as an example). If that is not the case, simple comment out the "result = ~result" line there.

Also, note that due to the way the lookuptable is read, the first and last value in it are duplicated at each start/end of a quadrant. That is, for example, the zero-crossing at 180° will become 0 at an ADC value of 511 (end of second quadrant) but also 0 at a ADC value of 512 (start of third quadrant). There are two ways to eliminate that error. One is to create the table so there is no 0° and 90°. So the sequence instead of, for example, 8-4-0 0-4-8 becomes 10-6-2 2-6-10. Another way is to limit the maximum value in the table, and then add a fixed value if you go negative. So if the sequence from the table would be 8-4-0 0-4-8 you simply add 4 if negative, and get 8-4-0 4-8-12 instead. Of course this means that the maximum value can not be 255 but must be 251 instead, to avoid an overflow when adding 4.

Personally i would prefer the first method. This ensures that the generated quadrants are symetrical. And at 8 bits for one quadrant you have a resolution of roundabout 0.35°, so the small "error" of not having complete 0° or 90° is just roundabout +/- 0.175°.

Greetings,

Chris


Hi Chris,

Thanks for going through this in such detail - it's appreciated. I'd like to implement your recommendations and see how it compares to the current code, speed wise. However the electronic/firmware side of the project has been put aside for now as I work on installing and wiring it into its instrument case. Give me several days to get back to revising the code.

 

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #166 on: August 06, 2013, 12:57:34 PM »
Just got a copy of the Korn Electronic and Hybrid Analogue Computers book. I like it. Dates from 1963 so right at the very end of both designing with valves and analogue computers, a few years later both were history. And all those ECC83s that were junked!

What is really nice is that the book can be read as a guide to design, there is lots of useful and interesting information. If you like the MIT Rad Lab books then you will like this. So many, most, text books are, quite frankly, boring and a chore to read, but every now and then a real gem pops up. Others are ones by Scroggie, Cathode Ray of Wireless World, Steinmetz from the early 1900s.

Thanks for the suggestion.


If you liked the Korn & Korn book, you'd also enjoy Design Fundamentals of Analog Computer Components by R. M. Howe. That one is even more of a "design guide" than K&K. However, unlike K&K which delves into transistor circuit design as well, it deals exclusively in tube circuitry.

BTW, have not forgotten about those pots, just have some annoyances to sort out ATM with my PayPal account.
 


Offline woodchips

  • Regular Contributor
  • *
  • Posts: 188
  • Country: gb
Re: Home Brew Analog Computer System
« Reply #167 on: August 08, 2013, 07:42:32 AM »
Thanks, have to get the Howe book now as well!

If you are still looking for equations like the Lorenz, have you seen the Cornu's spiral? Beyond me but looked a pretty picture in the book, Slater & Frank - Electromagnetism.

No problems with the sine cosine pots, also have some resolvers as well.

Online mamalala

  • Supporter
  • ****
  • Posts: 724
  • Country: de
Re: Home Brew Analog Computer System
« Reply #168 on: August 08, 2013, 07:56:51 AM »
Hi Chris,

Thanks for going through this in such detail - it's appreciated. I'd like to implement your recommendations and see how it compares to the current code, speed wise. However the electronic/firmware side of the project has been put aside for now as I work on installing and wiring it into its instrument case. Give me several days to get back to revising the code.

 

No problem, you're welcome. Just as a side-note, if you plan to use a lot of table lookups in the future, you might want to consider to use PIC18 instead of the PIC16 series chips. They allow a more direct access to the program memory especially for stuff like tables, strings, etc.

On the PIC16, what actually happens is that you load the index in the W register and then call a subroutine. That will use the value in the W register to calculate the target address of a coputed goto, then jumps to that location, which in turn returns the actual value back in the W register.

On PIC18 you have a dedicated set of registers to do that. You simply load the index value into those registers, and can immediately read back the result from another register. Much faster, and allows to keep large tables simple as well (PIC16 would need some extra code to access tables larger than 256 entries).

It also has registers to directly access arrays and stuff in RAM. And all of those (for RAM and ROM) have various registers that define how the access happens. One register reads without changing the address pointed to. Another one increases the address, yet another one decreases it. And then there is one that allows you to access the address you set plus/minus an offset given by what is currently in W.

Makes working with memory blocks and tables _much_ more performant.

Greetings,

Chris

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #169 on: August 15, 2013, 11:48:55 PM »
If you are still looking for equations like the Lorenz, have you seen the Cornu's spiral? Beyond me but looked a pretty picture in the book, Slater & Frank - Electromagnetism.


Looks interesting, but not chaotic though. in addition to the Rossler Attractor and the Lorenz Attractor, I have also found "Chua's circuit":

http://en.wikipedia.org/wiki/Chua%27s_circuit

I will have to get an analog simulation of that up and running as well, of course.



Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #170 on: August 15, 2013, 11:56:08 PM »
Hi Chris,

Thanks for going through this in such detail - it's appreciated. I'd like to implement your recommendations and see how it compares to the current code, speed wise. However the electronic/firmware side of the project has been put aside for now as I work on installing and wiring it into its instrument case. Give me several days to get back to revising the code.

 

No problem, you're welcome. Just as a side-note, if you plan to use a lot of table lookups in the future, you might want to consider to use PIC18 instead of the PIC16 series chips. They allow a more direct access to the program memory especially for stuff like tables, strings, etc.

On the PIC16, what actually happens is that you load the index in the W register and then call a subroutine. That will use the value in the W register to calculate the target address of a coputed goto, then jumps to that location, which in turn returns the actual value back in the W register.

On PIC18 you have a dedicated set of registers to do that. You simply load the index value into those registers, and can immediately read back the result from another register. Much faster, and allows to keep large tables simple as well (PIC16 would need some extra code to access tables larger than 256 entries).

It also has registers to directly access arrays and stuff in RAM. And all of those (for RAM and ROM) have various registers that define how the access happens. One register reads without changing the address pointed to. Another one increases the address, yet another one decreases it. And then there is one that allows you to access the address you set plus/minus an offset given by what is currently in W.

Makes working with memory blocks and tables _much_ more performant.

Greetings,

Chris


OK, thanks for the pointers! I'm currently using a ~ 10 year old version of the CCS compiler, so am currently restricted to a ~10 year old list of supported devices. However I'll soon be upgrading to the latest and greatest version and will also be looking for new candidates for my "preferred devices" inventory. I've been using the 16F87X series for a long time now but it's a bit old hat now and time to move on.



Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #171 on: August 16, 2013, 12:03:43 AM »
Finally, here is the completed 3-D Projection unit.

The red and white potentiometer knobs under the digital displays are the coarse and fine X axis and Y axis angle-of-rotation / perspective control knobs respectively. The X, Y and Z signal inputs all have identical 1/2/5 input attenuators and AC/GND/DC switching. Signal handling it up to 100V. Control legends are printed onto a laminated transparency. The two BNC's under the power switch are the horizontal and vertical drive signal outputs for the display (typically an X-Y oscilloscope).


 
« Last Edit: August 16, 2013, 12:05:58 AM by GK »

Offline baljemmett

  • Supporter
  • ****
  • Posts: 665
  • Country: gb
Re: Home Brew Analog Computer System
« Reply #172 on: August 16, 2013, 08:42:20 AM »
Finally, here is the completed 3-D Projection unit.

That's a really nice looking build - many thumbs up, sir!

Online mamalala

  • Supporter
  • ****
  • Posts: 724
  • Country: de
Re: Home Brew Analog Computer System
« Reply #173 on: August 16, 2013, 11:31:33 AM »
OK, thanks for the pointers! I'm currently using a ~ 10 year old version of the CCS compiler, so am currently restricted to a ~10 year old list of supported devices. However I'll soon be upgrading to the latest and greatest version and will also be looking for new candidates for my "preferred devices" inventory. I've been using the 16F87X series for a long time now but it's a bit old hat now and time to move on.

Microchip's C18 does a nice job, and is still available if you look around on the Micochip website. Combine that with MPLab or MPLabX and you are good to go.

Another alternative is SDCC. It may not have all the "chips" by default, but adding additional ones is just a matter of providing the right include file (after all, PIC16 are the same no matter what, just theperipherials are different, and the same applies for PIC18 parts).

Here i am happily using C18 and MPLabX on Linux, before i used SDCC for my own projects and MPLab in a virtual Windows machine, but again with C18.

MPLabX requires Java, and that makes it rather sloe, unless you have a good machine.

Other than that, great work with your analogue computer! I wish i had the time and funds for that (the former would be not that much of a problem, but the latter definitively is....)

Greetings,

Chris

Offline GK

  • Super Contributor
  • ***
  • Posts: 1864
  • Country: au
Re: Home Brew Analog Computer System
« Reply #174 on: November 26, 2013, 07:10:44 PM »
OK...... Have had a bit of a break from this project due to other stuff getting in the way, but am about to make some major construction progress in the near future as the coming Friday is my last day at work for the year, after which I'll be able to work on this more or less full time. The integrator (30), analogue multiplier (10) and variable diode function generator chassis's are well under way. However in the meanwhile.........

For the digital section of this "hybrid" computer project, I'm developing a CRT readout device that will simultaneously display the status of the computers counters and registers. In keeping with the old school analog pretext, and inspired by the clever Fourier synthesis method described in this old paper:

http://www.nixiebunny.com/crtgen/crtgen.html

I've decided to base the design roughly on the same technique. With modern components and design techniques the unit will be much easier to implement than it was in 1958. I intend to make a 16-charachter alpha numeric ROM to reproduce the numbers 0 through 9 and the upper case letters A through F. This will permit Hexadecimal readouts of the computers counters and registers. The ROM will simply be a bank of 16 pairs of (op-amp based) summing amplifiers each with a unique resistor matrix for defining the Fourier composition of each character - much easier that winding a few dozen toroidal transformers!

Some pics are attached of a preliminary design concept/evaluation conducted in SPICE. The harmonic generator will simply consist of a 5-stage binary ripple counter to produce the fundamental and harmonic frequency components. The sine fundamental and harmonic functions are produced by filtering the squarewaves with simple resistance-tuned multiple-feedback bandpass filters and the -cosine terms for each sine function are produced by simple resistance-tuned all-pass filters acting as unity gain 90 degree phase shifters. Not stuffing around with crusty inductors or trimmer capacitors here. Unlike in the 1958 design paper with its "shock-excited" resonant circuits, oscillation will be continuous with the gating and sequencing pulses/control signals derived appropriately from the harmonic generator clock source and ripple counters.




The numbers 0 through 7 shown in the picture above were produced using the Fourier coefficient values given in the tables of Figure 3 in the linked-to paper. They're a bit wonky and could do with some tweaking, but that is good enough for now. In SPICE I simply used behavioral voltage sources to generate the X and Y deflection signals, summing the Fourier components with the polarities and amplitudes for each numeral as required. The LTspice plotter can't to Z-modulation, so to get a usable display I had to fudge in some vertical deflection "blanking".

The article gives an explanation of the graphical method (Figure 1) for manually drawing out the character on Cartesian coordinates and then working out and plotting the X and Y waveforms required for reproduce the character. This is quite simple and straight forward enough, but the article does not then go on to explain or detail the "purely graphical" method for manually computing the Fourier components of the produced X and Y waveforms - though a reference is given: T.C. Blow, Graphical Fourier Analysis, Electronics, p194, Dec. 1947. Anyone have a stash of old copies of Electronics magazine?? I need to further compute the Fourier components for the numbers 8 and 9 and the letter A through F. Any other reference provided or insight into the technique would be appreciated!
« Last Edit: November 26, 2013, 07:29:13 PM by GK »


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf